@methodts/runtime 0.1.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/dist/__fixtures__/executor-fixtures.d.ts +10 -0
- package/dist/__fixtures__/executor-fixtures.d.ts.map +1 -0
- package/dist/__fixtures__/executor-fixtures.js +36 -0
- package/dist/__fixtures__/executor-fixtures.js.map +1 -0
- package/dist/architecture.test.d.ts +2 -0
- package/dist/architecture.test.d.ts.map +1 -0
- package/dist/architecture.test.js +143 -0
- package/dist/architecture.test.js.map +1 -0
- package/dist/config/cost-governor-config.d.ts +40 -0
- package/dist/config/cost-governor-config.d.ts.map +1 -0
- package/dist/config/cost-governor-config.js +48 -0
- package/dist/config/cost-governor-config.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/sessions-config.d.ts +29 -0
- package/dist/config/sessions-config.d.ts.map +1 -0
- package/dist/config/sessions-config.js +37 -0
- package/dist/config/sessions-config.js.map +1 -0
- package/dist/config/strategies-config.d.ts +38 -0
- package/dist/config/strategies-config.d.ts.map +1 -0
- package/dist/config/strategies-config.js +41 -0
- package/dist/config/strategies-config.js.map +1 -0
- package/dist/cost-governor/backpressure-queue.d.ts +20 -0
- package/dist/cost-governor/backpressure-queue.d.ts.map +1 -0
- package/dist/cost-governor/backpressure-queue.js +78 -0
- package/dist/cost-governor/backpressure-queue.js.map +1 -0
- package/dist/cost-governor/backpressure-queue.test.d.ts +2 -0
- package/dist/cost-governor/backpressure-queue.test.d.ts.map +1 -0
- package/dist/cost-governor/backpressure-queue.test.js +48 -0
- package/dist/cost-governor/backpressure-queue.test.js.map +1 -0
- package/dist/cost-governor/cost-events.d.ts +65 -0
- package/dist/cost-governor/cost-events.d.ts.map +1 -0
- package/dist/cost-governor/cost-events.js +48 -0
- package/dist/cost-governor/cost-events.js.map +1 -0
- package/dist/cost-governor/cost-governor-app-id.test.d.ts +19 -0
- package/dist/cost-governor/cost-governor-app-id.test.d.ts.map +1 -0
- package/dist/cost-governor/cost-governor-app-id.test.js +201 -0
- package/dist/cost-governor/cost-governor-app-id.test.js.map +1 -0
- package/dist/cost-governor/cost-oracle-impl.d.ts +19 -0
- package/dist/cost-governor/cost-oracle-impl.d.ts.map +1 -0
- package/dist/cost-governor/cost-oracle-impl.js +52 -0
- package/dist/cost-governor/cost-oracle-impl.js.map +1 -0
- package/dist/cost-governor/estimator.d.ts +22 -0
- package/dist/cost-governor/estimator.d.ts.map +1 -0
- package/dist/cost-governor/estimator.js +119 -0
- package/dist/cost-governor/estimator.js.map +1 -0
- package/dist/cost-governor/estimator.test.d.ts +2 -0
- package/dist/cost-governor/estimator.test.d.ts.map +1 -0
- package/dist/cost-governor/estimator.test.js +141 -0
- package/dist/cost-governor/estimator.test.js.map +1 -0
- package/dist/cost-governor/index.d.ts +75 -0
- package/dist/cost-governor/index.d.ts.map +1 -0
- package/dist/cost-governor/index.js +120 -0
- package/dist/cost-governor/index.js.map +1 -0
- package/dist/cost-governor/observations-store.d.ts +49 -0
- package/dist/cost-governor/observations-store.d.ts.map +1 -0
- package/dist/cost-governor/observations-store.js +179 -0
- package/dist/cost-governor/observations-store.js.map +1 -0
- package/dist/cost-governor/observations-store.test.d.ts +2 -0
- package/dist/cost-governor/observations-store.test.d.ts.map +1 -0
- package/dist/cost-governor/observations-store.test.js +191 -0
- package/dist/cost-governor/observations-store.test.js.map +1 -0
- package/dist/cost-governor/percentile.d.ts +17 -0
- package/dist/cost-governor/percentile.d.ts.map +1 -0
- package/dist/cost-governor/percentile.js +33 -0
- package/dist/cost-governor/percentile.js.map +1 -0
- package/dist/cost-governor/percentile.test.d.ts +2 -0
- package/dist/cost-governor/percentile.test.d.ts.map +1 -0
- package/dist/cost-governor/percentile.test.js +46 -0
- package/dist/cost-governor/percentile.test.js.map +1 -0
- package/dist/cost-governor/rate-governor-impl.d.ts +73 -0
- package/dist/cost-governor/rate-governor-impl.d.ts.map +1 -0
- package/dist/cost-governor/rate-governor-impl.js +148 -0
- package/dist/cost-governor/rate-governor-impl.js.map +1 -0
- package/dist/cost-governor/signature-builder.d.ts +22 -0
- package/dist/cost-governor/signature-builder.d.ts.map +1 -0
- package/dist/cost-governor/signature-builder.js +43 -0
- package/dist/cost-governor/signature-builder.js.map +1 -0
- package/dist/cost-governor/signature-builder.test.d.ts +2 -0
- package/dist/cost-governor/signature-builder.test.d.ts.map +1 -0
- package/dist/cost-governor/signature-builder.test.js +58 -0
- package/dist/cost-governor/signature-builder.test.js.map +1 -0
- package/dist/cost-governor/token-bucket.d.ts +57 -0
- package/dist/cost-governor/token-bucket.d.ts.map +1 -0
- package/dist/cost-governor/token-bucket.js +109 -0
- package/dist/cost-governor/token-bucket.js.map +1 -0
- package/dist/cost-governor/token-bucket.test.d.ts +2 -0
- package/dist/cost-governor/token-bucket.test.d.ts.map +1 -0
- package/dist/cost-governor/token-bucket.test.js +67 -0
- package/dist/cost-governor/token-bucket.test.js.map +1 -0
- package/dist/dlq/cortex-dlq-observer.d.ts +22 -0
- package/dist/dlq/cortex-dlq-observer.d.ts.map +1 -0
- package/dist/dlq/cortex-dlq-observer.js +29 -0
- package/dist/dlq/cortex-dlq-observer.js.map +1 -0
- package/dist/dlq/dlq-observer.test.d.ts +8 -0
- package/dist/dlq/dlq-observer.test.d.ts.map +1 -0
- package/dist/dlq/dlq-observer.test.js +103 -0
- package/dist/dlq/dlq-observer.test.js.map +1 -0
- package/dist/dlq/index.d.ts +6 -0
- package/dist/dlq/index.d.ts.map +1 -0
- package/dist/dlq/index.js +6 -0
- package/dist/dlq/index.js.map +1 -0
- package/dist/event-bus/adapters.d.ts +50 -0
- package/dist/event-bus/adapters.d.ts.map +1 -0
- package/dist/event-bus/adapters.js +51 -0
- package/dist/event-bus/adapters.js.map +1 -0
- package/dist/event-bus/adapters.test.d.ts +5 -0
- package/dist/event-bus/adapters.test.d.ts.map +1 -0
- package/dist/event-bus/adapters.test.js +73 -0
- package/dist/event-bus/adapters.test.js.map +1 -0
- package/dist/event-bus/agent-event-adapter.d.ts +22 -0
- package/dist/event-bus/agent-event-adapter.d.ts.map +1 -0
- package/dist/event-bus/agent-event-adapter.js +49 -0
- package/dist/event-bus/agent-event-adapter.js.map +1 -0
- package/dist/event-bus/agent-event-adapter.test.d.ts +5 -0
- package/dist/event-bus/agent-event-adapter.test.d.ts.map +1 -0
- package/dist/event-bus/agent-event-adapter.test.js +170 -0
- package/dist/event-bus/agent-event-adapter.test.js.map +1 -0
- package/dist/event-bus/channel-sink.d.ts +71 -0
- package/dist/event-bus/channel-sink.d.ts.map +1 -0
- package/dist/event-bus/channel-sink.js +159 -0
- package/dist/event-bus/channel-sink.js.map +1 -0
- package/dist/event-bus/channel-sink.test.d.ts +5 -0
- package/dist/event-bus/channel-sink.test.d.ts.map +1 -0
- package/dist/event-bus/channel-sink.test.js +234 -0
- package/dist/event-bus/channel-sink.test.js.map +1 -0
- package/dist/event-bus/event-types.snapshot.test.d.ts +27 -0
- package/dist/event-bus/event-types.snapshot.test.d.ts.map +1 -0
- package/dist/event-bus/event-types.snapshot.test.js +165 -0
- package/dist/event-bus/event-types.snapshot.test.js.map +1 -0
- package/dist/event-bus/genesis-sink.d.ts +55 -0
- package/dist/event-bus/genesis-sink.d.ts.map +1 -0
- package/dist/event-bus/genesis-sink.js +141 -0
- package/dist/event-bus/genesis-sink.js.map +1 -0
- package/dist/event-bus/genesis-sink.test.d.ts +5 -0
- package/dist/event-bus/genesis-sink.test.d.ts.map +1 -0
- package/dist/event-bus/genesis-sink.test.js +160 -0
- package/dist/event-bus/genesis-sink.test.js.map +1 -0
- package/dist/event-bus/in-memory-event-bus.d.ts +60 -0
- package/dist/event-bus/in-memory-event-bus.d.ts.map +1 -0
- package/dist/event-bus/in-memory-event-bus.js +274 -0
- package/dist/event-bus/in-memory-event-bus.js.map +1 -0
- package/dist/event-bus/in-memory-event-bus.test.d.ts +5 -0
- package/dist/event-bus/in-memory-event-bus.test.d.ts.map +1 -0
- package/dist/event-bus/in-memory-event-bus.test.js +457 -0
- package/dist/event-bus/in-memory-event-bus.test.js.map +1 -0
- package/dist/event-bus/index.d.ts +22 -0
- package/dist/event-bus/index.d.ts.map +1 -0
- package/dist/event-bus/index.js +17 -0
- package/dist/event-bus/index.js.map +1 -0
- package/dist/event-bus/persistence-sink.d.ts +74 -0
- package/dist/event-bus/persistence-sink.d.ts.map +1 -0
- package/dist/event-bus/persistence-sink.js +193 -0
- package/dist/event-bus/persistence-sink.js.map +1 -0
- package/dist/event-bus/persistence-sink.test.d.ts +6 -0
- package/dist/event-bus/persistence-sink.test.d.ts.map +1 -0
- package/dist/event-bus/persistence-sink.test.js +319 -0
- package/dist/event-bus/persistence-sink.test.js.map +1 -0
- package/dist/event-bus/session-checkpoint-sink.d.ts +91 -0
- package/dist/event-bus/session-checkpoint-sink.d.ts.map +1 -0
- package/dist/event-bus/session-checkpoint-sink.js +107 -0
- package/dist/event-bus/session-checkpoint-sink.js.map +1 -0
- package/dist/event-bus/session-checkpoint-sink.test.d.ts +5 -0
- package/dist/event-bus/session-checkpoint-sink.test.d.ts.map +1 -0
- package/dist/event-bus/session-checkpoint-sink.test.js +215 -0
- package/dist/event-bus/session-checkpoint-sink.test.js.map +1 -0
- package/dist/event-bus/webhook-connector.d.ts +59 -0
- package/dist/event-bus/webhook-connector.d.ts.map +1 -0
- package/dist/event-bus/webhook-connector.js +191 -0
- package/dist/event-bus/webhook-connector.js.map +1 -0
- package/dist/event-bus/webhook-connector.test.d.ts +5 -0
- package/dist/event-bus/webhook-connector.test.d.ts.map +1 -0
- package/dist/event-bus/webhook-connector.test.js +214 -0
- package/dist/event-bus/webhook-connector.test.js.map +1 -0
- package/dist/executors/cortex-job-backed-executor.d.ts +137 -0
- package/dist/executors/cortex-job-backed-executor.d.ts.map +1 -0
- package/dist/executors/cortex-job-backed-executor.js +441 -0
- package/dist/executors/cortex-job-backed-executor.js.map +1 -0
- package/dist/executors/cortex-job-backed-executor.test.d.ts +13 -0
- package/dist/executors/cortex-job-backed-executor.test.d.ts.map +1 -0
- package/dist/executors/cortex-job-backed-executor.test.js +303 -0
- package/dist/executors/cortex-job-backed-executor.test.js.map +1 -0
- package/dist/executors/index.d.ts +9 -0
- package/dist/executors/index.d.ts.map +1 -0
- package/dist/executors/index.js +9 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/ports/checkpoint-sink.d.ts +69 -0
- package/dist/ports/checkpoint-sink.d.ts.map +1 -0
- package/dist/ports/checkpoint-sink.js +16 -0
- package/dist/ports/checkpoint-sink.js.map +1 -0
- package/dist/ports/checkpoint.d.ts +68 -0
- package/dist/ports/checkpoint.d.ts.map +1 -0
- package/dist/ports/checkpoint.js +14 -0
- package/dist/ports/checkpoint.js.map +1 -0
- package/dist/ports/continuation-envelope-cross-app.test.d.ts +10 -0
- package/dist/ports/continuation-envelope-cross-app.test.d.ts.map +1 -0
- package/dist/ports/continuation-envelope-cross-app.test.js +95 -0
- package/dist/ports/continuation-envelope-cross-app.test.js.map +1 -0
- package/dist/ports/continuation-envelope.d.ts +199 -0
- package/dist/ports/continuation-envelope.d.ts.map +1 -0
- package/dist/ports/continuation-envelope.js +69 -0
- package/dist/ports/continuation-envelope.js.map +1 -0
- package/dist/ports/conversation.d.ts +64 -0
- package/dist/ports/conversation.d.ts.map +1 -0
- package/dist/ports/conversation.js +19 -0
- package/dist/ports/conversation.js.map +1 -0
- package/dist/ports/cost-oracle.d.ts +26 -0
- package/dist/ports/cost-oracle.d.ts.map +1 -0
- package/dist/ports/cost-oracle.js +9 -0
- package/dist/ports/cost-oracle.js.map +1 -0
- package/dist/ports/cross-app-invoker.d.ts +198 -0
- package/dist/ports/cross-app-invoker.d.ts.map +1 -0
- package/dist/ports/cross-app-invoker.js +157 -0
- package/dist/ports/cross-app-invoker.js.map +1 -0
- package/dist/ports/dlq-observer.d.ts +40 -0
- package/dist/ports/dlq-observer.d.ts.map +1 -0
- package/dist/ports/dlq-observer.js +20 -0
- package/dist/ports/dlq-observer.js.map +1 -0
- package/dist/ports/event-bus.d.ts +169 -0
- package/dist/ports/event-bus.d.ts.map +1 -0
- package/dist/ports/event-bus.js +20 -0
- package/dist/ports/event-bus.js.map +1 -0
- package/dist/ports/event-reader.d.ts +21 -0
- package/dist/ports/event-reader.d.ts.map +1 -0
- package/dist/ports/event-reader.js +12 -0
- package/dist/ports/event-reader.js.map +1 -0
- package/dist/ports/event-rotator.d.ts +39 -0
- package/dist/ports/event-rotator.d.ts.map +1 -0
- package/dist/ports/event-rotator.js +15 -0
- package/dist/ports/event-rotator.js.map +1 -0
- package/dist/ports/file-system.d.ts +48 -0
- package/dist/ports/file-system.d.ts.map +1 -0
- package/dist/ports/file-system.js +10 -0
- package/dist/ports/file-system.js.map +1 -0
- package/dist/ports/historical-observations.d.ts +39 -0
- package/dist/ports/historical-observations.d.ts.map +1 -0
- package/dist/ports/historical-observations.js +12 -0
- package/dist/ports/historical-observations.js.map +1 -0
- package/dist/ports/in-memory-source.d.ts +46 -0
- package/dist/ports/in-memory-source.d.ts.map +1 -0
- package/dist/ports/in-memory-source.js +69 -0
- package/dist/ports/in-memory-source.js.map +1 -0
- package/dist/ports/index.d.ts +32 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +10 -0
- package/dist/ports/index.js.map +1 -0
- package/dist/ports/job-backed-executor.d.ts +139 -0
- package/dist/ports/job-backed-executor.d.ts.map +1 -0
- package/dist/ports/job-backed-executor.js +56 -0
- package/dist/ports/job-backed-executor.js.map +1 -0
- package/dist/ports/methodology-source.d.ts +95 -0
- package/dist/ports/methodology-source.d.ts.map +1 -0
- package/dist/ports/methodology-source.js +26 -0
- package/dist/ports/methodology-source.js.map +1 -0
- package/dist/ports/native-session-discovery.d.ts +20 -0
- package/dist/ports/native-session-discovery.d.ts.map +1 -0
- package/dist/ports/native-session-discovery.js +13 -0
- package/dist/ports/native-session-discovery.js.map +1 -0
- package/dist/ports/projection-store.d.ts +48 -0
- package/dist/ports/projection-store.d.ts.map +1 -0
- package/dist/ports/projection-store.js +17 -0
- package/dist/ports/projection-store.js.map +1 -0
- package/dist/ports/projection.d.ts +29 -0
- package/dist/ports/projection.d.ts.map +1 -0
- package/dist/ports/projection.js +13 -0
- package/dist/ports/projection.js.map +1 -0
- package/dist/ports/rate-governor.d.ts +17 -0
- package/dist/ports/rate-governor.d.ts.map +1 -0
- package/dist/ports/rate-governor.js +11 -0
- package/dist/ports/rate-governor.js.map +1 -0
- package/dist/ports/schedule-client.d.ts +29 -0
- package/dist/ports/schedule-client.d.ts.map +1 -0
- package/dist/ports/schedule-client.js +2 -0
- package/dist/ports/schedule-client.js.map +1 -0
- package/dist/ports/session-pool.d.ts +162 -0
- package/dist/ports/session-pool.d.ts.map +1 -0
- package/dist/ports/session-pool.js +21 -0
- package/dist/ports/session-pool.js.map +1 -0
- package/dist/ports/session-store-errors.d.ts +22 -0
- package/dist/ports/session-store-errors.d.ts.map +1 -0
- package/dist/ports/session-store-errors.js +29 -0
- package/dist/ports/session-store-errors.js.map +1 -0
- package/dist/ports/session-store-types.d.ts +132 -0
- package/dist/ports/session-store-types.d.ts.map +1 -0
- package/dist/ports/session-store-types.js +14 -0
- package/dist/ports/session-store-types.js.map +1 -0
- package/dist/ports/session-store.d.ts +69 -0
- package/dist/ports/session-store.d.ts.map +1 -0
- package/dist/ports/session-store.js +23 -0
- package/dist/ports/session-store.js.map +1 -0
- package/dist/ports/yaml-loader.d.ts +15 -0
- package/dist/ports/yaml-loader.d.ts.map +1 -0
- package/dist/ports/yaml-loader.js +13 -0
- package/dist/ports/yaml-loader.js.map +1 -0
- package/dist/scheduling/index.d.ts +6 -0
- package/dist/scheduling/index.d.ts.map +1 -0
- package/dist/scheduling/index.js +6 -0
- package/dist/scheduling/index.js.map +1 -0
- package/dist/scheduling/scheduled-pact.d.ts +97 -0
- package/dist/scheduling/scheduled-pact.d.ts.map +1 -0
- package/dist/scheduling/scheduled-pact.js +89 -0
- package/dist/scheduling/scheduled-pact.js.map +1 -0
- package/dist/sessions/__tests__/cognitive-modules.test.d.ts +10 -0
- package/dist/sessions/__tests__/cognitive-modules.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/cognitive-modules.test.js +535 -0
- package/dist/sessions/__tests__/cognitive-modules.test.js.map +1 -0
- package/dist/sessions/__tests__/cognitive-provider.test.d.ts +13 -0
- package/dist/sessions/__tests__/cognitive-provider.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/cognitive-provider.test.js +331 -0
- package/dist/sessions/__tests__/cognitive-provider.test.js.map +1 -0
- package/dist/sessions/__tests__/cognitive-sink.test.d.ts +19 -0
- package/dist/sessions/__tests__/cognitive-sink.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/cognitive-sink.test.js +334 -0
- package/dist/sessions/__tests__/cognitive-sink.test.js.map +1 -0
- package/dist/sessions/__tests__/runtime-tools.test.d.ts +2 -0
- package/dist/sessions/__tests__/runtime-tools.test.d.ts.map +1 -0
- package/dist/sessions/__tests__/runtime-tools.test.js +83 -0
- package/dist/sessions/__tests__/runtime-tools.test.js.map +1 -0
- package/dist/sessions/auto-retro.d.ts +29 -0
- package/dist/sessions/auto-retro.d.ts.map +1 -0
- package/dist/sessions/auto-retro.js +181 -0
- package/dist/sessions/auto-retro.js.map +1 -0
- package/dist/sessions/auto-retro.test.d.ts +2 -0
- package/dist/sessions/auto-retro.test.d.ts.map +1 -0
- package/dist/sessions/auto-retro.test.js +361 -0
- package/dist/sessions/auto-retro.test.js.map +1 -0
- package/dist/sessions/channels.d.ts +55 -0
- package/dist/sessions/channels.d.ts.map +1 -0
- package/dist/sessions/channels.js +118 -0
- package/dist/sessions/channels.js.map +1 -0
- package/dist/sessions/channels.test.d.ts +2 -0
- package/dist/sessions/channels.test.d.ts.map +1 -0
- package/dist/sessions/channels.test.js +285 -0
- package/dist/sessions/channels.test.js.map +1 -0
- package/dist/sessions/cognitive-modules.d.ts +100 -0
- package/dist/sessions/cognitive-modules.d.ts.map +1 -0
- package/dist/sessions/cognitive-modules.js +458 -0
- package/dist/sessions/cognitive-modules.js.map +1 -0
- package/dist/sessions/cognitive-provider.d.ts +42 -0
- package/dist/sessions/cognitive-provider.d.ts.map +1 -0
- package/dist/sessions/cognitive-provider.js +208 -0
- package/dist/sessions/cognitive-provider.js.map +1 -0
- package/dist/sessions/cognitive-sink.d.ts +73 -0
- package/dist/sessions/cognitive-sink.d.ts.map +1 -0
- package/dist/sessions/cognitive-sink.js +154 -0
- package/dist/sessions/cognitive-sink.js.map +1 -0
- package/dist/sessions/diagnostics.d.ts +70 -0
- package/dist/sessions/diagnostics.d.ts.map +1 -0
- package/dist/sessions/diagnostics.js +129 -0
- package/dist/sessions/diagnostics.js.map +1 -0
- package/dist/sessions/diagnostics.test.d.ts +2 -0
- package/dist/sessions/diagnostics.test.d.ts.map +1 -0
- package/dist/sessions/diagnostics.test.js +135 -0
- package/dist/sessions/diagnostics.test.js.map +1 -0
- package/dist/sessions/index.d.ts +32 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +33 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/pool.d.ts +218 -0
- package/dist/sessions/pool.d.ts.map +1 -0
- package/dist/sessions/pool.js +991 -0
- package/dist/sessions/pool.js.map +1 -0
- package/dist/sessions/pool.test.d.ts +2 -0
- package/dist/sessions/pool.test.d.ts.map +1 -0
- package/dist/sessions/pool.test.js +633 -0
- package/dist/sessions/pool.test.js.map +1 -0
- package/dist/sessions/print-session.d.ts +142 -0
- package/dist/sessions/print-session.d.ts.map +1 -0
- package/dist/sessions/print-session.js +325 -0
- package/dist/sessions/print-session.js.map +1 -0
- package/dist/sessions/print-session.test.d.ts +2 -0
- package/dist/sessions/print-session.test.d.ts.map +1 -0
- package/dist/sessions/print-session.test.js +418 -0
- package/dist/sessions/print-session.test.js.map +1 -0
- package/dist/sessions/runtime-tools.d.ts +22 -0
- package/dist/sessions/runtime-tools.d.ts.map +1 -0
- package/dist/sessions/runtime-tools.js +162 -0
- package/dist/sessions/runtime-tools.js.map +1 -0
- package/dist/sessions/scope-hook.d.ts +77 -0
- package/dist/sessions/scope-hook.d.ts.map +1 -0
- package/dist/sessions/scope-hook.js +323 -0
- package/dist/sessions/scope-hook.js.map +1 -0
- package/dist/sessions/scope-hook.test.d.ts +2 -0
- package/dist/sessions/scope-hook.test.d.ts.map +1 -0
- package/dist/sessions/scope-hook.test.js +249 -0
- package/dist/sessions/scope-hook.test.js.map +1 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.d.ts +16 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.d.ts.map +1 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.js +191 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.js.map +1 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.test.d.ts +5 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.test.d.ts.map +1 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.test.js +137 -0
- package/dist/sessions/session-store/checkpoint-sink-impl.test.js.map +1 -0
- package/dist/sessions/session-store/conformance.d.ts +59 -0
- package/dist/sessions/session-store/conformance.d.ts.map +1 -0
- package/dist/sessions/session-store/conformance.js +172 -0
- package/dist/sessions/session-store/conformance.js.map +1 -0
- package/dist/sessions/session-store/conformance.test.d.ts +7 -0
- package/dist/sessions/session-store/conformance.test.d.ts.map +1 -0
- package/dist/sessions/session-store/conformance.test.js +22 -0
- package/dist/sessions/session-store/conformance.test.js.map +1 -0
- package/dist/sessions/session-store/in-memory-session-store.d.ts +23 -0
- package/dist/sessions/session-store/in-memory-session-store.d.ts.map +1 -0
- package/dist/sessions/session-store/in-memory-session-store.js +197 -0
- package/dist/sessions/session-store/in-memory-session-store.js.map +1 -0
- package/dist/sessions/session-store/in-memory-session-store.test.d.ts +6 -0
- package/dist/sessions/session-store/in-memory-session-store.test.d.ts.map +1 -0
- package/dist/sessions/session-store/in-memory-session-store.test.js +183 -0
- package/dist/sessions/session-store/in-memory-session-store.test.js.map +1 -0
- package/dist/sessions/session-store/index.d.ts +20 -0
- package/dist/sessions/session-store/index.d.ts.map +1 -0
- package/dist/sessions/session-store/index.js +15 -0
- package/dist/sessions/session-store/index.js.map +1 -0
- package/dist/sessions/session-store/resume.d.ts +88 -0
- package/dist/sessions/session-store/resume.d.ts.map +1 -0
- package/dist/sessions/session-store/resume.js +96 -0
- package/dist/sessions/session-store/resume.js.map +1 -0
- package/dist/sessions/session-store/resume.test.d.ts +5 -0
- package/dist/sessions/session-store/resume.test.d.ts.map +1 -0
- package/dist/sessions/session-store/resume.test.js +119 -0
- package/dist/sessions/session-store/resume.test.js.map +1 -0
- package/dist/sessions/spawn-queue.d.ts +28 -0
- package/dist/sessions/spawn-queue.d.ts.map +1 -0
- package/dist/sessions/spawn-queue.js +63 -0
- package/dist/sessions/spawn-queue.js.map +1 -0
- package/dist/sessions/spawn-queue.test.d.ts +2 -0
- package/dist/sessions/spawn-queue.test.d.ts.map +1 -0
- package/dist/sessions/spawn-queue.test.js +65 -0
- package/dist/sessions/spawn-queue.test.js.map +1 -0
- package/dist/sessions/types.d.ts +16 -0
- package/dist/sessions/types.d.ts.map +1 -0
- package/dist/sessions/types.js +11 -0
- package/dist/sessions/types.js.map +1 -0
- package/dist/sessions/worktree-stale.test.d.ts +2 -0
- package/dist/sessions/worktree-stale.test.d.ts.map +1 -0
- package/dist/sessions/worktree-stale.test.js +468 -0
- package/dist/sessions/worktree-stale.test.js.map +1 -0
- package/dist/strategy/artifact-store.d.ts +12 -0
- package/dist/strategy/artifact-store.d.ts.map +1 -0
- package/dist/strategy/artifact-store.js +12 -0
- package/dist/strategy/artifact-store.js.map +1 -0
- package/dist/strategy/artifact-store.test.d.ts +2 -0
- package/dist/strategy/artifact-store.test.d.ts.map +1 -0
- package/dist/strategy/artifact-store.test.js +170 -0
- package/dist/strategy/artifact-store.test.js.map +1 -0
- package/dist/strategy/context-load-executor.d.ts +23 -0
- package/dist/strategy/context-load-executor.d.ts.map +1 -0
- package/dist/strategy/context-load-executor.js +87 -0
- package/dist/strategy/context-load-executor.js.map +1 -0
- package/dist/strategy/context-load-executor.test.d.ts +16 -0
- package/dist/strategy/context-load-executor.test.d.ts.map +1 -0
- package/dist/strategy/context-load-executor.test.js +158 -0
- package/dist/strategy/context-load-executor.test.js.map +1 -0
- package/dist/strategy/cortex-cross-app-invoker.stub.d.ts +65 -0
- package/dist/strategy/cortex-cross-app-invoker.stub.d.ts.map +1 -0
- package/dist/strategy/cortex-cross-app-invoker.stub.js +68 -0
- package/dist/strategy/cortex-cross-app-invoker.stub.js.map +1 -0
- package/dist/strategy/cross-app-node-executor.d.ts +54 -0
- package/dist/strategy/cross-app-node-executor.d.ts.map +1 -0
- package/dist/strategy/cross-app-node-executor.js +98 -0
- package/dist/strategy/cross-app-node-executor.js.map +1 -0
- package/dist/strategy/cross-app-node-executor.test.d.ts +13 -0
- package/dist/strategy/cross-app-node-executor.test.d.ts.map +1 -0
- package/dist/strategy/cross-app-node-executor.test.js +160 -0
- package/dist/strategy/cross-app-node-executor.test.js.map +1 -0
- package/dist/strategy/gates.d.ts +13 -0
- package/dist/strategy/gates.d.ts.map +1 -0
- package/dist/strategy/gates.js +13 -0
- package/dist/strategy/gates.js.map +1 -0
- package/dist/strategy/gates.test.d.ts +2 -0
- package/dist/strategy/gates.test.d.ts.map +1 -0
- package/dist/strategy/gates.test.js +299 -0
- package/dist/strategy/gates.test.js.map +1 -0
- package/dist/strategy/human-approval-resolver.d.ts +23 -0
- package/dist/strategy/human-approval-resolver.d.ts.map +1 -0
- package/dist/strategy/human-approval-resolver.js +94 -0
- package/dist/strategy/human-approval-resolver.js.map +1 -0
- package/dist/strategy/human-approval-resolver.test.d.ts +16 -0
- package/dist/strategy/human-approval-resolver.test.d.ts.map +1 -0
- package/dist/strategy/human-approval-resolver.test.js +200 -0
- package/dist/strategy/human-approval-resolver.test.js.map +1 -0
- package/dist/strategy/in-process-cross-app-invoker.d.ts +105 -0
- package/dist/strategy/in-process-cross-app-invoker.d.ts.map +1 -0
- package/dist/strategy/in-process-cross-app-invoker.js +206 -0
- package/dist/strategy/in-process-cross-app-invoker.js.map +1 -0
- package/dist/strategy/in-process-cross-app-invoker.test.d.ts +15 -0
- package/dist/strategy/in-process-cross-app-invoker.test.d.ts.map +1 -0
- package/dist/strategy/in-process-cross-app-invoker.test.js +190 -0
- package/dist/strategy/in-process-cross-app-invoker.test.js.map +1 -0
- package/dist/strategy/index.d.ts +29 -0
- package/dist/strategy/index.d.ts.map +1 -0
- package/dist/strategy/index.js +29 -0
- package/dist/strategy/index.js.map +1 -0
- package/dist/strategy/pacta-strategy.d.ts +97 -0
- package/dist/strategy/pacta-strategy.d.ts.map +1 -0
- package/dist/strategy/pacta-strategy.js +117 -0
- package/dist/strategy/pacta-strategy.js.map +1 -0
- package/dist/strategy/pacta-strategy.test.d.ts +2 -0
- package/dist/strategy/pacta-strategy.test.d.ts.map +1 -0
- package/dist/strategy/pacta-strategy.test.js +234 -0
- package/dist/strategy/pacta-strategy.test.js.map +1 -0
- package/dist/strategy/retro-generator.d.ts +18 -0
- package/dist/strategy/retro-generator.d.ts.map +1 -0
- package/dist/strategy/retro-generator.js +22 -0
- package/dist/strategy/retro-generator.js.map +1 -0
- package/dist/strategy/retro-writer.d.ts +25 -0
- package/dist/strategy/retro-writer.d.ts.map +1 -0
- package/dist/strategy/retro-writer.js +65 -0
- package/dist/strategy/retro-writer.js.map +1 -0
- package/dist/strategy/strategy-executor.d.ts +39 -0
- package/dist/strategy/strategy-executor.d.ts.map +1 -0
- package/dist/strategy/strategy-executor.js +253 -0
- package/dist/strategy/strategy-executor.js.map +1 -0
- package/dist/strategy/strategy-executor.test.d.ts +8 -0
- package/dist/strategy/strategy-executor.test.d.ts.map +1 -0
- package/dist/strategy/strategy-executor.test.js +1301 -0
- package/dist/strategy/strategy-executor.test.js.map +1 -0
- package/dist/strategy/strategy-parser.d.ts +30 -0
- package/dist/strategy/strategy-parser.d.ts.map +1 -0
- package/dist/strategy/strategy-parser.js +30 -0
- package/dist/strategy/strategy-parser.js.map +1 -0
- package/dist/strategy/sub-strategy-source.d.ts +27 -0
- package/dist/strategy/sub-strategy-source.d.ts.map +1 -0
- package/dist/strategy/sub-strategy-source.js +77 -0
- package/dist/strategy/sub-strategy-source.js.map +1 -0
- package/dist/strategy/types.d.ts +12 -0
- package/dist/strategy/types.d.ts.map +1 -0
- package/dist/strategy/types.js +9 -0
- package/dist/strategy/types.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,991 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
5
|
+
import { createPrintSession } from './print-session.js';
|
|
6
|
+
import { createCognitiveSession } from './cognitive-provider.js';
|
|
7
|
+
import { createRuntimeToolProvider } from './runtime-tools.js';
|
|
8
|
+
import { createSessionChannels } from './channels.js';
|
|
9
|
+
import { installScopeHook } from './scope-hook.js';
|
|
10
|
+
import { createAgentEventAdapter } from '../event-bus/agent-event-adapter.js';
|
|
11
|
+
import { CognitiveEventBusSink as CognitiveSink } from './cognitive-sink.js';
|
|
12
|
+
const DEFAULT_MAX_SESSIONS = 10;
|
|
13
|
+
const DEFAULT_MAX_DEPTH = 3;
|
|
14
|
+
const DEFAULT_MAX_AGENTS = 10;
|
|
15
|
+
const DEFAULT_STALE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
|
16
|
+
const DEFAULT_KILL_TIMEOUT_MS = 60 * 60 * 1000; // 60 minutes
|
|
17
|
+
const WORKTREE_DIR = '.claude/worktrees';
|
|
18
|
+
// PRD 007: Fallback nickname word list
|
|
19
|
+
const NICKNAME_WORDS = [
|
|
20
|
+
'alpha', 'bravo', 'cedar', 'drift', 'ember', 'flux', 'grain', 'haze',
|
|
21
|
+
'iris', 'jade', 'kite', 'lumen', 'mist', 'nova', 'opal', 'prism',
|
|
22
|
+
'quartz', 'ridge', 'spark', 'tide', 'umbra', 'vale', 'wave', 'xenon',
|
|
23
|
+
'yield', 'zinc',
|
|
24
|
+
];
|
|
25
|
+
// PRD 007: Method short names for methodology-derived nicknames
|
|
26
|
+
const METHOD_SHORT_NAMES = {
|
|
27
|
+
'M1-COUNCIL': 'council',
|
|
28
|
+
'M1-IMPL': 'impl',
|
|
29
|
+
'M1-PLAN': 'plan',
|
|
30
|
+
'M1-REVIEW': 'review',
|
|
31
|
+
'M1-MDES': 'mdes',
|
|
32
|
+
'M2-ORCH': 'orch',
|
|
33
|
+
'M3-TMP': 'tmp',
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Create a session pool that manages multiple Claude Code PTY sessions.
|
|
37
|
+
*
|
|
38
|
+
* The pool enforces a maximum session count and provides a uniform interface
|
|
39
|
+
* for creating, prompting, inspecting, and killing sessions.
|
|
40
|
+
*
|
|
41
|
+
* PRD 006: Sessions now track parent-child chains with budget enforcement.
|
|
42
|
+
*/
|
|
43
|
+
export function createPool(options) {
|
|
44
|
+
const maxSessions = options?.maxSessions ?? DEFAULT_MAX_SESSIONS;
|
|
45
|
+
const fsProvider = options?.fsProvider;
|
|
46
|
+
const eventBus = options?.eventBus;
|
|
47
|
+
const cognitiveSink = options?.cognitiveSink;
|
|
48
|
+
const sessions = new Map();
|
|
49
|
+
const sessionMetadata = new Map();
|
|
50
|
+
const sessionWorkdirs = new Map();
|
|
51
|
+
const sessionChains = new Map();
|
|
52
|
+
const sessionChannels = new Map();
|
|
53
|
+
const sessionWorktrees = new Map();
|
|
54
|
+
const sessionStaleConfigs = new Map();
|
|
55
|
+
const sessionStaleFlags = new Map();
|
|
56
|
+
const sessionNicknames = new Map(); // sessionId → nickname
|
|
57
|
+
const sessionPurposes = new Map(); // sessionId → purpose
|
|
58
|
+
const activeNicknames = new Set(); // uniqueness guard
|
|
59
|
+
// PRD 010: Original workdir per session (pre-worktree) for retro placement
|
|
60
|
+
const sessionOriginalWorkdirs = new Map();
|
|
61
|
+
// PRD 012: Per-session diagnostics trackers
|
|
62
|
+
const sessionDiagnostics = new Map();
|
|
63
|
+
// PRD 012 Phase 4: Session mode tracking
|
|
64
|
+
const sessionModes = new Map();
|
|
65
|
+
// PRD 033: Cognitive SSE sink registration — allows promptStream to receive cognitive events
|
|
66
|
+
const cognitiveSSESinks = new Map();
|
|
67
|
+
// OBS-19: Waiting-for-sub-agent state (set externally; PTY auto-detection removed in PRD 028 C-4)
|
|
68
|
+
const sessionWaitingFor = new Map(); // sessionId → what it's waiting for
|
|
69
|
+
// Pool-level counters
|
|
70
|
+
let totalSpawned = 0;
|
|
71
|
+
const startedAt = new Date();
|
|
72
|
+
let nicknameWordIndex = 0;
|
|
73
|
+
const methodNicknameCounts = new Map(); // method-short → next sequence
|
|
74
|
+
/**
|
|
75
|
+
* PRD 007: Generate a unique nickname for a session.
|
|
76
|
+
* Priority: explicit > methodology-derived > fallback word list.
|
|
77
|
+
*/
|
|
78
|
+
function generateNickname(explicit, metadata) {
|
|
79
|
+
// 1. Explicit nickname — use if unique
|
|
80
|
+
if (explicit) {
|
|
81
|
+
const candidate = explicit.toLowerCase().replace(/[^a-z0-9-]/g, '');
|
|
82
|
+
if (candidate && !activeNicknames.has(candidate)) {
|
|
83
|
+
return candidate;
|
|
84
|
+
}
|
|
85
|
+
// If collision, append sequence number
|
|
86
|
+
for (let i = 2; i < 100; i++) {
|
|
87
|
+
const suffixed = `${candidate}-${i}`;
|
|
88
|
+
if (!activeNicknames.has(suffixed))
|
|
89
|
+
return suffixed;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// 2. Methodology-derived: if metadata has methodology_session_id, try to extract method
|
|
93
|
+
if (metadata?.methodology_session_id) {
|
|
94
|
+
const msid = String(metadata.methodology_session_id);
|
|
95
|
+
// Try to match known method patterns
|
|
96
|
+
for (const [methodId, shortName] of Object.entries(METHOD_SHORT_NAMES)) {
|
|
97
|
+
if (msid.includes(methodId) || msid.toLowerCase().includes(shortName)) {
|
|
98
|
+
const count = (methodNicknameCounts.get(shortName) ?? 0) + 1;
|
|
99
|
+
methodNicknameCounts.set(shortName, count);
|
|
100
|
+
const candidate = `${shortName}-${count}`;
|
|
101
|
+
if (!activeNicknames.has(candidate))
|
|
102
|
+
return candidate;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// 3. Fallback word list
|
|
107
|
+
for (let attempts = 0; attempts < NICKNAME_WORDS.length; attempts++) {
|
|
108
|
+
const candidate = NICKNAME_WORDS[nicknameWordIndex % NICKNAME_WORDS.length];
|
|
109
|
+
nicknameWordIndex++;
|
|
110
|
+
if (!activeNicknames.has(candidate))
|
|
111
|
+
return candidate;
|
|
112
|
+
}
|
|
113
|
+
// Last resort: word + counter
|
|
114
|
+
const base = NICKNAME_WORDS[nicknameWordIndex % NICKNAME_WORDS.length];
|
|
115
|
+
nicknameWordIndex++;
|
|
116
|
+
for (let i = 2; i < 100; i++) {
|
|
117
|
+
const candidate = `${base}-${i}`;
|
|
118
|
+
if (!activeNicknames.has(candidate))
|
|
119
|
+
return candidate;
|
|
120
|
+
}
|
|
121
|
+
// Absolute fallback
|
|
122
|
+
return `agent-${totalSpawned + 1}`;
|
|
123
|
+
}
|
|
124
|
+
function getChain(sessionId) {
|
|
125
|
+
return sessionChains.get(sessionId) ?? {
|
|
126
|
+
parent_session_id: null,
|
|
127
|
+
depth: 0,
|
|
128
|
+
children: [],
|
|
129
|
+
budget: { max_depth: DEFAULT_MAX_DEPTH, max_agents: DEFAULT_MAX_AGENTS, agents_spawned: 0 },
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Find the root session of a chain and return its shared budget reference.
|
|
134
|
+
* Budget is tracked at the root — all agents in a chain share the same budget.
|
|
135
|
+
*/
|
|
136
|
+
function getRootBudget(sessionId) {
|
|
137
|
+
const chain = sessionChains.get(sessionId);
|
|
138
|
+
if (!chain)
|
|
139
|
+
return null;
|
|
140
|
+
// Walk up to root
|
|
141
|
+
let currentId = sessionId;
|
|
142
|
+
let current = chain;
|
|
143
|
+
while (current.parent_session_id) {
|
|
144
|
+
const parent = sessionChains.get(current.parent_session_id);
|
|
145
|
+
if (!parent)
|
|
146
|
+
break;
|
|
147
|
+
currentId = current.parent_session_id;
|
|
148
|
+
current = parent;
|
|
149
|
+
}
|
|
150
|
+
return current.budget;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* PRD 010: Handle session death — previously detached PTY watcher and generated auto-retro.
|
|
154
|
+
* PTY watcher removed in PRD 028 C-4. Function retained for call-site symmetry.
|
|
155
|
+
*/
|
|
156
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
157
|
+
function handleSessionDeath(_sessionId, _reason) {
|
|
158
|
+
// PTY watcher removed in PRD 028 C-4. Auto-retro via watcher observations no longer applies.
|
|
159
|
+
// Future: print-mode retro generation can be added here if needed.
|
|
160
|
+
}
|
|
161
|
+
// ── LLM provider resolution for cognitive-agent mode ────────
|
|
162
|
+
async function resolveProvider(providerName, config) {
|
|
163
|
+
switch (providerName ?? 'anthropic') {
|
|
164
|
+
case 'anthropic': {
|
|
165
|
+
const { anthropicProvider } = await import('@methodts/pacta-provider-anthropic');
|
|
166
|
+
return anthropicProvider({ model: config.model, toolProvider: config.toolProvider });
|
|
167
|
+
}
|
|
168
|
+
case 'ollama': {
|
|
169
|
+
const { ollamaProvider } = await import('@methodts/pacta-provider-ollama');
|
|
170
|
+
const provider = ollamaProvider({
|
|
171
|
+
baseUrl: config.baseUrl ?? process.env.OLLAMA_BASE_URL ?? 'http://chobits:11434',
|
|
172
|
+
model: config.model,
|
|
173
|
+
});
|
|
174
|
+
await provider.init();
|
|
175
|
+
return provider;
|
|
176
|
+
}
|
|
177
|
+
default:
|
|
178
|
+
throw new Error(`Unknown LLM provider: ${providerName}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
async create({ workdir, initialPrompt, spawnArgs, metadata, parentSessionId, depth, budget, isolation, timeout_ms, nickname, purpose, persistent, spawn_delay_ms, mode, allowed_paths, scope_mode, session_id, provider_type, cognitive_config, cognitive_patterns, llm_provider, llm_config, experiment_id, run_id }) {
|
|
183
|
+
// Count active (non-dead) sessions toward the limit
|
|
184
|
+
const activeSessions = [...sessions.values()].filter((s) => s.status !== 'dead').length;
|
|
185
|
+
if (activeSessions >= maxSessions) {
|
|
186
|
+
throw new Error(`Session pool full — maximum ${maxSessions} active sessions`);
|
|
187
|
+
}
|
|
188
|
+
// Determine chain properties
|
|
189
|
+
const effectiveDepth = depth ?? 0;
|
|
190
|
+
const effectiveBudget = {
|
|
191
|
+
max_depth: budget?.max_depth ?? DEFAULT_MAX_DEPTH,
|
|
192
|
+
max_agents: budget?.max_agents ?? DEFAULT_MAX_AGENTS,
|
|
193
|
+
agents_spawned: budget?.agents_spawned ?? 0,
|
|
194
|
+
};
|
|
195
|
+
// If this is a child session, inherit and validate budget from parent
|
|
196
|
+
if (parentSessionId) {
|
|
197
|
+
const parentChain = sessionChains.get(parentSessionId);
|
|
198
|
+
if (parentChain) {
|
|
199
|
+
// Use parent's budget as the source of truth (shared budget across chain)
|
|
200
|
+
const rootBudget = getRootBudget(parentSessionId) ?? parentChain.budget;
|
|
201
|
+
// Depth check
|
|
202
|
+
if (effectiveDepth >= rootBudget.max_depth) {
|
|
203
|
+
throw new Error(JSON.stringify({
|
|
204
|
+
error: 'DEPTH_EXCEEDED',
|
|
205
|
+
message: `Depth limit exceeded: depth ${effectiveDepth} >= max_depth ${rootBudget.max_depth}. Cannot spawn deeper.`,
|
|
206
|
+
budget: rootBudget,
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
// Agent count check
|
|
210
|
+
if (rootBudget.agents_spawned >= rootBudget.max_agents) {
|
|
211
|
+
throw new Error(JSON.stringify({
|
|
212
|
+
error: 'BUDGET_EXHAUSTED',
|
|
213
|
+
message: `Agent budget exceeded: ${rootBudget.agents_spawned}/${rootBudget.max_agents} agents spawned. Increase budget or complete existing work.`,
|
|
214
|
+
budget: rootBudget,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
// Increment the root budget's agent count
|
|
218
|
+
rootBudget.agents_spawned++;
|
|
219
|
+
// Copy current root budget values for the child
|
|
220
|
+
effectiveBudget.max_depth = rootBudget.max_depth;
|
|
221
|
+
effectiveBudget.max_agents = rootBudget.max_agents;
|
|
222
|
+
effectiveBudget.agents_spawned = rootBudget.agents_spawned;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
const sessionId = session_id ?? randomUUID();
|
|
226
|
+
// PRD 007: Generate and register nickname
|
|
227
|
+
const assignedNickname = generateNickname(nickname, metadata);
|
|
228
|
+
activeNicknames.add(assignedNickname);
|
|
229
|
+
// PRD 006 Component 2: Worktree isolation
|
|
230
|
+
const effectiveIsolation = isolation ?? 'shared';
|
|
231
|
+
let worktreePath = null;
|
|
232
|
+
let worktreeBranch = null;
|
|
233
|
+
let effectiveWorkdir = workdir;
|
|
234
|
+
if (effectiveIsolation === 'worktree') {
|
|
235
|
+
worktreeBranch = `worktree-${sessionId.substring(0, 8)}`;
|
|
236
|
+
const worktreeRelDir = join(WORKTREE_DIR, sessionId.substring(0, 8));
|
|
237
|
+
worktreePath = resolve(workdir, worktreeRelDir);
|
|
238
|
+
try {
|
|
239
|
+
execSync(`git worktree add "${worktreeRelDir}" -b "${worktreeBranch}"`, { cwd: workdir, stdio: 'pipe' });
|
|
240
|
+
effectiveWorkdir = worktreePath;
|
|
241
|
+
}
|
|
242
|
+
catch (e) {
|
|
243
|
+
throw new Error(`Worktree creation failed: ${e.message}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const worktreeInfo = {
|
|
247
|
+
isolation: effectiveIsolation,
|
|
248
|
+
worktree_path: worktreePath,
|
|
249
|
+
worktree_branch: worktreeBranch,
|
|
250
|
+
metals_available: effectiveIsolation !== 'worktree',
|
|
251
|
+
};
|
|
252
|
+
// PRD 014: Scope enforcement — determine effective mode and install hook
|
|
253
|
+
const effectiveAllowedPaths = allowed_paths ?? [];
|
|
254
|
+
const envScopeDefault = process.env.SCOPE_ENFORCEMENT_DEFAULT;
|
|
255
|
+
const validatedEnvDefault = (envScopeDefault === 'enforce' || envScopeDefault === 'warn') ? envScopeDefault : 'enforce';
|
|
256
|
+
let effectiveScopeMode = scope_mode ?? validatedEnvDefault;
|
|
257
|
+
if (effectiveAllowedPaths.length > 0) {
|
|
258
|
+
if (effectiveIsolation !== 'worktree' && effectiveScopeMode === 'enforce') {
|
|
259
|
+
// PRD 014: Worktree fallback — can't install hook in shared mode
|
|
260
|
+
console.warn(`[PRD 014] allowed_paths provided without worktree isolation — falling back to mode 'warn'. Pre-commit hook requires isolation: 'worktree'.`);
|
|
261
|
+
effectiveScopeMode = 'warn';
|
|
262
|
+
}
|
|
263
|
+
if (effectiveScopeMode === 'enforce' && worktreePath) {
|
|
264
|
+
// Install pre-commit hook in the worktree
|
|
265
|
+
const hookResult = installScopeHook(worktreePath, sessionId, effectiveAllowedPaths);
|
|
266
|
+
if (hookResult.error) {
|
|
267
|
+
console.warn(`[PRD 014] Scope hook installation warning: ${hookResult.error}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Store scope constraint in metadata for PTY watcher (Phase 2)
|
|
271
|
+
const existingMetadata = metadata ?? {};
|
|
272
|
+
metadata = {
|
|
273
|
+
...existingMetadata,
|
|
274
|
+
allowed_paths: effectiveAllowedPaths,
|
|
275
|
+
scope_mode: effectiveScopeMode,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
// PRD 006 Component 4: Stale detection config
|
|
279
|
+
// PRD 011: persistent sessions skip stale detection entirely
|
|
280
|
+
const staleConfig = persistent ? null : {
|
|
281
|
+
stale_timeout_ms: timeout_ms ?? DEFAULT_STALE_TIMEOUT_MS,
|
|
282
|
+
kill_timeout_ms: (timeout_ms ? timeout_ms * 2 : DEFAULT_KILL_TIMEOUT_MS),
|
|
283
|
+
};
|
|
284
|
+
// PRD 033: Determine session mode from provider_type (default: print)
|
|
285
|
+
const effectiveMode = provider_type === 'cognitive-agent' ? 'cognitive-agent' : 'print';
|
|
286
|
+
// PRD 012: Staggered spawn — delay before spawning process
|
|
287
|
+
if (spawn_delay_ms && spawn_delay_ms > 0) {
|
|
288
|
+
await new Promise(r => setTimeout(r, spawn_delay_ms));
|
|
289
|
+
}
|
|
290
|
+
let session;
|
|
291
|
+
// PRD-057 / S2 §6 / C5: if a SessionProviderFactory was supplied at pool
|
|
292
|
+
// construction, delegate the "how does a prompt actually execute" part
|
|
293
|
+
// to the factory. Otherwise fall back to the built-in print + cognitive
|
|
294
|
+
// paths. Both paths set up the cognitive SSE sink in the same way when
|
|
295
|
+
// applicable so `promptStream` behavior is identical.
|
|
296
|
+
if (options?.providerFactory) {
|
|
297
|
+
let sseSink = null;
|
|
298
|
+
if (effectiveMode === 'cognitive-agent') {
|
|
299
|
+
cognitiveSSESinks.set(sessionId, (cb) => { sseSink = cb; });
|
|
300
|
+
}
|
|
301
|
+
const sessionCognitiveSink = (effectiveMode === 'cognitive-agent' && experiment_id && run_id && eventBus)
|
|
302
|
+
? new CognitiveSink(eventBus, { sessionId, experimentId: experiment_id, runId: run_id })
|
|
303
|
+
: cognitiveSink;
|
|
304
|
+
const factoryOptions = {
|
|
305
|
+
sessionId,
|
|
306
|
+
mode: effectiveMode,
|
|
307
|
+
workdir: effectiveWorkdir,
|
|
308
|
+
allowedTools: spawnArgs,
|
|
309
|
+
allowedPaths: effectiveAllowedPaths,
|
|
310
|
+
metadata,
|
|
311
|
+
onEvent: (event) => {
|
|
312
|
+
// Forward to active SSE stream (if any) and emit cognitive
|
|
313
|
+
// events onto the bus for PRD 041 experiment tracing.
|
|
314
|
+
sseSink?.(event);
|
|
315
|
+
if (eventBus && effectiveMode === 'cognitive-agent') {
|
|
316
|
+
eventBus.emit({
|
|
317
|
+
version: 1,
|
|
318
|
+
domain: 'session',
|
|
319
|
+
type: `session.cognitive.${event.type}`,
|
|
320
|
+
severity: 'info',
|
|
321
|
+
sessionId,
|
|
322
|
+
payload: event,
|
|
323
|
+
source: 'runtime/sessions/pool',
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
cognitiveConfig: cognitive_config,
|
|
328
|
+
cognitiveSink: sessionCognitiveSink,
|
|
329
|
+
};
|
|
330
|
+
const handle = await options.providerFactory.createSession(factoryOptions);
|
|
331
|
+
// The factory returns a handle structurally compatible with
|
|
332
|
+
// PtySession; cast once here — every method the pool invokes is
|
|
333
|
+
// guaranteed present by the PtySessionHandle contract.
|
|
334
|
+
session = handle;
|
|
335
|
+
}
|
|
336
|
+
else if (effectiveMode === 'cognitive-agent') {
|
|
337
|
+
// PRD 033: Cognitive agent session — runs reasoning cycle internally
|
|
338
|
+
const { createProviderAdapter } = await import('@methodts/pacta');
|
|
339
|
+
const tools = createRuntimeToolProvider(effectiveWorkdir);
|
|
340
|
+
const model = llm_config?.model ?? (typeof metadata?.model === 'string' ? metadata.model : undefined);
|
|
341
|
+
const agentProvider = await resolveProvider(llm_provider, { model, baseUrl: llm_config?.baseUrl, toolProvider: tools });
|
|
342
|
+
const adapter = createProviderAdapter(agentProvider, {
|
|
343
|
+
pactTemplate: { mode: { type: 'oneshot' }, budget: { maxOutputTokens: 4096 } },
|
|
344
|
+
});
|
|
345
|
+
// Mutable SSE sink — set by promptStream(), cleared on completion.
|
|
346
|
+
// Allows cognitive events to flow to both the event bus and the active SSE stream.
|
|
347
|
+
let sseSink = null;
|
|
348
|
+
cognitiveSSESinks.set(sessionId, (cb) => { sseSink = cb; });
|
|
349
|
+
// PRD 041: Create a per-session CognitiveSink with experiment context so that
|
|
350
|
+
// ExperimentEventSink can route emitted RuntimeEvents to the correct JSONL file.
|
|
351
|
+
// Falls back to the pool-level sink when no experiment context is present.
|
|
352
|
+
const sessionCognitiveSink = (experiment_id && run_id && eventBus)
|
|
353
|
+
? new CognitiveSink(eventBus, { sessionId, experimentId: experiment_id, runId: run_id })
|
|
354
|
+
: cognitiveSink;
|
|
355
|
+
session = createCognitiveSession({
|
|
356
|
+
id: sessionId,
|
|
357
|
+
workdir: effectiveWorkdir,
|
|
358
|
+
adapter,
|
|
359
|
+
tools,
|
|
360
|
+
cognitiveSink: sessionCognitiveSink,
|
|
361
|
+
config: {
|
|
362
|
+
name: cognitive_config?.name,
|
|
363
|
+
patterns: cognitive_patterns,
|
|
364
|
+
maxCycles: cognitive_config?.maxCycles,
|
|
365
|
+
workspaceCapacity: cognitive_config?.workspaceCapacity,
|
|
366
|
+
confidenceThreshold: cognitive_config?.confidenceThreshold,
|
|
367
|
+
stagnationThreshold: cognitive_config?.stagnationThreshold,
|
|
368
|
+
interventionBudget: cognitive_config?.interventionBudget,
|
|
369
|
+
},
|
|
370
|
+
initialPrompt: initialPrompt ?? undefined,
|
|
371
|
+
onEvent: (event) => {
|
|
372
|
+
// Forward to active SSE stream (if any)
|
|
373
|
+
sseSink?.(event);
|
|
374
|
+
// Route cognitive cycle events through the event bus
|
|
375
|
+
if (eventBus) {
|
|
376
|
+
eventBus.emit({
|
|
377
|
+
version: 1,
|
|
378
|
+
domain: 'session',
|
|
379
|
+
type: `session.cognitive.${event.type}`,
|
|
380
|
+
severity: 'info',
|
|
381
|
+
sessionId,
|
|
382
|
+
payload: event,
|
|
383
|
+
source: 'runtime/sessions/cognitive-provider',
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
// Default: print-mode session (claude --print)
|
|
391
|
+
const DEFAULT_SYSTEM_PROMPT_SUFFIX = [
|
|
392
|
+
'When producing diagrams, flowcharts, or architecture visualizations, use GlyphJS ui: fenced code blocks instead of ASCII art.',
|
|
393
|
+
'Available components: ui:flowchart, ui:callout, ui:table, ui:architecture, ui:timeline, ui:graph, ui:sequence, ui:tabs, ui:steps, ui:kpi, ui:mindmap.',
|
|
394
|
+
'Use proper markdown tables (| col | col |) instead of ASCII-aligned columns.',
|
|
395
|
+
'Example: ```ui:flowchart\\nnodes:\\n - id: a\\n label: Start\\nedges:\\n - from: a\\n to: b\\n```',
|
|
396
|
+
].join(' ');
|
|
397
|
+
const userSystemPrompt = typeof metadata?.append_system_prompt === 'string' ? metadata.append_system_prompt : '';
|
|
398
|
+
const effectiveSystemPrompt = userSystemPrompt
|
|
399
|
+
? `${userSystemPrompt}\n\n${DEFAULT_SYSTEM_PROMPT_SUFFIX}`
|
|
400
|
+
: DEFAULT_SYSTEM_PROMPT_SUFFIX;
|
|
401
|
+
session = createPrintSession({
|
|
402
|
+
id: sessionId,
|
|
403
|
+
workdir: effectiveWorkdir,
|
|
404
|
+
initialPrompt: initialPrompt ?? undefined,
|
|
405
|
+
maxBudgetUsd: typeof metadata?.max_budget_usd === 'number' ? metadata.max_budget_usd : undefined,
|
|
406
|
+
appendSystemPrompt: effectiveSystemPrompt,
|
|
407
|
+
permissionMode: process.env.PRINT_PERMISSION_MODE ?? 'bypassPermissions',
|
|
408
|
+
model: typeof metadata?.model === 'string' ? metadata.model : undefined,
|
|
409
|
+
spawnArgs,
|
|
410
|
+
onEvent: eventBus ? createAgentEventAdapter(eventBus, sessionId, metadata?.project_id ?? 'unknown') : undefined,
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
sessions.set(sessionId, session);
|
|
414
|
+
sessionModes.set(sessionId, effectiveMode);
|
|
415
|
+
sessionWorkdirs.set(sessionId, effectiveWorkdir);
|
|
416
|
+
if (metadata) {
|
|
417
|
+
sessionMetadata.set(sessionId, metadata);
|
|
418
|
+
}
|
|
419
|
+
sessionWorktrees.set(sessionId, worktreeInfo);
|
|
420
|
+
if (staleConfig) {
|
|
421
|
+
sessionStaleConfigs.set(sessionId, staleConfig);
|
|
422
|
+
}
|
|
423
|
+
sessionStaleFlags.set(sessionId, false);
|
|
424
|
+
sessionNicknames.set(sessionId, assignedNickname);
|
|
425
|
+
if (purpose) {
|
|
426
|
+
sessionPurposes.set(sessionId, purpose);
|
|
427
|
+
}
|
|
428
|
+
// Record chain info
|
|
429
|
+
const chainInfo = {
|
|
430
|
+
parent_session_id: parentSessionId ?? null,
|
|
431
|
+
depth: effectiveDepth,
|
|
432
|
+
children: [],
|
|
433
|
+
budget: effectiveBudget,
|
|
434
|
+
};
|
|
435
|
+
sessionChains.set(sessionId, chainInfo);
|
|
436
|
+
// Register as child of parent
|
|
437
|
+
if (parentSessionId) {
|
|
438
|
+
const parentChain = sessionChains.get(parentSessionId);
|
|
439
|
+
if (parentChain) {
|
|
440
|
+
parentChain.children.push(sessionId);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
// PRD 008: Create channels (legacy — retained for getChannels() compatibility)
|
|
444
|
+
const channels = createSessionChannels();
|
|
445
|
+
sessionChannels.set(sessionId, channels);
|
|
446
|
+
// PRD 026 Phase 3: session.spawned emitted via eventBus only (appendMessage removed)
|
|
447
|
+
if (eventBus) {
|
|
448
|
+
eventBus.emit({
|
|
449
|
+
version: 1,
|
|
450
|
+
domain: 'session',
|
|
451
|
+
type: 'session.spawned',
|
|
452
|
+
severity: 'info',
|
|
453
|
+
sessionId,
|
|
454
|
+
payload: {
|
|
455
|
+
session_id: sessionId,
|
|
456
|
+
parent_session_id: parentSessionId ?? null,
|
|
457
|
+
depth: effectiveDepth,
|
|
458
|
+
mode: effectiveMode,
|
|
459
|
+
workdir,
|
|
460
|
+
nickname,
|
|
461
|
+
},
|
|
462
|
+
source: 'runtime/sessions/pool',
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
// PRD 010: Track original workdir (pre-worktree) for auto-retro placement
|
|
466
|
+
sessionOriginalWorkdirs.set(sessionId, workdir);
|
|
467
|
+
totalSpawned++;
|
|
468
|
+
return { sessionId, nickname: assignedNickname, status: session.status, chain: chainInfo, worktree: worktreeInfo, mode: effectiveMode };
|
|
469
|
+
},
|
|
470
|
+
async prompt(sessionId, prompt, timeoutMs, settleDelayMs) {
|
|
471
|
+
const session = sessions.get(sessionId);
|
|
472
|
+
if (!session) {
|
|
473
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
474
|
+
}
|
|
475
|
+
if (session.status === 'dead') {
|
|
476
|
+
throw new Error(`Session ${sessionId} is dead — cannot send prompt`);
|
|
477
|
+
}
|
|
478
|
+
const result = await session.sendPrompt(prompt, timeoutMs, settleDelayMs);
|
|
479
|
+
// PRD 012: Record settle overhead for this prompt
|
|
480
|
+
const tracker = sessionDiagnostics.get(sessionId);
|
|
481
|
+
if (tracker && !result.timedOut) {
|
|
482
|
+
tracker.recordPromptCompletion();
|
|
483
|
+
}
|
|
484
|
+
// Read printMetadata in-place after sendPrompt resolves (same tick — no race)
|
|
485
|
+
const printSession = session;
|
|
486
|
+
const metadata = printSession.printMetadata ?? null;
|
|
487
|
+
return { output: result.output, timedOut: result.timedOut, metadata };
|
|
488
|
+
},
|
|
489
|
+
async promptStream(sessionId, prompt, onEvent, timeoutMs) {
|
|
490
|
+
const session = sessions.get(sessionId);
|
|
491
|
+
if (!session) {
|
|
492
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
493
|
+
}
|
|
494
|
+
if (session.status === 'dead') {
|
|
495
|
+
throw new Error(`Session ${sessionId} is dead — cannot send prompt`);
|
|
496
|
+
}
|
|
497
|
+
// PRD 033: Register SSE sink for cognitive sessions so cycle events flow to SSE
|
|
498
|
+
const setSink = cognitiveSSESinks.get(sessionId);
|
|
499
|
+
if (setSink)
|
|
500
|
+
setSink(onEvent);
|
|
501
|
+
try {
|
|
502
|
+
let result;
|
|
503
|
+
if (typeof session.sendPromptStream === 'function') {
|
|
504
|
+
// Use the streaming path — emits incremental text chunks
|
|
505
|
+
result = await session.sendPromptStream(prompt, (chunk) => {
|
|
506
|
+
onEvent({ type: 'text', content: chunk });
|
|
507
|
+
}, timeoutMs);
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
// Fallback: non-streaming path (subscribes to onOutput for single emit)
|
|
511
|
+
const unsubscribe = session.onOutput((data) => {
|
|
512
|
+
if (data.startsWith('\n[print-mode]'))
|
|
513
|
+
return;
|
|
514
|
+
onEvent({ type: 'text', content: data });
|
|
515
|
+
});
|
|
516
|
+
try {
|
|
517
|
+
result = await session.sendPrompt(prompt, timeoutMs);
|
|
518
|
+
}
|
|
519
|
+
finally {
|
|
520
|
+
unsubscribe();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
// Cognitive sessions emit their own 'done' event via the SSE sink —
|
|
524
|
+
// skip the pool's redundant done to avoid overwriting metadata with nulls.
|
|
525
|
+
const isCognitive = cognitiveSSESinks.has(sessionId);
|
|
526
|
+
if (!isCognitive) {
|
|
527
|
+
// Read printMetadata and map to response shape (same as non-streaming endpoint)
|
|
528
|
+
const printSession = session;
|
|
529
|
+
const raw = printSession.printMetadata ?? null;
|
|
530
|
+
const metadata = raw ? {
|
|
531
|
+
cost_usd: raw.total_cost_usd,
|
|
532
|
+
num_turns: raw.num_turns,
|
|
533
|
+
duration_ms: raw.duration_ms,
|
|
534
|
+
stop_reason: raw.stop_reason,
|
|
535
|
+
input_tokens: raw.usage.input_tokens,
|
|
536
|
+
output_tokens: raw.usage.output_tokens,
|
|
537
|
+
cache_read_tokens: raw.usage.cache_read_input_tokens,
|
|
538
|
+
cache_write_tokens: raw.usage.cache_creation_input_tokens,
|
|
539
|
+
} : null;
|
|
540
|
+
// Send done event with full response + mapped metadata
|
|
541
|
+
onEvent({
|
|
542
|
+
type: 'done',
|
|
543
|
+
output: result.output,
|
|
544
|
+
metadata,
|
|
545
|
+
timed_out: result.timedOut,
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
catch (err) {
|
|
550
|
+
onEvent({
|
|
551
|
+
type: 'error',
|
|
552
|
+
error: err.message,
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
finally {
|
|
556
|
+
// Clear the cognitive SSE sink to avoid leaking callbacks
|
|
557
|
+
if (setSink)
|
|
558
|
+
setSink(null);
|
|
559
|
+
}
|
|
560
|
+
},
|
|
561
|
+
status(sessionId) {
|
|
562
|
+
const session = sessions.get(sessionId);
|
|
563
|
+
if (!session) {
|
|
564
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
565
|
+
}
|
|
566
|
+
// OBS-19: Override status to 'waiting' when session is waiting for a sub-agent
|
|
567
|
+
const waitingFor = sessionWaitingFor.get(sessionId) ?? null;
|
|
568
|
+
const effectiveStatus = (waitingFor && session.status === 'ready') ? 'waiting' : session.status;
|
|
569
|
+
// PRD 012: Build diagnostics snapshot with stall classification
|
|
570
|
+
const tracker = sessionDiagnostics.get(sessionId);
|
|
571
|
+
let diagnostics = null;
|
|
572
|
+
if (tracker) {
|
|
573
|
+
diagnostics = tracker.snapshot();
|
|
574
|
+
// Classify stall reason for stale or idle sessions
|
|
575
|
+
const isStale = sessionStaleFlags.get(sessionId) ?? false;
|
|
576
|
+
if (isStale || (effectiveStatus === 'ready' && session.promptCount > 0)) {
|
|
577
|
+
// Check if other sessions are also slow (for resource_contention classification)
|
|
578
|
+
const otherSessionsSlow = [...sessionDiagnostics.entries()].some(([otherId, otherTracker]) => {
|
|
579
|
+
if (otherId === sessionId)
|
|
580
|
+
return false;
|
|
581
|
+
const otherSnap = otherTracker.snapshot();
|
|
582
|
+
return otherSnap.time_to_first_output_ms !== null && otherSnap.time_to_first_output_ms > 10_000;
|
|
583
|
+
});
|
|
584
|
+
diagnostics.stall_reason = tracker.classifyStall(otherSessionsSlow);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
sessionId,
|
|
589
|
+
nickname: sessionNicknames.get(sessionId) ?? sessionId.substring(0, 8),
|
|
590
|
+
purpose: sessionPurposes.get(sessionId) ?? null,
|
|
591
|
+
status: effectiveStatus,
|
|
592
|
+
queueDepth: session.queueDepth,
|
|
593
|
+
metadata: sessionMetadata.get(sessionId),
|
|
594
|
+
promptCount: session.promptCount,
|
|
595
|
+
lastActivityAt: session.lastActivityAt,
|
|
596
|
+
workdir: sessionWorkdirs.get(sessionId) ?? '',
|
|
597
|
+
chain: getChain(sessionId),
|
|
598
|
+
worktree: sessionWorktrees.get(sessionId) ?? {
|
|
599
|
+
isolation: 'shared', worktree_path: null, worktree_branch: null, metals_available: true,
|
|
600
|
+
},
|
|
601
|
+
stale: sessionStaleFlags.get(sessionId) ?? false,
|
|
602
|
+
waiting_for: waitingFor,
|
|
603
|
+
mode: sessionModes.get(sessionId) ?? 'print',
|
|
604
|
+
diagnostics,
|
|
605
|
+
};
|
|
606
|
+
},
|
|
607
|
+
kill(sessionId, worktreeAction) {
|
|
608
|
+
const session = sessions.get(sessionId);
|
|
609
|
+
if (!session) {
|
|
610
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
611
|
+
}
|
|
612
|
+
// PRD 010: Detach watcher and generate auto-retro before killing
|
|
613
|
+
handleSessionDeath(sessionId, 'killed');
|
|
614
|
+
session.kill();
|
|
615
|
+
// PRD 006 Component 2: Handle worktree cleanup
|
|
616
|
+
let worktreeCleaned = false;
|
|
617
|
+
const wtInfo = sessionWorktrees.get(sessionId);
|
|
618
|
+
if (wtInfo && wtInfo.isolation === 'worktree' && wtInfo.worktree_path) {
|
|
619
|
+
const action = worktreeAction ?? 'keep';
|
|
620
|
+
const originalWorkdir = resolve(wtInfo.worktree_path, '..', '..', '..');
|
|
621
|
+
if (action === 'discard') {
|
|
622
|
+
try {
|
|
623
|
+
execSync(`git worktree remove "${wtInfo.worktree_path}" --force`, {
|
|
624
|
+
cwd: originalWorkdir, stdio: 'pipe',
|
|
625
|
+
});
|
|
626
|
+
if (wtInfo.worktree_branch) {
|
|
627
|
+
execSync(`git branch -D "${wtInfo.worktree_branch}"`, {
|
|
628
|
+
cwd: originalWorkdir, stdio: 'pipe',
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
worktreeCleaned = true;
|
|
632
|
+
}
|
|
633
|
+
catch {
|
|
634
|
+
// Worktree cleanup failure is non-fatal
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
else if (action === 'merge') {
|
|
638
|
+
try {
|
|
639
|
+
if (wtInfo.worktree_branch) {
|
|
640
|
+
execSync(`git merge "${wtInfo.worktree_branch}" --no-edit`, {
|
|
641
|
+
cwd: originalWorkdir, stdio: 'pipe',
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
execSync(`git worktree remove "${wtInfo.worktree_path}" --force`, {
|
|
645
|
+
cwd: originalWorkdir, stdio: 'pipe',
|
|
646
|
+
});
|
|
647
|
+
worktreeCleaned = true;
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
// Merge failure is non-fatal — worktree preserved for manual merge
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
// action === 'keep': leave worktree on disk
|
|
654
|
+
}
|
|
655
|
+
// PRD 026 Phase 3: session.killed emitted via eventBus only (appendMessage removed)
|
|
656
|
+
if (eventBus) {
|
|
657
|
+
eventBus.emit({
|
|
658
|
+
version: 1,
|
|
659
|
+
domain: 'session',
|
|
660
|
+
type: 'session.killed',
|
|
661
|
+
severity: 'info',
|
|
662
|
+
sessionId,
|
|
663
|
+
payload: {
|
|
664
|
+
session_id: sessionId,
|
|
665
|
+
killed_by: 'api',
|
|
666
|
+
worktree_action: worktreeAction ?? 'keep',
|
|
667
|
+
worktree_cleaned: worktreeCleaned,
|
|
668
|
+
},
|
|
669
|
+
source: 'runtime/sessions/pool',
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
return { sessionId: session.id, killed: true, worktree_cleaned: worktreeCleaned };
|
|
673
|
+
},
|
|
674
|
+
list() {
|
|
675
|
+
return [...sessions.entries()].map(([sessionId, session]) => {
|
|
676
|
+
// OBS-19: Override status to 'waiting' when session is waiting for a sub-agent
|
|
677
|
+
const waitingFor = sessionWaitingFor.get(sessionId) ?? null;
|
|
678
|
+
const effectiveStatus = (waitingFor && session.status === 'ready') ? 'waiting' : session.status;
|
|
679
|
+
// PRD 012: Include diagnostics snapshot
|
|
680
|
+
const tracker = sessionDiagnostics.get(sessionId);
|
|
681
|
+
const diagnostics = tracker ? tracker.snapshot() : null;
|
|
682
|
+
return {
|
|
683
|
+
sessionId,
|
|
684
|
+
nickname: sessionNicknames.get(sessionId) ?? sessionId.substring(0, 8),
|
|
685
|
+
purpose: sessionPurposes.get(sessionId) ?? null,
|
|
686
|
+
status: effectiveStatus,
|
|
687
|
+
queueDepth: session.queueDepth,
|
|
688
|
+
metadata: sessionMetadata.get(sessionId),
|
|
689
|
+
promptCount: session.promptCount,
|
|
690
|
+
lastActivityAt: session.lastActivityAt,
|
|
691
|
+
workdir: sessionWorkdirs.get(sessionId) ?? '',
|
|
692
|
+
chain: getChain(sessionId),
|
|
693
|
+
worktree: sessionWorktrees.get(sessionId) ?? {
|
|
694
|
+
isolation: 'shared', worktree_path: null, worktree_branch: null, metals_available: true,
|
|
695
|
+
},
|
|
696
|
+
stale: sessionStaleFlags.get(sessionId) ?? false,
|
|
697
|
+
waiting_for: waitingFor,
|
|
698
|
+
mode: sessionModes.get(sessionId) ?? 'print',
|
|
699
|
+
diagnostics,
|
|
700
|
+
};
|
|
701
|
+
});
|
|
702
|
+
},
|
|
703
|
+
getChannels(sessionId) {
|
|
704
|
+
const channels = sessionChannels.get(sessionId);
|
|
705
|
+
if (!channels) {
|
|
706
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
707
|
+
}
|
|
708
|
+
return channels;
|
|
709
|
+
},
|
|
710
|
+
getSession(sessionId) {
|
|
711
|
+
const session = sessions.get(sessionId);
|
|
712
|
+
if (!session) {
|
|
713
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
714
|
+
}
|
|
715
|
+
return session;
|
|
716
|
+
},
|
|
717
|
+
poolStats() {
|
|
718
|
+
const allSessions = [...sessions.values()];
|
|
719
|
+
const active = allSessions.filter((s) => s.status !== 'dead').length;
|
|
720
|
+
const dead = allSessions.filter((s) => s.status === 'dead').length;
|
|
721
|
+
return {
|
|
722
|
+
totalSpawned,
|
|
723
|
+
startedAt,
|
|
724
|
+
maxSessions,
|
|
725
|
+
activeSessions: active,
|
|
726
|
+
deadSessions: dead,
|
|
727
|
+
};
|
|
728
|
+
},
|
|
729
|
+
removeDead(ttlMs) {
|
|
730
|
+
let removed = 0;
|
|
731
|
+
for (const [sessionId, session] of sessions.entries()) {
|
|
732
|
+
if (session.status === 'dead') {
|
|
733
|
+
// Use lastActivityAt as the "died at" timestamp (it's the last activity before death)
|
|
734
|
+
if (Date.now() - session.lastActivityAt.getTime() > ttlMs) {
|
|
735
|
+
const nick = sessionNicknames.get(sessionId);
|
|
736
|
+
if (nick)
|
|
737
|
+
activeNicknames.delete(nick);
|
|
738
|
+
sessions.delete(sessionId);
|
|
739
|
+
sessionMetadata.delete(sessionId);
|
|
740
|
+
sessionWorkdirs.delete(sessionId);
|
|
741
|
+
sessionModes.delete(sessionId);
|
|
742
|
+
sessionChains.delete(sessionId);
|
|
743
|
+
sessionChannels.delete(sessionId);
|
|
744
|
+
sessionWorktrees.delete(sessionId);
|
|
745
|
+
sessionStaleConfigs.delete(sessionId);
|
|
746
|
+
sessionStaleFlags.delete(sessionId);
|
|
747
|
+
sessionNicknames.delete(sessionId);
|
|
748
|
+
sessionPurposes.delete(sessionId);
|
|
749
|
+
sessionOriginalWorkdirs.delete(sessionId);
|
|
750
|
+
sessionWaitingFor.delete(sessionId);
|
|
751
|
+
sessionDiagnostics.delete(sessionId);
|
|
752
|
+
removed++;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return removed;
|
|
757
|
+
},
|
|
758
|
+
/**
|
|
759
|
+
* PRD 006 Component 4: Check all sessions for staleness.
|
|
760
|
+
* - Sessions inactive > stale_timeout_ms → marked stale, 'stale' event emitted
|
|
761
|
+
* - Sessions inactive > kill_timeout_ms → auto-killed
|
|
762
|
+
* Returns lists of newly-stale and newly-killed session IDs.
|
|
763
|
+
*/
|
|
764
|
+
checkStale() {
|
|
765
|
+
const now = Date.now();
|
|
766
|
+
const staleIds = [];
|
|
767
|
+
const killedIds = [];
|
|
768
|
+
for (const [sessionId, session] of sessions.entries()) {
|
|
769
|
+
if (session.status === 'dead')
|
|
770
|
+
continue;
|
|
771
|
+
const config = sessionStaleConfigs.get(sessionId);
|
|
772
|
+
if (!config)
|
|
773
|
+
continue;
|
|
774
|
+
const inactiveMs = now - session.lastActivityAt.getTime();
|
|
775
|
+
const isStale = sessionStaleFlags.get(sessionId) ?? false;
|
|
776
|
+
// Auto-kill: inactive beyond kill timeout
|
|
777
|
+
if (inactiveMs >= config.kill_timeout_ms) {
|
|
778
|
+
handleSessionDeath(sessionId, 'stale');
|
|
779
|
+
session.kill();
|
|
780
|
+
// PRD 026 Phase 3: session.stale emitted via eventBus only (appendMessage removed)
|
|
781
|
+
if (eventBus) {
|
|
782
|
+
eventBus.emit({
|
|
783
|
+
version: 1,
|
|
784
|
+
domain: 'session',
|
|
785
|
+
type: 'session.stale',
|
|
786
|
+
severity: 'warning',
|
|
787
|
+
sessionId,
|
|
788
|
+
payload: {
|
|
789
|
+
session_id: sessionId,
|
|
790
|
+
inactive_ms: inactiveMs,
|
|
791
|
+
action: 'auto_killed',
|
|
792
|
+
},
|
|
793
|
+
source: 'runtime/sessions/pool',
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
killedIds.push(sessionId);
|
|
797
|
+
sessionStaleFlags.set(sessionId, true);
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
800
|
+
// Mark stale: inactive beyond stale timeout (but not yet killed)
|
|
801
|
+
if (inactiveMs >= config.stale_timeout_ms && !isStale) {
|
|
802
|
+
sessionStaleFlags.set(sessionId, true);
|
|
803
|
+
// PRD 026 Phase 3: session.stale emitted via eventBus only (appendMessage removed)
|
|
804
|
+
if (eventBus) {
|
|
805
|
+
eventBus.emit({
|
|
806
|
+
version: 1,
|
|
807
|
+
domain: 'session',
|
|
808
|
+
type: 'session.stale',
|
|
809
|
+
severity: 'warning',
|
|
810
|
+
sessionId,
|
|
811
|
+
payload: {
|
|
812
|
+
session_id: sessionId,
|
|
813
|
+
inactive_ms: inactiveMs,
|
|
814
|
+
action: 'marked_stale',
|
|
815
|
+
kill_in_ms: config.kill_timeout_ms - inactiveMs,
|
|
816
|
+
},
|
|
817
|
+
source: 'runtime/sessions/pool',
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
staleIds.push(sessionId);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return { stale: staleIds, killed: killedIds };
|
|
824
|
+
},
|
|
825
|
+
childPids() {
|
|
826
|
+
const pids = [];
|
|
827
|
+
for (const [, session] of sessions.entries()) {
|
|
828
|
+
if (session.status !== 'dead' && session.pid !== null) {
|
|
829
|
+
pids.push(session.pid);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
return pids;
|
|
833
|
+
},
|
|
834
|
+
setObservationHook(_hook) {
|
|
835
|
+
// PTY watcher removed in PRD 028 C-4. Observation hook is now a no-op.
|
|
836
|
+
},
|
|
837
|
+
restoreSession(snapshot) {
|
|
838
|
+
const sid = snapshot.sessionId;
|
|
839
|
+
// Duplicate restore — silently skip if session already exists
|
|
840
|
+
if (sessions.has(sid)) {
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
// Build a minimal PtySession stub that is compatible with pool operations.
|
|
844
|
+
// The stub does not spawn a process — it is a placeholder for recovered state.
|
|
845
|
+
// Sending a prompt creates a real print session under the hood (recovered mode).
|
|
846
|
+
let status = 'ready';
|
|
847
|
+
let promptCount = snapshot.promptCount;
|
|
848
|
+
let lastActivityAt = new Date();
|
|
849
|
+
let transcript = '';
|
|
850
|
+
const outputSubscribers = new Set();
|
|
851
|
+
const exitCallbacks = [];
|
|
852
|
+
let lastMetadata = null;
|
|
853
|
+
const stubSession = {
|
|
854
|
+
id: sid,
|
|
855
|
+
get pid() { return null; },
|
|
856
|
+
get status() { return status; },
|
|
857
|
+
set status(s) { status = s; },
|
|
858
|
+
get queueDepth() { return 0; },
|
|
859
|
+
get promptCount() { return promptCount; },
|
|
860
|
+
set promptCount(n) { promptCount = n; },
|
|
861
|
+
get lastActivityAt() { return lastActivityAt; },
|
|
862
|
+
set lastActivityAt(d) { lastActivityAt = d; },
|
|
863
|
+
get transcript() { return transcript; },
|
|
864
|
+
onOutput(cb) {
|
|
865
|
+
outputSubscribers.add(cb);
|
|
866
|
+
return () => { outputSubscribers.delete(cb); };
|
|
867
|
+
},
|
|
868
|
+
onExit(cb) {
|
|
869
|
+
exitCallbacks.push(cb);
|
|
870
|
+
},
|
|
871
|
+
sendPrompt(prompt, _timeoutMs, _settleDelayMs) {
|
|
872
|
+
if (status === 'dead') {
|
|
873
|
+
return Promise.reject(new Error(`Session ${sid} is dead — cannot send prompt`));
|
|
874
|
+
}
|
|
875
|
+
// Lazy upgrade: replace stub with real print session on first prompt
|
|
876
|
+
const real = createPrintSession({
|
|
877
|
+
id: sid,
|
|
878
|
+
workdir: snapshot.workdir,
|
|
879
|
+
recovered: true,
|
|
880
|
+
model: typeof snapshot.metadata?.model === 'string' ? snapshot.metadata.model : undefined,
|
|
881
|
+
onEvent: eventBus ? createAgentEventAdapter(eventBus, sid, snapshot.metadata?.project_id ?? 'unknown') : undefined,
|
|
882
|
+
});
|
|
883
|
+
// Migrate subscribers
|
|
884
|
+
for (const sub of outputSubscribers) {
|
|
885
|
+
real.onOutput(sub);
|
|
886
|
+
}
|
|
887
|
+
for (const cb of exitCallbacks) {
|
|
888
|
+
real.onExit(cb);
|
|
889
|
+
}
|
|
890
|
+
// Replace in pool map
|
|
891
|
+
sessions.set(sid, real);
|
|
892
|
+
return real.sendPrompt(prompt, _timeoutMs, _settleDelayMs);
|
|
893
|
+
},
|
|
894
|
+
sendPromptStream(prompt, onChunk, _timeoutMs) {
|
|
895
|
+
if (status === 'dead') {
|
|
896
|
+
return Promise.reject(new Error(`Session ${sid} is dead — cannot send prompt`));
|
|
897
|
+
}
|
|
898
|
+
// Lazy upgrade: replace stub with real print session on first prompt (streaming)
|
|
899
|
+
const real = createPrintSession({
|
|
900
|
+
id: sid,
|
|
901
|
+
workdir: snapshot.workdir,
|
|
902
|
+
recovered: true,
|
|
903
|
+
model: typeof snapshot.metadata?.model === 'string' ? snapshot.metadata.model : undefined,
|
|
904
|
+
onEvent: eventBus ? createAgentEventAdapter(eventBus, sid, snapshot.metadata?.project_id ?? 'unknown') : undefined,
|
|
905
|
+
});
|
|
906
|
+
for (const sub of outputSubscribers) {
|
|
907
|
+
real.onOutput(sub);
|
|
908
|
+
}
|
|
909
|
+
for (const cb of exitCallbacks) {
|
|
910
|
+
real.onExit(cb);
|
|
911
|
+
}
|
|
912
|
+
sessions.set(sid, real);
|
|
913
|
+
if (typeof real.sendPromptStream === 'function') {
|
|
914
|
+
return real.sendPromptStream(prompt, onChunk, _timeoutMs);
|
|
915
|
+
}
|
|
916
|
+
return real.sendPrompt(prompt, _timeoutMs);
|
|
917
|
+
},
|
|
918
|
+
resize(_cols, _rows) { },
|
|
919
|
+
kill() {
|
|
920
|
+
status = 'dead';
|
|
921
|
+
outputSubscribers.clear();
|
|
922
|
+
for (const cb of exitCallbacks) {
|
|
923
|
+
try {
|
|
924
|
+
cb(0);
|
|
925
|
+
}
|
|
926
|
+
catch { /* non-fatal */ }
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
interrupt() { return false; },
|
|
930
|
+
get adaptiveSettle() { return null; },
|
|
931
|
+
get printMetadata() { return lastMetadata; },
|
|
932
|
+
};
|
|
933
|
+
// Hydrate all internal Maps
|
|
934
|
+
sessions.set(sid, stubSession);
|
|
935
|
+
sessionWorkdirs.set(sid, snapshot.workdir);
|
|
936
|
+
sessionModes.set(sid, snapshot.mode);
|
|
937
|
+
sessionNicknames.set(sid, snapshot.nickname);
|
|
938
|
+
activeNicknames.add(snapshot.nickname);
|
|
939
|
+
if (snapshot.purpose) {
|
|
940
|
+
sessionPurposes.set(sid, snapshot.purpose);
|
|
941
|
+
}
|
|
942
|
+
if (snapshot.metadata) {
|
|
943
|
+
sessionMetadata.set(sid, snapshot.metadata);
|
|
944
|
+
}
|
|
945
|
+
sessionChains.set(sid, {
|
|
946
|
+
parent_session_id: snapshot.parentSessionId ?? null,
|
|
947
|
+
depth: snapshot.depth,
|
|
948
|
+
children: [],
|
|
949
|
+
budget: { max_depth: DEFAULT_MAX_DEPTH, max_agents: DEFAULT_MAX_AGENTS, agents_spawned: 0 },
|
|
950
|
+
});
|
|
951
|
+
sessionWorktrees.set(sid, {
|
|
952
|
+
isolation: snapshot.isolation,
|
|
953
|
+
worktree_path: null,
|
|
954
|
+
worktree_branch: null,
|
|
955
|
+
metals_available: snapshot.isolation !== 'worktree',
|
|
956
|
+
});
|
|
957
|
+
sessionStaleFlags.set(sid, false);
|
|
958
|
+
sessionChannels.set(sid, createSessionChannels());
|
|
959
|
+
// Note: totalSpawned is NOT incremented — restored sessions don't count as newly spawned.
|
|
960
|
+
},
|
|
961
|
+
cleanupStaleCognitiveSessions() {
|
|
962
|
+
const killed = [];
|
|
963
|
+
for (const [sessionId] of sessions.entries()) {
|
|
964
|
+
if (sessionModes.get(sessionId) === 'cognitive-agent') {
|
|
965
|
+
const session = sessions.get(sessionId);
|
|
966
|
+
if (session && session.status !== 'dead') {
|
|
967
|
+
session.kill();
|
|
968
|
+
killed.push(sessionId);
|
|
969
|
+
if (eventBus) {
|
|
970
|
+
eventBus.emit({
|
|
971
|
+
version: 1,
|
|
972
|
+
domain: 'session',
|
|
973
|
+
type: 'session.killed',
|
|
974
|
+
severity: 'info',
|
|
975
|
+
sessionId,
|
|
976
|
+
payload: {
|
|
977
|
+
session_id: sessionId,
|
|
978
|
+
killed_by: 'startup_recovery',
|
|
979
|
+
reason: 'cognitive sessions are in-memory only and cannot survive a restart',
|
|
980
|
+
},
|
|
981
|
+
source: 'runtime/sessions/pool',
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
return { killed };
|
|
988
|
+
},
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
//# sourceMappingURL=pool.js.map
|