@roj-ai/sdk 0.1.36 → 0.2.2
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/bootstrap.d.ts +420 -26
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +55 -24
- package/dist/bootstrap.js.map +1 -1
- package/dist/bun-platform/fs.d.ts.map +1 -1
- package/dist/bun-platform/fs.js +1 -0
- package/dist/bun-platform/fs.js.map +1 -1
- package/dist/bun-platform/index.d.ts +4 -1
- package/dist/bun-platform/index.d.ts.map +1 -1
- package/dist/bun-platform/index.js +7 -1
- package/dist/bun-platform/index.js.map +1 -1
- package/dist/bun-platform/server-lifecycle.d.ts +30 -0
- package/dist/bun-platform/server-lifecycle.d.ts.map +1 -0
- package/dist/bun-platform/server-lifecycle.js +182 -0
- package/dist/bun-platform/server-lifecycle.js.map +1 -0
- package/dist/bun-platform/shell.d.ts +33 -0
- package/dist/bun-platform/shell.d.ts.map +1 -0
- package/dist/bun-platform/shell.js +322 -0
- package/dist/bun-platform/shell.js.map +1 -0
- package/dist/config.d.ts +34 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +97 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agents/agent.d.ts +42 -7
- package/dist/core/agents/agent.d.ts.map +1 -1
- package/dist/core/agents/agent.js +202 -87
- package/dist/core/agents/agent.js.map +1 -1
- package/dist/core/agents/config.d.ts +8 -1
- package/dist/core/agents/config.d.ts.map +1 -1
- package/dist/core/agents/config.js +5 -1
- package/dist/core/agents/config.js.map +1 -1
- package/dist/core/agents/retry.d.ts +1 -1
- package/dist/core/agents/retry.d.ts.map +1 -1
- package/dist/core/agents/retry.js +14 -16
- package/dist/core/agents/retry.js.map +1 -1
- package/dist/core/agents/state.d.ts +3 -1
- package/dist/core/agents/state.d.ts.map +1 -1
- package/dist/core/agents/state.js +1 -1
- package/dist/core/agents/state.js.map +1 -1
- package/dist/core/context/state.d.ts +3 -3
- package/dist/core/context/state.js +2 -2
- package/dist/core/events/base-event-store.d.ts.map +1 -1
- package/dist/core/events/base-event-store.js +22 -14
- package/dist/core/events/base-event-store.js.map +1 -1
- package/dist/core/events/file.d.ts +39 -1
- package/dist/core/events/file.d.ts.map +1 -1
- package/dist/core/events/file.js +159 -20
- package/dist/core/events/file.js.map +1 -1
- package/dist/core/events/types.d.ts +1 -1
- package/dist/core/file-store/containment.d.ts +19 -0
- package/dist/core/file-store/containment.d.ts.map +1 -0
- package/dist/core/file-store/containment.js +62 -0
- package/dist/core/file-store/containment.js.map +1 -0
- package/dist/core/file-store/file-store.d.ts +22 -2
- package/dist/core/file-store/file-store.d.ts.map +1 -1
- package/dist/core/file-store/file-store.js +88 -20
- package/dist/core/file-store/file-store.js.map +1 -1
- package/dist/core/file-store/types.d.ts +13 -1
- package/dist/core/file-store/types.d.ts.map +1 -1
- package/dist/core/image/image-processor.d.ts.map +1 -1
- package/dist/core/image/image-processor.js +3 -1
- package/dist/core/image/image-processor.js.map +1 -1
- package/dist/core/image/types.d.ts +2 -0
- package/dist/core/image/types.d.ts.map +1 -1
- package/dist/core/image/vips-resizer.d.ts.map +1 -1
- package/dist/core/image/vips-resizer.js +81 -33
- package/dist/core/image/vips-resizer.js.map +1 -1
- package/dist/core/llm/anthropic.d.ts +0 -1
- package/dist/core/llm/anthropic.d.ts.map +1 -1
- package/dist/core/llm/anthropic.js +58 -72
- package/dist/core/llm/anthropic.js.map +1 -1
- package/dist/core/llm/logger.d.ts +14 -2
- package/dist/core/llm/logger.d.ts.map +1 -1
- package/dist/core/llm/logger.js +161 -36
- package/dist/core/llm/logger.js.map +1 -1
- package/dist/core/llm/openrouter.d.ts +0 -1
- package/dist/core/llm/openrouter.d.ts.map +1 -1
- package/dist/core/llm/openrouter.js +53 -66
- package/dist/core/llm/openrouter.js.map +1 -1
- package/dist/core/llm/provider-request.d.ts +10 -0
- package/dist/core/llm/provider-request.d.ts.map +1 -0
- package/dist/core/llm/provider-request.js +41 -0
- package/dist/core/llm/provider-request.js.map +1 -0
- package/dist/core/llm/provider.d.ts +11 -0
- package/dist/core/llm/provider.d.ts.map +1 -1
- package/dist/core/llm/provider.js +26 -0
- package/dist/core/llm/provider.js.map +1 -1
- package/dist/core/llm/state.d.ts +2 -2
- package/dist/core/llm/state.js +4 -4
- package/dist/core/plugins/plugin-builder.d.ts +57 -3
- package/dist/core/plugins/plugin-builder.d.ts.map +1 -1
- package/dist/core/plugins/plugin-builder.js +68 -14
- package/dist/core/plugins/plugin-builder.js.map +1 -1
- package/dist/core/preset/preset-builder.d.ts +3 -2
- package/dist/core/preset/preset-builder.d.ts.map +1 -1
- package/dist/core/preset/preset-builder.js +7 -16
- package/dist/core/preset/preset-builder.js.map +1 -1
- package/dist/core/sessions/context.d.ts +23 -5
- package/dist/core/sessions/context.d.ts.map +1 -1
- package/dist/core/sessions/runtime-activity.d.ts +33 -0
- package/dist/core/sessions/runtime-activity.d.ts.map +1 -0
- package/dist/core/sessions/runtime-activity.js +55 -0
- package/dist/core/sessions/runtime-activity.js.map +1 -0
- package/dist/core/sessions/schema.d.ts +23 -2
- package/dist/core/sessions/schema.d.ts.map +1 -1
- package/dist/core/sessions/schema.js +24 -3
- package/dist/core/sessions/schema.js.map +1 -1
- package/dist/core/sessions/session-manager.d.ts +83 -6
- package/dist/core/sessions/session-manager.d.ts.map +1 -1
- package/dist/core/sessions/session-manager.js +517 -118
- package/dist/core/sessions/session-manager.js.map +1 -1
- package/dist/core/sessions/session-store.d.ts +18 -0
- package/dist/core/sessions/session-store.d.ts.map +1 -1
- package/dist/core/sessions/session-store.js +33 -0
- package/dist/core/sessions/session-store.js.map +1 -1
- package/dist/core/sessions/session.d.ts +42 -6
- package/dist/core/sessions/session.d.ts.map +1 -1
- package/dist/core/sessions/session.js +176 -44
- package/dist/core/sessions/session.js.map +1 -1
- package/dist/core/sessions/state.d.ts +10 -1
- package/dist/core/sessions/state.d.ts.map +1 -1
- package/dist/core/sessions/state.js +11 -1
- package/dist/core/sessions/state.js.map +1 -1
- package/dist/core/system.d.ts +9 -0
- package/dist/core/system.d.ts.map +1 -1
- package/dist/core/system.js +4 -1
- package/dist/core/system.js.map +1 -1
- package/dist/core/tools/executor.d.ts +1 -1
- package/dist/core/wake-key.d.ts +34 -0
- package/dist/core/wake-key.d.ts.map +1 -0
- package/dist/core/wake-key.js +51 -0
- package/dist/core/wake-key.js.map +1 -0
- package/dist/index.d.ts +25 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -8
- package/dist/index.js.map +1 -1
- package/dist/lib/archive/archive-inspection.d.ts +48 -0
- package/dist/lib/archive/archive-inspection.d.ts.map +1 -0
- package/dist/lib/archive/archive-inspection.fixtures.d.ts +7 -0
- package/dist/lib/archive/archive-inspection.fixtures.d.ts.map +1 -0
- package/dist/lib/archive/archive-inspection.fixtures.js +134 -0
- package/dist/lib/archive/archive-inspection.fixtures.js.map +1 -0
- package/dist/lib/archive/archive-inspection.js +253 -0
- package/dist/lib/archive/archive-inspection.js.map +1 -0
- package/dist/lib/archive/index.d.ts +3 -0
- package/dist/lib/archive/index.d.ts.map +1 -0
- package/dist/lib/archive/index.js +2 -0
- package/dist/lib/archive/index.js.map +1 -0
- package/dist/lib/logger/console.d.ts +5 -12
- package/dist/lib/logger/console.d.ts.map +1 -1
- package/dist/lib/logger/console.js +5 -47
- package/dist/lib/logger/console.js.map +1 -1
- package/dist/lib/logger/file.d.ts +8 -11
- package/dist/lib/logger/file.d.ts.map +1 -1
- package/dist/lib/logger/file.js +26 -37
- package/dist/lib/logger/file.js.map +1 -1
- package/dist/lib/logger/index.d.ts +3 -1
- package/dist/lib/logger/index.d.ts.map +1 -1
- package/dist/lib/logger/index.js +3 -1
- package/dist/lib/logger/index.js.map +1 -1
- package/dist/lib/logger/jsonl.d.ts +21 -0
- package/dist/lib/logger/jsonl.d.ts.map +1 -0
- package/dist/lib/logger/jsonl.js +29 -0
- package/dist/lib/logger/jsonl.js.map +1 -0
- package/dist/lib/logger/logger.d.ts +22 -0
- package/dist/lib/logger/logger.d.ts.map +1 -1
- package/dist/lib/logger/logger.js +37 -0
- package/dist/lib/logger/logger.js.map +1 -1
- package/dist/lib/logger/session-log.d.ts +21 -0
- package/dist/lib/logger/session-log.d.ts.map +1 -0
- package/dist/lib/logger/session-log.js +37 -0
- package/dist/lib/logger/session-log.js.map +1 -0
- package/dist/lib/utils/concurrency.d.ts +1 -1
- package/dist/lib/utils/concurrency.d.ts.map +1 -1
- package/dist/lib/utils/concurrency.js +30 -7
- package/dist/lib/utils/concurrency.js.map +1 -1
- package/dist/lib/utils/fs-batch.d.ts +17 -0
- package/dist/lib/utils/fs-batch.d.ts.map +1 -0
- package/dist/lib/utils/fs-batch.js +38 -0
- package/dist/lib/utils/fs-batch.js.map +1 -0
- package/dist/lib/utils/result.d.ts +7 -22
- package/dist/lib/utils/result.d.ts.map +1 -1
- package/dist/lib/utils/result.js +6 -17
- package/dist/lib/utils/result.js.map +1 -1
- package/dist/lib/utils/sleep.d.ts +10 -0
- package/dist/lib/utils/sleep.d.ts.map +1 -0
- package/dist/lib/utils/sleep.js +26 -0
- package/dist/lib/utils/sleep.js.map +1 -0
- package/dist/platform/fs-revision.d.ts +21 -0
- package/dist/platform/fs-revision.d.ts.map +1 -0
- package/dist/platform/fs-revision.js +9 -0
- package/dist/platform/fs-revision.js.map +1 -0
- package/dist/platform/fs.d.ts +104 -1
- package/dist/platform/fs.d.ts.map +1 -1
- package/dist/platform/git.d.ts +59 -0
- package/dist/platform/git.d.ts.map +1 -0
- package/dist/platform/git.js +8 -0
- package/dist/platform/git.js.map +1 -0
- package/dist/platform/index.d.ts +40 -1
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/index.js.map +1 -1
- package/dist/platform/llm-call-log.d.ts +80 -0
- package/dist/platform/llm-call-log.d.ts.map +1 -0
- package/dist/platform/llm-call-log.js +12 -0
- package/dist/platform/llm-call-log.js.map +1 -0
- package/dist/platform/scheduler.d.ts +32 -0
- package/dist/platform/scheduler.d.ts.map +1 -0
- package/dist/platform/scheduler.js +46 -0
- package/dist/platform/scheduler.js.map +1 -0
- package/dist/platform/session-log.d.ts +36 -0
- package/dist/platform/session-log.d.ts.map +1 -0
- package/dist/platform/session-log.js +12 -0
- package/dist/platform/session-log.js.map +1 -0
- package/dist/platform/shell.d.ts +83 -0
- package/dist/platform/shell.d.ts.map +1 -0
- package/dist/platform/shell.js +13 -0
- package/dist/platform/shell.js.map +1 -0
- package/dist/plugins/agent-status/plugin.d.ts.map +1 -1
- package/dist/plugins/agent-status/plugin.js +1 -0
- package/dist/plugins/agent-status/plugin.js.map +1 -1
- package/dist/plugins/agents/plugin.d.ts.map +1 -1
- package/dist/plugins/agents/plugin.js +129 -62
- package/dist/plugins/agents/plugin.js.map +1 -1
- package/dist/plugins/filesystem/listing.d.ts +3 -0
- package/dist/plugins/filesystem/listing.d.ts.map +1 -1
- package/dist/plugins/filesystem/listing.js +66 -10
- package/dist/plugins/filesystem/listing.js.map +1 -1
- package/dist/plugins/filesystem/plugin.d.ts.map +1 -1
- package/dist/plugins/filesystem/plugin.js +8 -6
- package/dist/plugins/filesystem/plugin.js.map +1 -1
- package/dist/plugins/git-status/index.d.ts +1 -0
- package/dist/plugins/git-status/index.d.ts.map +1 -1
- package/dist/plugins/git-status/plugin.d.ts +38 -7
- package/dist/plugins/git-status/plugin.d.ts.map +1 -1
- package/dist/plugins/git-status/plugin.js +169 -64
- package/dist/plugins/git-status/plugin.js.map +1 -1
- package/dist/plugins/llm-debug/plugin.d.ts.map +1 -1
- package/dist/plugins/llm-debug/plugin.js +1 -0
- package/dist/plugins/llm-debug/plugin.js.map +1 -1
- package/dist/plugins/logs/plugin.d.ts +1 -4
- package/dist/plugins/logs/plugin.d.ts.map +1 -1
- package/dist/plugins/logs/plugin.js +7 -0
- package/dist/plugins/logs/plugin.js.map +1 -1
- package/dist/plugins/mailbox/helpers.d.ts +2 -2
- package/dist/plugins/mailbox/helpers.js +1 -1
- package/dist/plugins/mailbox/plugin.d.ts.map +1 -1
- package/dist/plugins/mailbox/plugin.js +38 -43
- package/dist/plugins/mailbox/plugin.js.map +1 -1
- package/dist/plugins/mailbox/query.d.ts +7 -2
- package/dist/plugins/mailbox/query.d.ts.map +1 -1
- package/dist/plugins/mailbox/query.js +14 -7
- package/dist/plugins/mailbox/query.js.map +1 -1
- package/dist/plugins/mailbox/state.d.ts +5 -4
- package/dist/plugins/mailbox/state.d.ts.map +1 -1
- package/dist/plugins/mailbox/state.js +6 -5
- package/dist/plugins/mailbox/state.js.map +1 -1
- package/dist/plugins/resources/filename.d.ts +4 -0
- package/dist/plugins/resources/filename.d.ts.map +1 -0
- package/dist/plugins/resources/filename.js +18 -0
- package/dist/plugins/resources/filename.js.map +1 -0
- package/dist/plugins/resources/plugin.d.ts +3 -0
- package/dist/plugins/resources/plugin.d.ts.map +1 -1
- package/dist/plugins/resources/plugin.js +97 -60
- package/dist/plugins/resources/plugin.js.map +1 -1
- package/dist/plugins/resources/state.d.ts +1 -1
- package/dist/plugins/resources/state.js +1 -1
- package/dist/plugins/result-eviction/plugin.d.ts.map +1 -1
- package/dist/plugins/result-eviction/plugin.js +6 -1
- package/dist/plugins/result-eviction/plugin.js.map +1 -1
- package/dist/plugins/services/plugin.d.ts +4 -1
- package/dist/plugins/services/plugin.d.ts.map +1 -1
- package/dist/plugins/services/plugin.js +251 -100
- package/dist/plugins/services/plugin.js.map +1 -1
- package/dist/plugins/services/prompt.d.ts.map +1 -1
- package/dist/plugins/services/prompt.js +1 -4
- package/dist/plugins/services/prompt.js.map +1 -1
- package/dist/plugins/services/schema.d.ts +15 -5
- package/dist/plugins/services/schema.d.ts.map +1 -1
- package/dist/plugins/services/service.d.ts +100 -18
- package/dist/plugins/services/service.d.ts.map +1 -1
- package/dist/plugins/services/service.js +680 -230
- package/dist/plugins/services/service.js.map +1 -1
- package/dist/plugins/session-lifecycle/plugin.d.ts +21 -1
- package/dist/plugins/session-lifecycle/plugin.d.ts.map +1 -1
- package/dist/plugins/session-lifecycle/plugin.js +53 -40
- package/dist/plugins/session-lifecycle/plugin.js.map +1 -1
- package/dist/plugins/session-state/plugin.d.ts +21 -13
- package/dist/plugins/session-state/plugin.d.ts.map +1 -1
- package/dist/plugins/session-state/plugin.js +214 -79
- package/dist/plugins/session-state/plugin.js.map +1 -1
- package/dist/plugins/session-stats/plugin.d.ts.map +1 -1
- package/dist/plugins/session-stats/plugin.js +1 -0
- package/dist/plugins/session-stats/plugin.js.map +1 -1
- package/dist/plugins/shell/executor.d.ts +17 -15
- package/dist/plugins/shell/executor.d.ts.map +1 -1
- package/dist/plugins/shell/executor.js +130 -195
- package/dist/plugins/shell/executor.js.map +1 -1
- package/dist/plugins/shell/index.d.ts +2 -2
- package/dist/plugins/shell/index.d.ts.map +1 -1
- package/dist/plugins/shell/index.js +2 -2
- package/dist/plugins/shell/index.js.map +1 -1
- package/dist/plugins/shell/plugin.d.ts +5 -4
- package/dist/plugins/shell/plugin.d.ts.map +1 -1
- package/dist/plugins/shell/plugin.js +4 -8
- package/dist/plugins/shell/plugin.js.map +1 -1
- package/dist/plugins/skills/discovery.d.ts.map +1 -1
- package/dist/plugins/skills/discovery.js +10 -8
- package/dist/plugins/skills/discovery.js.map +1 -1
- package/dist/plugins/skills/index.d.ts +1 -1
- package/dist/plugins/skills/index.d.ts.map +1 -1
- package/dist/plugins/skills/plugin.d.ts +1 -1
- package/dist/plugins/skills/plugin.d.ts.map +1 -1
- package/dist/plugins/skills/plugin.js +23 -30
- package/dist/plugins/skills/plugin.js.map +1 -1
- package/dist/plugins/skills/prompts.d.ts +3 -3
- package/dist/plugins/skills/prompts.d.ts.map +1 -1
- package/dist/plugins/skills/prompts.js.map +1 -1
- package/dist/plugins/skills/schema.d.ts +4 -2
- package/dist/plugins/skills/schema.d.ts.map +1 -1
- package/dist/plugins/todo/schema.d.ts +1 -1
- package/dist/plugins/uploads/plugin.d.ts +11 -4
- package/dist/plugins/uploads/plugin.d.ts.map +1 -1
- package/dist/plugins/uploads/plugin.js +891 -225
- package/dist/plugins/uploads/plugin.js.map +1 -1
- package/dist/plugins/uploads/preprocessor.d.ts +14 -0
- package/dist/plugins/uploads/preprocessor.d.ts.map +1 -1
- package/dist/plugins/uploads/preprocessor.js +11 -0
- package/dist/plugins/uploads/preprocessor.js.map +1 -1
- package/dist/plugins/uploads/preprocessors/image-classifier.d.ts +1 -1
- package/dist/plugins/uploads/preprocessors/image-classifier.d.ts.map +1 -1
- package/dist/plugins/uploads/preprocessors/image-classifier.js +51 -26
- package/dist/plugins/uploads/preprocessors/image-classifier.js.map +1 -1
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts +2 -2
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts.map +1 -1
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js +41 -16
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js.map +1 -1
- package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts +1 -1
- package/dist/plugins/uploads/preprocessors/pdf-preprocessor.d.ts.map +1 -1
- package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js +29 -14
- package/dist/plugins/uploads/preprocessors/pdf-preprocessor.js.map +1 -1
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts +1 -1
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts.map +1 -1
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.js +62 -34
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.js.map +1 -1
- package/dist/plugins/uploads/schema.d.ts +25 -2
- package/dist/plugins/uploads/schema.d.ts.map +1 -1
- package/dist/plugins/uploads/schema.js +24 -3
- package/dist/plugins/uploads/schema.js.map +1 -1
- package/dist/plugins/uploads/state.d.ts +13 -1
- package/dist/plugins/uploads/state.d.ts.map +1 -1
- package/dist/plugins/uploads/state.js +4 -1
- package/dist/plugins/uploads/state.js.map +1 -1
- package/dist/plugins/user-chat/plugin.d.ts +12 -5
- package/dist/plugins/user-chat/plugin.d.ts.map +1 -1
- package/dist/plugins/user-chat/plugin.js +141 -32
- package/dist/plugins/user-chat/plugin.js.map +1 -1
- package/dist/plugins/workers/context.d.ts +35 -13
- package/dist/plugins/workers/context.d.ts.map +1 -1
- package/dist/plugins/workers/context.js +82 -32
- package/dist/plugins/workers/context.js.map +1 -1
- package/dist/plugins/workers/definition.d.ts +7 -0
- package/dist/plugins/workers/definition.d.ts.map +1 -1
- package/dist/plugins/workers/definition.js.map +1 -1
- package/dist/plugins/workers/index.d.ts +4 -4
- package/dist/plugins/workers/index.d.ts.map +1 -1
- package/dist/plugins/workers/index.js +2 -2
- package/dist/plugins/workers/index.js.map +1 -1
- package/dist/plugins/workers/plugin.d.ts +10 -57
- package/dist/plugins/workers/plugin.d.ts.map +1 -1
- package/dist/plugins/workers/plugin.js +385 -123
- package/dist/plugins/workers/plugin.js.map +1 -1
- package/dist/plugins/workers/state.d.ts +69 -0
- package/dist/plugins/workers/state.d.ts.map +1 -0
- package/dist/plugins/workers/state.js +52 -0
- package/dist/plugins/workers/state.js.map +1 -0
- package/dist/plugins/workers/worker.d.ts +15 -4
- package/dist/plugins/workers/worker.d.ts.map +1 -1
- package/dist/testing/conformance.d.ts +106 -0
- package/dist/testing/conformance.d.ts.map +1 -0
- package/dist/testing/conformance.js +1463 -0
- package/dist/testing/conformance.js.map +1 -0
- package/dist/testing/node-platform.d.ts.map +1 -1
- package/dist/testing/node-platform.js +5 -0
- package/dist/testing/node-platform.js.map +1 -1
- package/dist/testing/test-harness.d.ts +11 -1
- package/dist/testing/test-harness.d.ts.map +1 -1
- package/dist/testing/test-harness.js +17 -37
- package/dist/testing/test-harness.js.map +1 -1
- package/dist/testing/wait-helpers.d.ts.map +1 -1
- package/dist/testing/wait-helpers.js +1 -3
- package/dist/testing/wait-helpers.js.map +1 -1
- package/dist/transport/adapter/client-adapter.d.ts +6 -0
- package/dist/transport/adapter/client-adapter.d.ts.map +1 -1
- package/dist/transport/adapter/client-adapter.js +50 -3
- package/dist/transport/adapter/client-adapter.js.map +1 -1
- package/dist/transport/adapter/heartbeat.d.ts +16 -0
- package/dist/transport/adapter/heartbeat.d.ts.map +1 -0
- package/dist/transport/adapter/heartbeat.js +41 -0
- package/dist/transport/adapter/heartbeat.js.map +1 -0
- package/dist/transport/adapter/server-adapter.d.ts.map +1 -1
- package/dist/transport/adapter/server-adapter.js +6 -0
- package/dist/transport/adapter/server-adapter.js.map +1 -1
- package/dist/transport/http/app.d.ts +3 -30
- package/dist/transport/http/app.d.ts.map +1 -1
- package/dist/transport/http/app.js +3 -7
- package/dist/transport/http/app.js.map +1 -1
- package/dist/transport/http/context.d.ts +40 -0
- package/dist/transport/http/context.d.ts.map +1 -0
- package/dist/transport/http/context.js +17 -0
- package/dist/transport/http/context.js.map +1 -0
- package/dist/transport/http/fetch-guard.d.ts +49 -0
- package/dist/transport/http/fetch-guard.d.ts.map +1 -0
- package/dist/transport/http/fetch-guard.js +312 -0
- package/dist/transport/http/fetch-guard.js.map +1 -0
- package/dist/transport/http/index.d.ts +1 -1
- package/dist/transport/http/index.d.ts.map +1 -1
- package/dist/transport/http/middleware/bearer-auth.d.ts +1 -1
- package/dist/transport/http/middleware/bearer-auth.d.ts.map +1 -1
- package/dist/transport/http/middleware/error-handler.d.ts +2 -2
- package/dist/transport/http/middleware/error-handler.d.ts.map +1 -1
- package/dist/transport/http/path-containment.d.ts +20 -0
- package/dist/transport/http/path-containment.d.ts.map +1 -0
- package/dist/transport/http/path-containment.js +31 -0
- package/dist/transport/http/path-containment.js.map +1 -0
- package/dist/transport/http/responses.d.ts +30 -0
- package/dist/transport/http/responses.d.ts.map +1 -0
- package/dist/transport/http/responses.js +5 -0
- package/dist/transport/http/responses.js.map +1 -0
- package/dist/transport/http/routes/files.d.ts +1 -1
- package/dist/transport/http/routes/files.d.ts.map +1 -1
- package/dist/transport/http/routes/files.js +54 -155
- package/dist/transport/http/routes/files.js.map +1 -1
- package/dist/transport/http/routes/resources.d.ts +1 -1
- package/dist/transport/http/routes/resources.d.ts.map +1 -1
- package/dist/transport/http/routes/resources.js +92 -57
- package/dist/transport/http/routes/resources.js.map +1 -1
- package/dist/transport/http/routes/rpc.d.ts +6 -1
- package/dist/transport/http/routes/rpc.d.ts.map +1 -1
- package/dist/transport/http/routes/rpc.js +51 -21
- package/dist/transport/http/routes/rpc.js.map +1 -1
- package/dist/transport/http/routes/upload.d.ts +1 -1
- package/dist/transport/http/routes/upload.d.ts.map +1 -1
- package/dist/transport/http/routes/upload.js +256 -169
- package/dist/transport/http/routes/upload.js.map +1 -1
- package/dist/user-config.d.ts +34 -7
- package/dist/user-config.d.ts.map +1 -1
- package/dist/user-config.js +71 -0
- package/dist/user-config.js.map +1 -1
- package/package.json +17 -7
- package/src/bootstrap.ts +119 -35
- package/src/bun-platform/fs.ts +1 -0
- package/src/bun-platform/index.ts +18 -1
- package/src/bun-platform/server-lifecycle.ts +218 -0
- package/src/bun-platform/shell.ts +362 -0
- package/src/config.ts +130 -0
- package/src/core/agents/agent.ts +210 -92
- package/src/core/agents/config.ts +8 -0
- package/src/core/agents/retry.ts +16 -17
- package/src/core/agents/state.ts +2 -0
- package/src/core/events/base-event-store.ts +24 -16
- package/src/core/events/file.ts +198 -22
- package/src/core/file-store/containment.ts +75 -0
- package/src/core/file-store/file-store.ts +106 -25
- package/src/core/file-store/types.ts +14 -1
- package/src/core/image/image-processor.ts +3 -1
- package/src/core/image/types.ts +2 -0
- package/src/core/image/vips-resizer.ts +102 -37
- package/src/core/llm/anthropic.ts +63 -79
- package/src/core/llm/logger.ts +175 -37
- package/src/core/llm/openrouter.ts +57 -72
- package/src/core/llm/provider-request.ts +40 -0
- package/src/core/llm/provider.ts +28 -0
- package/src/core/plugins/plugin-builder.ts +106 -14
- package/src/core/preset/preset-builder.ts +12 -22
- package/src/core/sessions/context.ts +18 -0
- package/src/core/sessions/runtime-activity.ts +78 -0
- package/src/core/sessions/schema.ts +29 -3
- package/src/core/sessions/session-manager.ts +560 -140
- package/src/core/sessions/session-store.ts +38 -0
- package/src/core/sessions/session.ts +187 -47
- package/src/core/sessions/state.ts +11 -0
- package/src/core/system.ts +15 -0
- package/src/core/wake-key.ts +65 -0
- package/src/index.ts +32 -12
- package/src/lib/archive/archive-inspection.fixtures.ts +138 -0
- package/src/lib/archive/archive-inspection.ts +359 -0
- package/src/lib/archive/index.ts +17 -0
- package/src/lib/logger/console.ts +7 -57
- package/src/lib/logger/file.ts +28 -50
- package/src/lib/logger/index.ts +3 -1
- package/src/lib/logger/jsonl.ts +36 -0
- package/src/lib/logger/logger.ts +48 -0
- package/src/lib/logger/session-log.ts +42 -0
- package/src/lib/utils/concurrency.ts +37 -8
- package/src/lib/utils/fs-batch.ts +49 -0
- package/src/lib/utils/result.ts +7 -31
- package/src/lib/utils/sleep.ts +23 -0
- package/src/platform/fs-revision.ts +21 -0
- package/src/platform/fs.ts +109 -1
- package/src/platform/git.ts +67 -0
- package/src/platform/index.ts +51 -1
- package/src/platform/llm-call-log.ts +86 -0
- package/src/platform/scheduler.ts +71 -0
- package/src/platform/session-log.ts +39 -0
- package/src/platform/shell.ts +89 -0
- package/src/plugins/agent-status/plugin.ts +1 -0
- package/src/plugins/agents/plugin.ts +134 -81
- package/src/plugins/filesystem/listing.ts +70 -12
- package/src/plugins/filesystem/plugin.ts +8 -6
- package/src/plugins/git-status/index.ts +1 -0
- package/src/plugins/git-status/plugin.ts +211 -77
- package/src/plugins/llm-debug/plugin.ts +1 -0
- package/src/plugins/logs/plugin.ts +9 -0
- package/src/plugins/mailbox/plugin.ts +46 -64
- package/src/plugins/mailbox/query.ts +15 -7
- package/src/plugins/mailbox/state.ts +1 -0
- package/src/plugins/resources/filename.ts +19 -0
- package/src/plugins/resources/plugin.ts +111 -59
- package/src/plugins/result-eviction/plugin.ts +6 -1
- package/src/plugins/services/plugin.ts +254 -98
- package/src/plugins/services/prompt.ts +1 -6
- package/src/plugins/services/schema.ts +17 -3
- package/src/plugins/services/service.ts +702 -252
- package/src/plugins/session-lifecycle/plugin.ts +56 -41
- package/src/plugins/session-state/plugin.ts +242 -88
- package/src/plugins/session-stats/plugin.ts +1 -0
- package/src/plugins/shell/executor.ts +144 -226
- package/src/plugins/shell/index.ts +1 -4
- package/src/plugins/shell/plugin.ts +7 -9
- package/src/plugins/skills/discovery.ts +10 -8
- package/src/plugins/skills/index.ts +1 -1
- package/src/plugins/skills/plugin.ts +19 -27
- package/src/plugins/skills/prompts.ts +3 -3
- package/src/plugins/skills/schema.ts +5 -2
- package/src/plugins/uploads/plugin.ts +991 -273
- package/src/plugins/uploads/preprocessor.ts +25 -0
- package/src/plugins/uploads/preprocessors/image-classifier.ts +56 -25
- package/src/plugins/uploads/preprocessors/markitdown-preprocessor.ts +41 -15
- package/src/plugins/uploads/preprocessors/pdf-preprocessor.ts +32 -16
- package/src/plugins/uploads/preprocessors/zip-preprocessor.ts +67 -38
- package/src/plugins/uploads/schema.ts +30 -3
- package/src/plugins/uploads/state.ts +12 -0
- package/src/plugins/user-chat/plugin.ts +196 -40
- package/src/plugins/workers/context.ts +102 -39
- package/src/plugins/workers/definition.ts +7 -0
- package/src/plugins/workers/index.ts +4 -4
- package/src/plugins/workers/plugin.ts +461 -151
- package/src/plugins/workers/state.ts +64 -0
- package/src/plugins/workers/worker.ts +15 -4
- package/src/testing/conformance.ts +1751 -0
- package/src/testing/node-platform.ts +5 -0
- package/src/testing/test-harness.ts +21 -38
- package/src/testing/wait-helpers.ts +1 -4
- package/src/transport/adapter/client-adapter.ts +60 -3
- package/src/transport/adapter/heartbeat.ts +50 -0
- package/src/transport/adapter/server-adapter.ts +6 -0
- package/src/transport/http/app.ts +7 -35
- package/src/transport/http/context.ts +46 -0
- package/src/transport/http/fetch-guard.ts +318 -0
- package/src/transport/http/index.ts +1 -1
- package/src/transport/http/middleware/bearer-auth.ts +1 -1
- package/src/transport/http/middleware/error-handler.ts +1 -1
- package/src/transport/http/path-containment.ts +44 -0
- package/src/transport/http/responses.ts +20 -0
- package/src/transport/http/routes/files.ts +69 -159
- package/src/transport/http/routes/resources.ts +124 -93
- package/src/transport/http/routes/rpc.ts +63 -26
- package/src/transport/http/routes/upload.ts +327 -258
- package/src/user-config.ts +93 -7
- package/dist/config.test.d.ts +0 -2
- package/dist/config.test.d.ts.map +0 -1
- package/dist/config.test.js +0 -155
- package/dist/config.test.js.map +0 -1
- package/dist/core/agent-loop.integration.test.d.ts +0 -2
- package/dist/core/agent-loop.integration.test.d.ts.map +0 -1
- package/dist/core/agent-loop.integration.test.js +0 -414
- package/dist/core/agent-loop.integration.test.js.map +0 -1
- package/dist/core/agents/agent-config.test.d.ts +0 -2
- package/dist/core/agents/agent-config.test.d.ts.map +0 -1
- package/dist/core/agents/agent-config.test.js +0 -194
- package/dist/core/agents/agent-config.test.js.map +0 -1
- package/dist/core/agents/agent-shutdown.test.d.ts +0 -6
- package/dist/core/agents/agent-shutdown.test.d.ts.map +0 -1
- package/dist/core/agents/agent-shutdown.test.js +0 -180
- package/dist/core/agents/agent-shutdown.test.js.map +0 -1
- package/dist/core/agents/agent.test.d.ts +0 -2
- package/dist/core/agents/agent.test.d.ts.map +0 -1
- package/dist/core/agents/agent.test.js +0 -313
- package/dist/core/agents/agent.test.js.map +0 -1
- package/dist/core/agents/communicator.d.ts +0 -3
- package/dist/core/agents/communicator.d.ts.map +0 -1
- package/dist/core/agents/communicator.js +0 -13
- package/dist/core/agents/communicator.js.map +0 -1
- package/dist/core/agents/handler-events.test.d.ts +0 -5
- package/dist/core/agents/handler-events.test.d.ts.map +0 -1
- package/dist/core/agents/handler-events.test.js +0 -115
- package/dist/core/agents/handler-events.test.js.map +0 -1
- package/dist/core/agents/response-sanitizer.test.d.ts +0 -2
- package/dist/core/agents/response-sanitizer.test.d.ts.map +0 -1
- package/dist/core/agents/response-sanitizer.test.js +0 -101
- package/dist/core/agents/response-sanitizer.test.js.map +0 -1
- package/dist/core/error-recovery.integration.test.d.ts +0 -2
- package/dist/core/error-recovery.integration.test.d.ts.map +0 -1
- package/dist/core/error-recovery.integration.test.js +0 -288
- package/dist/core/error-recovery.integration.test.js.map +0 -1
- package/dist/core/event-sourcing.integration.test.d.ts +0 -2
- package/dist/core/event-sourcing.integration.test.d.ts.map +0 -1
- package/dist/core/event-sourcing.integration.test.js +0 -154
- package/dist/core/event-sourcing.integration.test.js.map +0 -1
- package/dist/core/events/file.test.d.ts +0 -2
- package/dist/core/events/file.test.d.ts.map +0 -1
- package/dist/core/events/file.test.js +0 -284
- package/dist/core/events/file.test.js.map +0 -1
- package/dist/core/events/memory.test.d.ts +0 -2
- package/dist/core/events/memory.test.d.ts.map +0 -1
- package/dist/core/events/memory.test.js +0 -502
- package/dist/core/events/memory.test.js.map +0 -1
- package/dist/core/image/image-processor.test.d.ts +0 -2
- package/dist/core/image/image-processor.test.d.ts.map +0 -1
- package/dist/core/image/image-processor.test.js +0 -171
- package/dist/core/image/image-processor.test.js.map +0 -1
- package/dist/core/image/vips-resizer.test.d.ts +0 -2
- package/dist/core/image/vips-resizer.test.d.ts.map +0 -1
- package/dist/core/image/vips-resizer.test.js +0 -336
- package/dist/core/image/vips-resizer.test.js.map +0 -1
- package/dist/core/llm/anthropic.test.d.ts +0 -2
- package/dist/core/llm/anthropic.test.d.ts.map +0 -1
- package/dist/core/llm/anthropic.test.js +0 -464
- package/dist/core/llm/anthropic.test.js.map +0 -1
- package/dist/core/llm/cache-breakpoints.test.d.ts +0 -2
- package/dist/core/llm/cache-breakpoints.test.d.ts.map +0 -1
- package/dist/core/llm/cache-breakpoints.test.js +0 -69
- package/dist/core/llm/cache-breakpoints.test.js.map +0 -1
- package/dist/core/llm/cache-live.test.d.ts +0 -16
- package/dist/core/llm/cache-live.test.d.ts.map +0 -1
- package/dist/core/llm/cache-live.test.js +0 -137
- package/dist/core/llm/cache-live.test.js.map +0 -1
- package/dist/core/llm/logger.test.d.ts +0 -7
- package/dist/core/llm/logger.test.d.ts.map +0 -1
- package/dist/core/llm/logger.test.js +0 -228
- package/dist/core/llm/logger.test.js.map +0 -1
- package/dist/core/llm/message-sanitization.test.d.ts +0 -2
- package/dist/core/llm/message-sanitization.test.d.ts.map +0 -1
- package/dist/core/llm/message-sanitization.test.js +0 -181
- package/dist/core/llm/message-sanitization.test.js.map +0 -1
- package/dist/core/llm/mock.test.d.ts +0 -2
- package/dist/core/llm/mock.test.d.ts.map +0 -1
- package/dist/core/llm/mock.test.js +0 -318
- package/dist/core/llm/mock.test.js.map +0 -1
- package/dist/core/llm/model-shortlist-live.test.d.ts +0 -35
- package/dist/core/llm/model-shortlist-live.test.d.ts.map +0 -1
- package/dist/core/llm/model-shortlist-live.test.js +0 -452
- package/dist/core/llm/model-shortlist-live.test.js.map +0 -1
- package/dist/core/llm/openrouter-mapping.test.d.ts +0 -2
- package/dist/core/llm/openrouter-mapping.test.d.ts.map +0 -1
- package/dist/core/llm/openrouter-mapping.test.js +0 -190
- package/dist/core/llm/openrouter-mapping.test.js.map +0 -1
- package/dist/core/llm/openrouter.test.d.ts +0 -2
- package/dist/core/llm/openrouter.test.d.ts.map +0 -1
- package/dist/core/llm/openrouter.test.js +0 -377
- package/dist/core/llm/openrouter.test.js.map +0 -1
- package/dist/core/llm/provider-integration.test.d.ts +0 -12
- package/dist/core/llm/provider-integration.test.d.ts.map +0 -1
- package/dist/core/llm/provider-integration.test.js +0 -350
- package/dist/core/llm/provider-integration.test.js.map +0 -1
- package/dist/core/llm/reasoning-details.test.d.ts +0 -2
- package/dist/core/llm/reasoning-details.test.d.ts.map +0 -1
- package/dist/core/llm/reasoning-details.test.js +0 -144
- package/dist/core/llm/reasoning-details.test.js.map +0 -1
- package/dist/core/llm/routing-provider.test.d.ts +0 -2
- package/dist/core/llm/routing-provider.test.d.ts.map +0 -1
- package/dist/core/llm/routing-provider.test.js +0 -94
- package/dist/core/llm/routing-provider.test.js.map +0 -1
- package/dist/core/llm/snapshot-middleware.test.d.ts +0 -2
- package/dist/core/llm/snapshot-middleware.test.d.ts.map +0 -1
- package/dist/core/llm/snapshot-middleware.test.js +0 -144
- package/dist/core/llm/snapshot-middleware.test.js.map +0 -1
- package/dist/core/llm/thinking-blocks.test.d.ts +0 -2
- package/dist/core/llm/thinking-blocks.test.d.ts.map +0 -1
- package/dist/core/llm/thinking-blocks.test.js +0 -291
- package/dist/core/llm/thinking-blocks.test.js.map +0 -1
- package/dist/core/multi-agent.integration.test.d.ts +0 -2
- package/dist/core/multi-agent.integration.test.d.ts.map +0 -1
- package/dist/core/multi-agent.integration.test.js +0 -298
- package/dist/core/multi-agent.integration.test.js.map +0 -1
- package/dist/core/plugin-hooks.integration.test.d.ts +0 -2
- package/dist/core/plugin-hooks.integration.test.d.ts.map +0 -1
- package/dist/core/plugin-hooks.integration.test.js +0 -458
- package/dist/core/plugin-hooks.integration.test.js.map +0 -1
- package/dist/core/reasoning-round-trip.integration.test.d.ts +0 -2
- package/dist/core/reasoning-round-trip.integration.test.d.ts.map +0 -1
- package/dist/core/reasoning-round-trip.integration.test.js +0 -150
- package/dist/core/reasoning-round-trip.integration.test.js.map +0 -1
- package/dist/core/session-lifecycle.integration.test.d.ts +0 -2
- package/dist/core/session-lifecycle.integration.test.d.ts.map +0 -1
- package/dist/core/session-lifecycle.integration.test.js +0 -159
- package/dist/core/session-lifecycle.integration.test.js.map +0 -1
- package/dist/core/sessions/fork-utils.test.d.ts +0 -2
- package/dist/core/sessions/fork-utils.test.d.ts.map +0 -1
- package/dist/core/sessions/fork-utils.test.js +0 -129
- package/dist/core/sessions/fork-utils.test.js.map +0 -1
- package/dist/core/sessions/session-overrides.integration.test.d.ts +0 -2
- package/dist/core/sessions/session-overrides.integration.test.d.ts.map +0 -1
- package/dist/core/sessions/session-overrides.integration.test.js +0 -154
- package/dist/core/sessions/session-overrides.integration.test.js.map +0 -1
- package/dist/core/sessions/session.test.d.ts +0 -2
- package/dist/core/sessions/session.test.d.ts.map +0 -1
- package/dist/core/sessions/session.test.js +0 -1100
- package/dist/core/sessions/session.test.js.map +0 -1
- package/dist/core/tools/executor.test.d.ts +0 -2
- package/dist/core/tools/executor.test.d.ts.map +0 -1
- package/dist/core/tools/executor.test.js +0 -144
- package/dist/core/tools/executor.test.js.map +0 -1
- package/dist/lib/logger/console.test.d.ts +0 -2
- package/dist/lib/logger/console.test.d.ts.map +0 -1
- package/dist/lib/logger/console.test.js +0 -258
- package/dist/lib/logger/console.test.js.map +0 -1
- package/dist/lib/never.d.ts +0 -2
- package/dist/lib/never.d.ts.map +0 -1
- package/dist/lib/never.js +0 -4
- package/dist/lib/never.js.map +0 -1
- package/dist/lib/utils/concurrency.test.d.ts +0 -2
- package/dist/lib/utils/concurrency.test.d.ts.map +0 -1
- package/dist/lib/utils/concurrency.test.js +0 -135
- package/dist/lib/utils/concurrency.test.js.map +0 -1
- package/dist/plugins/agent-status/agent-status.test.d.ts +0 -2
- package/dist/plugins/agent-status/agent-status.test.d.ts.map +0 -1
- package/dist/plugins/agent-status/agent-status.test.js +0 -136
- package/dist/plugins/agent-status/agent-status.test.js.map +0 -1
- package/dist/plugins/agents/agents.integration.test.d.ts +0 -2
- package/dist/plugins/agents/agents.integration.test.d.ts.map +0 -1
- package/dist/plugins/agents/agents.integration.test.js +0 -830
- package/dist/plugins/agents/agents.integration.test.js.map +0 -1
- package/dist/plugins/agents/supervision.integration.test.d.ts +0 -2
- package/dist/plugins/agents/supervision.integration.test.d.ts.map +0 -1
- package/dist/plugins/agents/supervision.integration.test.js +0 -215
- package/dist/plugins/agents/supervision.integration.test.js.map +0 -1
- package/dist/plugins/context-compact/compaction-live.test.d.ts +0 -17
- package/dist/plugins/context-compact/compaction-live.test.d.ts.map +0 -1
- package/dist/plugins/context-compact/compaction-live.test.js +0 -177
- package/dist/plugins/context-compact/compaction-live.test.js.map +0 -1
- package/dist/plugins/context-compact/context-compact.integration.test.d.ts +0 -2
- package/dist/plugins/context-compact/context-compact.integration.test.d.ts.map +0 -1
- package/dist/plugins/context-compact/context-compact.integration.test.js +0 -364
- package/dist/plugins/context-compact/context-compact.integration.test.js.map +0 -1
- package/dist/plugins/context-compact/context-compactor.test.d.ts +0 -2
- package/dist/plugins/context-compact/context-compactor.test.d.ts.map +0 -1
- package/dist/plugins/context-compact/context-compactor.test.js +0 -858
- package/dist/plugins/context-compact/context-compactor.test.js.map +0 -1
- package/dist/plugins/context-compact/history-offloader.test.d.ts +0 -2
- package/dist/plugins/context-compact/history-offloader.test.d.ts.map +0 -1
- package/dist/plugins/context-compact/history-offloader.test.js +0 -77
- package/dist/plugins/context-compact/history-offloader.test.js.map +0 -1
- package/dist/plugins/filesystem/filesystem.integration.test.d.ts +0 -2
- package/dist/plugins/filesystem/filesystem.integration.test.d.ts.map +0 -1
- package/dist/plugins/filesystem/filesystem.integration.test.js +0 -447
- package/dist/plugins/filesystem/filesystem.integration.test.js.map +0 -1
- package/dist/plugins/filesystem/schema.d.ts +0 -7
- package/dist/plugins/filesystem/schema.d.ts.map +0 -1
- package/dist/plugins/filesystem/schema.js +0 -2
- package/dist/plugins/filesystem/schema.js.map +0 -1
- package/dist/plugins/limits-guard/limit-guard.test.d.ts +0 -2
- package/dist/plugins/limits-guard/limit-guard.test.d.ts.map +0 -1
- package/dist/plugins/limits-guard/limit-guard.test.js +0 -194
- package/dist/plugins/limits-guard/limit-guard.test.js.map +0 -1
- package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts +0 -2
- package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts.map +0 -1
- package/dist/plugins/limits-guard/limits-guard.integration.test.js +0 -887
- package/dist/plugins/limits-guard/limits-guard.integration.test.js.map +0 -1
- package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts +0 -2
- package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts.map +0 -1
- package/dist/plugins/llm-debug/llm-debug.integration.test.js +0 -157
- package/dist/plugins/llm-debug/llm-debug.integration.test.js.map +0 -1
- package/dist/plugins/mailbox/mailbox.integration.test.d.ts +0 -2
- package/dist/plugins/mailbox/mailbox.integration.test.d.ts.map +0 -1
- package/dist/plugins/mailbox/mailbox.integration.test.js +0 -678
- package/dist/plugins/mailbox/mailbox.integration.test.js.map +0 -1
- package/dist/plugins/resources/resources.integration.test.d.ts +0 -2
- package/dist/plugins/resources/resources.integration.test.d.ts.map +0 -1
- package/dist/plugins/resources/resources.integration.test.js +0 -62
- package/dist/plugins/resources/resources.integration.test.js.map +0 -1
- package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts +0 -2
- package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts.map +0 -1
- package/dist/plugins/result-eviction/result-eviction.integration.test.js +0 -294
- package/dist/plugins/result-eviction/result-eviction.integration.test.js.map +0 -1
- package/dist/plugins/services/pid-registry.test.d.ts +0 -2
- package/dist/plugins/services/pid-registry.test.d.ts.map +0 -1
- package/dist/plugins/services/pid-registry.test.js +0 -161
- package/dist/plugins/services/pid-registry.test.js.map +0 -1
- package/dist/plugins/services/services.integration.test.d.ts +0 -2
- package/dist/plugins/services/services.integration.test.d.ts.map +0 -1
- package/dist/plugins/services/services.integration.test.js +0 -1057
- package/dist/plugins/services/services.integration.test.js.map +0 -1
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts +0 -2
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts.map +0 -1
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js +0 -498
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js.map +0 -1
- package/dist/plugins/session-stats/plugin.test.d.ts +0 -2
- package/dist/plugins/session-stats/plugin.test.d.ts.map +0 -1
- package/dist/plugins/session-stats/plugin.test.js +0 -145
- package/dist/plugins/session-stats/plugin.test.js.map +0 -1
- package/dist/plugins/shell/shell.integration.test.d.ts +0 -2
- package/dist/plugins/shell/shell.integration.test.d.ts.map +0 -1
- package/dist/plugins/shell/shell.integration.test.js +0 -234
- package/dist/plugins/shell/shell.integration.test.js.map +0 -1
- package/dist/plugins/shell/shell.test.d.ts +0 -2
- package/dist/plugins/shell/shell.test.d.ts.map +0 -1
- package/dist/plugins/shell/shell.test.js +0 -236
- package/dist/plugins/shell/shell.test.js.map +0 -1
- package/dist/plugins/skills/discovery.test.d.ts +0 -2
- package/dist/plugins/skills/discovery.test.d.ts.map +0 -1
- package/dist/plugins/skills/discovery.test.js +0 -312
- package/dist/plugins/skills/discovery.test.js.map +0 -1
- package/dist/plugins/skills/skills.integration.test.d.ts +0 -2
- package/dist/plugins/skills/skills.integration.test.d.ts.map +0 -1
- package/dist/plugins/skills/skills.integration.test.js +0 -475
- package/dist/plugins/skills/skills.integration.test.js.map +0 -1
- package/dist/plugins/todo/todo.integration.test.d.ts +0 -2
- package/dist/plugins/todo/todo.integration.test.d.ts.map +0 -1
- package/dist/plugins/todo/todo.integration.test.js +0 -605
- package/dist/plugins/todo/todo.integration.test.js.map +0 -1
- package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts +0 -2
- package/dist/plugins/uploads/preprocessors/image-classifier.test.d.ts.map +0 -1
- package/dist/plugins/uploads/preprocessors/image-classifier.test.js +0 -113
- package/dist/plugins/uploads/preprocessors/image-classifier.test.js.map +0 -1
- package/dist/plugins/uploads/uploads.integration.test.d.ts +0 -2
- package/dist/plugins/uploads/uploads.integration.test.d.ts.map +0 -1
- package/dist/plugins/uploads/uploads.integration.test.js +0 -639
- package/dist/plugins/uploads/uploads.integration.test.js.map +0 -1
- package/dist/plugins/user-chat/user-chat.integration.test.d.ts +0 -2
- package/dist/plugins/user-chat/user-chat.integration.test.d.ts.map +0 -1
- package/dist/plugins/user-chat/user-chat.integration.test.js +0 -754
- package/dist/plugins/user-chat/user-chat.integration.test.js.map +0 -1
- package/dist/plugins/workers/workers.integration.test.d.ts +0 -2
- package/dist/plugins/workers/workers.integration.test.d.ts.map +0 -1
- package/dist/plugins/workers/workers.integration.test.js +0 -629
- package/dist/plugins/workers/workers.integration.test.js.map +0 -1
- package/dist/prompts/macros.test.d.ts +0 -2
- package/dist/prompts/macros.test.d.ts.map +0 -1
- package/dist/prompts/macros.test.js +0 -80
- package/dist/prompts/macros.test.js.map +0 -1
- package/dist/testing/test-harness.test.d.ts +0 -2
- package/dist/testing/test-harness.test.d.ts.map +0 -1
- package/dist/testing/test-harness.test.js +0 -92
- package/dist/testing/test-harness.test.js.map +0 -1
- package/dist/transport/http/routes/rpc.integration.test.d.ts +0 -2
- package/dist/transport/http/routes/rpc.integration.test.d.ts.map +0 -1
- package/dist/transport/http/routes/rpc.integration.test.js +0 -189
- package/dist/transport/http/routes/rpc.integration.test.js.map +0 -1
- package/dist/transport/http/routes/rpc.test.d.ts +0 -2
- package/dist/transport/http/routes/rpc.test.d.ts.map +0 -1
- package/dist/transport/http/routes/rpc.test.js +0 -316
- package/dist/transport/http/routes/rpc.test.js.map +0 -1
- package/src/config.test.ts +0 -174
- package/src/core/agent-loop.integration.test.ts +0 -503
- package/src/core/agents/agent-config.test.ts +0 -240
- package/src/core/agents/agent-shutdown.test.ts +0 -236
- package/src/core/agents/agent.test.ts +0 -387
- package/src/core/agents/communicator.ts +0 -16
- package/src/core/agents/handler-events.test.ts +0 -167
- package/src/core/agents/response-sanitizer.test.ts +0 -137
- package/src/core/error-recovery.integration.test.ts +0 -343
- package/src/core/event-sourcing.integration.test.ts +0 -191
- package/src/core/events/file.test.ts +0 -436
- package/src/core/events/memory.test.ts +0 -741
- package/src/core/image/image-processor.test.ts +0 -218
- package/src/core/image/vips-resizer.test.ts +0 -388
- package/src/core/llm/anthropic.test.ts +0 -546
- package/src/core/llm/cache-breakpoints.test.ts +0 -85
- package/src/core/llm/cache-live.test.ts +0 -155
- package/src/core/llm/logger.test.ts +0 -270
- package/src/core/llm/message-sanitization.test.ts +0 -217
- package/src/core/llm/mock.test.ts +0 -402
- package/src/core/llm/model-shortlist-live.test.ts +0 -577
- package/src/core/llm/openrouter-mapping.test.ts +0 -234
- package/src/core/llm/openrouter.test.ts +0 -499
- package/src/core/llm/provider-integration.test.ts +0 -408
- package/src/core/llm/reasoning-details.test.ts +0 -177
- package/src/core/llm/routing-provider.test.ts +0 -113
- package/src/core/llm/snapshot-middleware.test.ts +0 -168
- package/src/core/llm/thinking-blocks.test.ts +0 -345
- package/src/core/multi-agent.integration.test.ts +0 -340
- package/src/core/plugin-hooks.integration.test.ts +0 -568
- package/src/core/reasoning-round-trip.integration.test.ts +0 -188
- package/src/core/session-lifecycle.integration.test.ts +0 -202
- package/src/core/sessions/fork-utils.test.ts +0 -158
- package/src/core/sessions/session-overrides.integration.test.ts +0 -210
- package/src/core/sessions/session.test.ts +0 -1736
- package/src/core/tools/executor.test.ts +0 -161
- package/src/lib/logger/console.test.ts +0 -348
- package/src/lib/never.ts +0 -3
- package/src/lib/utils/concurrency.test.ts +0 -169
- package/src/plugins/agent-status/agent-status.test.ts +0 -164
- package/src/plugins/agents/agents.integration.test.ts +0 -976
- package/src/plugins/agents/supervision.integration.test.ts +0 -249
- package/src/plugins/context-compact/compaction-live.test.ts +0 -221
- package/src/plugins/context-compact/context-compact.integration.test.ts +0 -418
- package/src/plugins/context-compact/context-compactor.test.ts +0 -1036
- package/src/plugins/context-compact/history-offloader.test.ts +0 -100
- package/src/plugins/filesystem/filesystem.integration.test.ts +0 -529
- package/src/plugins/filesystem/schema.ts +0 -6
- package/src/plugins/limits-guard/limit-guard.test.ts +0 -253
- package/src/plugins/limits-guard/limits-guard.integration.test.ts +0 -1012
- package/src/plugins/llm-debug/llm-debug.integration.test.ts +0 -192
- package/src/plugins/mailbox/mailbox.integration.test.ts +0 -794
- package/src/plugins/resources/resources.integration.test.ts +0 -68
- package/src/plugins/result-eviction/result-eviction.integration.test.ts +0 -332
- package/src/plugins/services/pid-registry.test.ts +0 -180
- package/src/plugins/services/services.integration.test.ts +0 -1223
- package/src/plugins/session-lifecycle/session-lifecycle.integration.test.ts +0 -639
- package/src/plugins/session-stats/plugin.test.ts +0 -160
- package/src/plugins/shell/shell.integration.test.ts +0 -273
- package/src/plugins/shell/shell.test.ts +0 -314
- package/src/plugins/skills/discovery.test.ts +0 -395
- package/src/plugins/skills/skills.integration.test.ts +0 -580
- package/src/plugins/todo/todo.integration.test.ts +0 -687
- package/src/plugins/uploads/preprocessors/image-classifier.test.ts +0 -142
- package/src/plugins/uploads/uploads.integration.test.ts +0 -831
- package/src/plugins/user-chat/user-chat.integration.test.ts +0 -893
- package/src/plugins/workers/workers.integration.test.ts +0 -778
- package/src/prompts/macros.test.ts +0 -107
- package/src/testing/test-harness.test.ts +0 -114
- package/src/transport/http/routes/rpc.integration.test.ts +0 -243
- package/src/transport/http/routes/rpc.test.ts +0 -372
|
@@ -1,1057 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, it } from 'bun:test';
|
|
2
|
-
import { mkdir, mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { MemoryEventStore } from '../../core/events/memory.js';
|
|
6
|
-
import { MockLLMProvider } from '../../core/llm/mock.js';
|
|
7
|
-
import { selectPluginState } from '../../core/sessions/reducer.js';
|
|
8
|
-
import { SessionId } from '../../core/sessions/schema.js';
|
|
9
|
-
import { ToolCallId } from '../../core/tools/schema.js';
|
|
10
|
-
import { silentLogger } from '../../lib/logger/logger.js';
|
|
11
|
-
import { createNodePlatform } from '../../testing/node-platform.js';
|
|
12
|
-
import { createTestPreset, TestHarness } from '../../testing/index.js';
|
|
13
|
-
import { serviceEvents, servicePlugin } from './plugin.js';
|
|
14
|
-
import { PortPool } from './port-pool.js';
|
|
15
|
-
import { buildServiceStatusMessage } from './prompt.js';
|
|
16
|
-
import { ServiceExecutor } from './service.js';
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// Test Service Configs
|
|
19
|
-
// ============================================================================
|
|
20
|
-
const quickService = {
|
|
21
|
-
type: 'quick',
|
|
22
|
-
description: 'Quick service that becomes ready immediately',
|
|
23
|
-
command: 'echo "service output" && sleep 60',
|
|
24
|
-
};
|
|
25
|
-
const readyPatternService = {
|
|
26
|
-
type: 'ready-service',
|
|
27
|
-
description: 'Service with ready pattern',
|
|
28
|
-
command: 'echo "Listening READY" && sleep 60',
|
|
29
|
-
readyPattern: 'READY',
|
|
30
|
-
};
|
|
31
|
-
const commandCallbackService = {
|
|
32
|
-
type: 'callback-service',
|
|
33
|
-
description: 'Service with command callback that uses allocated port',
|
|
34
|
-
command: ({ port }) => `echo "Server on port ${port}" && sleep 60`,
|
|
35
|
-
readyPattern: 'Server on port',
|
|
36
|
-
};
|
|
37
|
-
const failingService = {
|
|
38
|
-
type: 'failing',
|
|
39
|
-
description: 'Service that exits immediately',
|
|
40
|
-
command: 'exit 1',
|
|
41
|
-
};
|
|
42
|
-
const autoStartService = {
|
|
43
|
-
type: 'auto-start',
|
|
44
|
-
description: 'Auto-starting service',
|
|
45
|
-
command: 'sleep 60',
|
|
46
|
-
autoStart: true,
|
|
47
|
-
};
|
|
48
|
-
// ============================================================================
|
|
49
|
-
// Helpers
|
|
50
|
-
// ============================================================================
|
|
51
|
-
let currentHarness;
|
|
52
|
-
afterEach(async () => {
|
|
53
|
-
if (currentHarness) {
|
|
54
|
-
await currentHarness.shutdown();
|
|
55
|
-
currentHarness = undefined;
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
function createServicesPreset(services, agentServices, portPool, overrides) {
|
|
59
|
-
return createTestPreset({
|
|
60
|
-
...overrides,
|
|
61
|
-
plugins: [
|
|
62
|
-
servicePlugin.configure({ services, portPool }),
|
|
63
|
-
...(overrides?.plugins ?? []),
|
|
64
|
-
],
|
|
65
|
-
orchestratorPlugins: [
|
|
66
|
-
servicePlugin.configureAgent({ services: agentServices }),
|
|
67
|
-
...(overrides?.orchestratorPlugins ?? []),
|
|
68
|
-
],
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
function createServicesHarness(options) {
|
|
72
|
-
const harness = new TestHarness({ ...options, systemPlugins: [servicePlugin] });
|
|
73
|
-
currentHarness = harness;
|
|
74
|
-
return harness;
|
|
75
|
-
}
|
|
76
|
-
/** Wait for a service status change event of a specific type */
|
|
77
|
-
async function waitForServiceStatus(session, serviceType, targetStatus, timeoutMs = 5000) {
|
|
78
|
-
const deadline = Date.now() + timeoutMs;
|
|
79
|
-
while (Date.now() < deadline) {
|
|
80
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
81
|
-
if (events.some((e) => e.serviceType === serviceType && e.toStatus === targetStatus)) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/** Wait for the services plugin state slice to reflect a given status for a serviceType */
|
|
88
|
-
async function waitForServiceStateStatus(session, serviceType, targetStatus, timeoutMs = 5000) {
|
|
89
|
-
const deadline = Date.now() + timeoutMs;
|
|
90
|
-
while (Date.now() < deadline) {
|
|
91
|
-
const entry = selectPluginState(session.state, 'services')?.get(serviceType);
|
|
92
|
-
if (entry?.status === targetStatus)
|
|
93
|
-
return;
|
|
94
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
// ============================================================================
|
|
98
|
-
// Tests
|
|
99
|
-
// ============================================================================
|
|
100
|
-
describe('services plugin', () => {
|
|
101
|
-
// =========================================================================
|
|
102
|
-
// Service lifecycle via methods
|
|
103
|
-
// =========================================================================
|
|
104
|
-
describe('service lifecycle via methods', () => {
|
|
105
|
-
it('start → status_changed events (starting, ready) → state updated', async () => {
|
|
106
|
-
const portPool = new PortPool();
|
|
107
|
-
const harness = createServicesHarness({
|
|
108
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
109
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
110
|
-
});
|
|
111
|
-
const session = await harness.createSession('test');
|
|
112
|
-
await session.sendAndWaitForIdle('Hi');
|
|
113
|
-
const entryAgentId = session.getEntryAgentId();
|
|
114
|
-
const result = await session.callPluginMethod('services.start', {
|
|
115
|
-
sessionId: String(session.sessionId),
|
|
116
|
-
agentId: String(entryAgentId),
|
|
117
|
-
serviceType: 'quick',
|
|
118
|
-
});
|
|
119
|
-
expect(result.ok).toBe(true);
|
|
120
|
-
// Wait for ready (no readyPattern = immediately ready)
|
|
121
|
-
await waitForServiceStatus(session, 'quick', 'ready');
|
|
122
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
123
|
-
const quickEvents = events.filter((e) => e.serviceType === 'quick');
|
|
124
|
-
const statuses = quickEvents.map((e) => e.toStatus);
|
|
125
|
-
expect(statuses).toContain('starting');
|
|
126
|
-
expect(statuses).toContain('ready');
|
|
127
|
-
// Verify state has port from pool
|
|
128
|
-
const serviceState = selectPluginState(session.state, 'services')?.get('quick');
|
|
129
|
-
expect(serviceState).toBeDefined();
|
|
130
|
-
expect(serviceState.status).toBe('ready');
|
|
131
|
-
expect(serviceState.port).toBeGreaterThanOrEqual(10000);
|
|
132
|
-
expect(serviceState.port).toBeLessThanOrEqual(49151);
|
|
133
|
-
});
|
|
134
|
-
it('stop running service → status stopped', async () => {
|
|
135
|
-
const portPool = new PortPool();
|
|
136
|
-
const harness = createServicesHarness({
|
|
137
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
138
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
139
|
-
});
|
|
140
|
-
const session = await harness.createSession('test');
|
|
141
|
-
await session.sendAndWaitForIdle('Hi');
|
|
142
|
-
const entryAgentId = session.getEntryAgentId();
|
|
143
|
-
await session.callPluginMethod('services.start', {
|
|
144
|
-
sessionId: String(session.sessionId),
|
|
145
|
-
agentId: String(entryAgentId),
|
|
146
|
-
serviceType: 'quick',
|
|
147
|
-
});
|
|
148
|
-
await waitForServiceStatus(session, 'quick', 'ready');
|
|
149
|
-
const stopResult = await session.callPluginMethod('services.stop', {
|
|
150
|
-
sessionId: String(session.sessionId),
|
|
151
|
-
agentId: String(entryAgentId),
|
|
152
|
-
serviceType: 'quick',
|
|
153
|
-
});
|
|
154
|
-
expect(stopResult.ok).toBe(true);
|
|
155
|
-
await waitForServiceStatus(session, 'quick', 'stopped');
|
|
156
|
-
const serviceState = selectPluginState(session.state, 'services')?.get('quick');
|
|
157
|
-
expect(serviceState.status).toBe('stopped');
|
|
158
|
-
});
|
|
159
|
-
it('start already running service → idempotent', async () => {
|
|
160
|
-
const portPool = new PortPool();
|
|
161
|
-
const harness = createServicesHarness({
|
|
162
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
163
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
164
|
-
});
|
|
165
|
-
const session = await harness.createSession('test');
|
|
166
|
-
await session.sendAndWaitForIdle('Hi');
|
|
167
|
-
const entryAgentId = session.getEntryAgentId();
|
|
168
|
-
await session.callPluginMethod('services.start', {
|
|
169
|
-
sessionId: String(session.sessionId),
|
|
170
|
-
agentId: String(entryAgentId),
|
|
171
|
-
serviceType: 'quick',
|
|
172
|
-
});
|
|
173
|
-
await waitForServiceStatus(session, 'quick', 'ready');
|
|
174
|
-
// Start again — should be idempotent
|
|
175
|
-
const result = await session.callPluginMethod('services.start', {
|
|
176
|
-
sessionId: String(session.sessionId),
|
|
177
|
-
agentId: String(entryAgentId),
|
|
178
|
-
serviceType: 'quick',
|
|
179
|
-
});
|
|
180
|
-
expect(result.ok).toBe(true);
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
// =========================================================================
|
|
184
|
-
// Port pool allocation
|
|
185
|
-
// =========================================================================
|
|
186
|
-
describe('port pool allocation', () => {
|
|
187
|
-
it('starting event includes allocated port', async () => {
|
|
188
|
-
const portPool = new PortPool();
|
|
189
|
-
const harness = createServicesHarness({
|
|
190
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
191
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
192
|
-
});
|
|
193
|
-
const session = await harness.createSession('test');
|
|
194
|
-
await session.sendAndWaitForIdle('Hi');
|
|
195
|
-
const entryAgentId = session.getEntryAgentId();
|
|
196
|
-
await session.callPluginMethod('services.start', {
|
|
197
|
-
sessionId: String(session.sessionId),
|
|
198
|
-
agentId: String(entryAgentId),
|
|
199
|
-
serviceType: 'quick',
|
|
200
|
-
});
|
|
201
|
-
await waitForServiceStatus(session, 'quick', 'ready');
|
|
202
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
203
|
-
const startingEvent = events.find((e) => e.serviceType === 'quick' && e.toStatus === 'starting');
|
|
204
|
-
expect(startingEvent).toBeDefined();
|
|
205
|
-
expect(startingEvent.port).toBeGreaterThanOrEqual(10000);
|
|
206
|
-
});
|
|
207
|
-
it('command callback receives allocated port', async () => {
|
|
208
|
-
const portPool = new PortPool();
|
|
209
|
-
const harness = createServicesHarness({
|
|
210
|
-
presets: [createServicesPreset([commandCallbackService], ['callback-service'], portPool)],
|
|
211
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
212
|
-
});
|
|
213
|
-
const session = await harness.createSession('test');
|
|
214
|
-
await session.sendAndWaitForIdle('Hi');
|
|
215
|
-
const entryAgentId = session.getEntryAgentId();
|
|
216
|
-
await session.callPluginMethod('services.start', {
|
|
217
|
-
sessionId: String(session.sessionId),
|
|
218
|
-
agentId: String(entryAgentId),
|
|
219
|
-
serviceType: 'callback-service',
|
|
220
|
-
});
|
|
221
|
-
await waitForServiceStatus(session, 'callback-service', 'ready');
|
|
222
|
-
// Port should be in state from starting event
|
|
223
|
-
const serviceState = selectPluginState(session.state, 'services')?.get('callback-service');
|
|
224
|
-
expect(serviceState.port).toBeGreaterThanOrEqual(10000);
|
|
225
|
-
});
|
|
226
|
-
it('resolves cwd, command, and env callbacks with runtime context', async () => {
|
|
227
|
-
const workspaceDir = await mkdtemp(join(tmpdir(), 'roj-svc-runtime-'));
|
|
228
|
-
const webDir = join(workspaceDir, 'packages', 'web');
|
|
229
|
-
await mkdir(webDir, { recursive: true });
|
|
230
|
-
let cwdArgs;
|
|
231
|
-
let commandArgs;
|
|
232
|
-
let envArgs;
|
|
233
|
-
const runtimeService = {
|
|
234
|
-
type: 'runtime',
|
|
235
|
-
description: 'Service with runtime resolvers',
|
|
236
|
-
cwd: (args) => {
|
|
237
|
-
cwdArgs = args;
|
|
238
|
-
return 'packages/web';
|
|
239
|
-
},
|
|
240
|
-
command: async (args) => {
|
|
241
|
-
commandArgs = args;
|
|
242
|
-
return `printf "%s" "$RUNTIME_MARKER" > marker.txt && echo "READY ${args.port}" && sleep 60`;
|
|
243
|
-
},
|
|
244
|
-
env: (args) => {
|
|
245
|
-
envArgs = args;
|
|
246
|
-
return {
|
|
247
|
-
RUNTIME_MARKER: `${args.sessionId}|${args.workspaceDir}|${args.cwd}|${args.port}`,
|
|
248
|
-
};
|
|
249
|
-
},
|
|
250
|
-
readyPattern: 'READY',
|
|
251
|
-
};
|
|
252
|
-
try {
|
|
253
|
-
const portPool = new PortPool();
|
|
254
|
-
const harness = createServicesHarness({
|
|
255
|
-
presets: [createServicesPreset([runtimeService], ['runtime'], portPool, { workspaceDir })],
|
|
256
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
257
|
-
});
|
|
258
|
-
const session = await harness.createSession('test');
|
|
259
|
-
const entryAgentId = session.getEntryAgentId();
|
|
260
|
-
const startResult = await session.callPluginMethod('services.start', {
|
|
261
|
-
sessionId: String(session.sessionId),
|
|
262
|
-
agentId: String(entryAgentId),
|
|
263
|
-
serviceType: 'runtime',
|
|
264
|
-
});
|
|
265
|
-
expect(startResult.ok).toBe(true);
|
|
266
|
-
await waitForServiceStatus(session, 'runtime', 'ready');
|
|
267
|
-
const serviceState = selectPluginState(session.state, 'services')?.get('runtime');
|
|
268
|
-
expect(cwdArgs?.workspaceDir).toBe(workspaceDir);
|
|
269
|
-
expect(cwdArgs?.sessionId).toBe(String(session.sessionId));
|
|
270
|
-
expect(commandArgs?.cwd).toBe(webDir);
|
|
271
|
-
expect(commandArgs?.workspaceDir).toBe(workspaceDir);
|
|
272
|
-
expect(envArgs?.cwd).toBe(webDir);
|
|
273
|
-
expect(serviceState?.cwd).toBe(webDir);
|
|
274
|
-
expect(serviceState?.command).toContain('RUNTIME_MARKER');
|
|
275
|
-
const marker = await readFile(join(webDir, 'marker.txt'), 'utf-8');
|
|
276
|
-
expect(marker).toContain(String(session.sessionId));
|
|
277
|
-
expect(marker).toContain(workspaceDir);
|
|
278
|
-
expect(marker).toContain(webDir);
|
|
279
|
-
const statusResult = await session.callPluginMethod('services.status', {
|
|
280
|
-
sessionId: String(session.sessionId),
|
|
281
|
-
agentId: String(entryAgentId),
|
|
282
|
-
serviceType: 'runtime',
|
|
283
|
-
});
|
|
284
|
-
expect(statusResult).toMatchObject({
|
|
285
|
-
ok: true,
|
|
286
|
-
value: {
|
|
287
|
-
status: 'ready',
|
|
288
|
-
cwd: webDir,
|
|
289
|
-
command: serviceState?.command,
|
|
290
|
-
},
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
finally {
|
|
294
|
-
await rm(workspaceDir, { recursive: true, force: true });
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
// =========================================================================
|
|
299
|
-
// Service tools
|
|
300
|
-
// =========================================================================
|
|
301
|
-
describe('service tools', () => {
|
|
302
|
-
it('agent calls service_start tool → service starts', async () => {
|
|
303
|
-
const portPool = new PortPool();
|
|
304
|
-
const harness = createServicesHarness({
|
|
305
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
306
|
-
llmProvider: MockLLMProvider.withSequence([
|
|
307
|
-
{
|
|
308
|
-
toolCalls: [{
|
|
309
|
-
id: ToolCallId('tc1'),
|
|
310
|
-
name: 'service_start',
|
|
311
|
-
input: { serviceType: 'quick' },
|
|
312
|
-
}],
|
|
313
|
-
},
|
|
314
|
-
{ content: 'Done', toolCalls: [] },
|
|
315
|
-
]),
|
|
316
|
-
});
|
|
317
|
-
const session = await harness.createSession('test');
|
|
318
|
-
await session.sendAndWaitForIdle('Start service');
|
|
319
|
-
await waitForServiceStatus(session, 'quick', 'ready');
|
|
320
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
321
|
-
const quickEvents = events.filter((e) => e.serviceType === 'quick');
|
|
322
|
-
expect(quickEvents.length).toBeGreaterThanOrEqual(1);
|
|
323
|
-
});
|
|
324
|
-
it('agent calls service_status → returns status info', async () => {
|
|
325
|
-
const portPool = new PortPool();
|
|
326
|
-
const harness = createServicesHarness({
|
|
327
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
328
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
329
|
-
});
|
|
330
|
-
const session = await harness.createSession('test');
|
|
331
|
-
await session.sendAndWaitForIdle('Hi');
|
|
332
|
-
const entryAgentId = session.getEntryAgentId();
|
|
333
|
-
// Start service
|
|
334
|
-
await session.callPluginMethod('services.start', {
|
|
335
|
-
sessionId: String(session.sessionId),
|
|
336
|
-
agentId: String(entryAgentId),
|
|
337
|
-
serviceType: 'quick',
|
|
338
|
-
});
|
|
339
|
-
await waitForServiceStatus(session, 'quick', 'ready');
|
|
340
|
-
// Get status
|
|
341
|
-
const statusResult = await session.callPluginMethod('services.status', {
|
|
342
|
-
sessionId: String(session.sessionId),
|
|
343
|
-
agentId: String(entryAgentId),
|
|
344
|
-
serviceType: 'quick',
|
|
345
|
-
});
|
|
346
|
-
expect(statusResult).toMatchObject({ ok: true, value: { status: 'ready' } });
|
|
347
|
-
});
|
|
348
|
-
it('service not in agent visible list → error', async () => {
|
|
349
|
-
const portPool = new PortPool();
|
|
350
|
-
const harness = createServicesHarness({
|
|
351
|
-
presets: [createServicesPreset([quickService], [], portPool)], // empty visible list
|
|
352
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
353
|
-
});
|
|
354
|
-
const session = await harness.createSession('test');
|
|
355
|
-
await session.sendAndWaitForIdle('Hi');
|
|
356
|
-
// No service tools should be available
|
|
357
|
-
const lastRequest = harness.llmProvider.getLastRequest();
|
|
358
|
-
const toolNames = lastRequest?.tools?.map((t) => t.name) ?? [];
|
|
359
|
-
expect(toolNames).not.toContain('service_start');
|
|
360
|
-
expect(toolNames).not.toContain('service_stop');
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
// =========================================================================
|
|
364
|
-
// Auto-start on session ready
|
|
365
|
-
// =========================================================================
|
|
366
|
-
describe('auto-start on session ready', () => {
|
|
367
|
-
it('service with autoStart: true → started on session creation', async () => {
|
|
368
|
-
const portPool = new PortPool();
|
|
369
|
-
const harness = createServicesHarness({
|
|
370
|
-
presets: [createServicesPreset([autoStartService], ['auto-start'], portPool)],
|
|
371
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
372
|
-
});
|
|
373
|
-
const session = await harness.createSession('test');
|
|
374
|
-
// Session creation triggers onSessionReady → autoStart services
|
|
375
|
-
await waitForServiceStatus(session, 'auto-start', 'ready');
|
|
376
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
377
|
-
const autoEvents = events.filter((e) => e.serviceType === 'auto-start');
|
|
378
|
-
expect(autoEvents.length).toBeGreaterThanOrEqual(1);
|
|
379
|
-
});
|
|
380
|
-
it('availableWhen false skips auto-start and explicit start returns an error', async () => {
|
|
381
|
-
const unavailableService = {
|
|
382
|
-
type: 'unavailable',
|
|
383
|
-
description: 'Unavailable service',
|
|
384
|
-
command: 'sleep 60',
|
|
385
|
-
autoStart: true,
|
|
386
|
-
availableWhen: () => false,
|
|
387
|
-
};
|
|
388
|
-
const portPool = new PortPool();
|
|
389
|
-
const harness = createServicesHarness({
|
|
390
|
-
presets: [createServicesPreset([unavailableService], ['unavailable'], portPool)],
|
|
391
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
392
|
-
});
|
|
393
|
-
const session = await harness.createSession('test');
|
|
394
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
395
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
396
|
-
expect(events.some((event) => event.serviceType === 'unavailable')).toBe(false);
|
|
397
|
-
const entryAgentId = session.getEntryAgentId();
|
|
398
|
-
const result = await session.callPluginMethod('services.start', {
|
|
399
|
-
sessionId: String(session.sessionId),
|
|
400
|
-
agentId: String(entryAgentId),
|
|
401
|
-
serviceType: 'unavailable',
|
|
402
|
-
});
|
|
403
|
-
expect(result.ok).toBe(false);
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
// =========================================================================
|
|
407
|
-
// Service failure
|
|
408
|
-
// =========================================================================
|
|
409
|
-
describe('service failure', () => {
|
|
410
|
-
it('service that exits immediately → status failed with error', async () => {
|
|
411
|
-
const portPool = new PortPool();
|
|
412
|
-
const harness = createServicesHarness({
|
|
413
|
-
presets: [createServicesPreset([failingService], ['failing'], portPool)],
|
|
414
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
415
|
-
});
|
|
416
|
-
const session = await harness.createSession('test');
|
|
417
|
-
await session.sendAndWaitForIdle('Hi');
|
|
418
|
-
const entryAgentId = session.getEntryAgentId();
|
|
419
|
-
await session.callPluginMethod('services.start', {
|
|
420
|
-
sessionId: String(session.sessionId),
|
|
421
|
-
agentId: String(entryAgentId),
|
|
422
|
-
serviceType: 'failing',
|
|
423
|
-
});
|
|
424
|
-
await waitForServiceStatus(session, 'failing', 'failed');
|
|
425
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
426
|
-
const failEvent = events.find((e) => e.serviceType === 'failing' && e.toStatus === 'failed');
|
|
427
|
-
expect(failEvent).toBeDefined();
|
|
428
|
-
expect(failEvent.error).toBeDefined();
|
|
429
|
-
});
|
|
430
|
-
});
|
|
431
|
-
// =========================================================================
|
|
432
|
-
// Ready pattern
|
|
433
|
-
// =========================================================================
|
|
434
|
-
describe('ready pattern', () => {
|
|
435
|
-
it('service with readyPattern → status ready when pattern matches', async () => {
|
|
436
|
-
const portPool = new PortPool();
|
|
437
|
-
const harness = createServicesHarness({
|
|
438
|
-
presets: [createServicesPreset([readyPatternService], ['ready-service'], portPool)],
|
|
439
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
440
|
-
});
|
|
441
|
-
const session = await harness.createSession('test');
|
|
442
|
-
await session.sendAndWaitForIdle('Hi');
|
|
443
|
-
const entryAgentId = session.getEntryAgentId();
|
|
444
|
-
await session.callPluginMethod('services.start', {
|
|
445
|
-
sessionId: String(session.sessionId),
|
|
446
|
-
agentId: String(entryAgentId),
|
|
447
|
-
serviceType: 'ready-service',
|
|
448
|
-
});
|
|
449
|
-
await waitForServiceStatus(session, 'ready-service', 'ready');
|
|
450
|
-
const serviceState = selectPluginState(session.state, 'services')?.get('ready-service');
|
|
451
|
-
expect(serviceState.status).toBe('ready');
|
|
452
|
-
});
|
|
453
|
-
it('readyWhen can mark a service ready without output pattern', async () => {
|
|
454
|
-
let checks = 0;
|
|
455
|
-
const readyWhenService = {
|
|
456
|
-
type: 'ready-when',
|
|
457
|
-
description: 'Service with callback readiness',
|
|
458
|
-
command: 'sleep 60',
|
|
459
|
-
readyWhen: () => {
|
|
460
|
-
checks += 1;
|
|
461
|
-
return checks > 1;
|
|
462
|
-
},
|
|
463
|
-
readyCheckIntervalMs: 20,
|
|
464
|
-
startupTimeoutMs: 1000,
|
|
465
|
-
};
|
|
466
|
-
const portPool = new PortPool();
|
|
467
|
-
const harness = createServicesHarness({
|
|
468
|
-
presets: [createServicesPreset([readyWhenService], ['ready-when'], portPool)],
|
|
469
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
470
|
-
});
|
|
471
|
-
const session = await harness.createSession('test');
|
|
472
|
-
const entryAgentId = session.getEntryAgentId();
|
|
473
|
-
const result = await session.callPluginMethod('services.start', {
|
|
474
|
-
sessionId: String(session.sessionId),
|
|
475
|
-
agentId: String(entryAgentId),
|
|
476
|
-
serviceType: 'ready-when',
|
|
477
|
-
});
|
|
478
|
-
expect(result.ok).toBe(true);
|
|
479
|
-
await waitForServiceStatus(session, 'ready-when', 'ready');
|
|
480
|
-
expect(checks).toBeGreaterThan(1);
|
|
481
|
-
});
|
|
482
|
-
});
|
|
483
|
-
// =========================================================================
|
|
484
|
-
// Server restart reconcile
|
|
485
|
-
// =========================================================================
|
|
486
|
-
describe('onSessionReady reconcile after server restart', () => {
|
|
487
|
-
it('preserves port in state when service transitions to stopped', async () => {
|
|
488
|
-
const portPool = new PortPool();
|
|
489
|
-
const harness = createServicesHarness({
|
|
490
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
491
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
492
|
-
});
|
|
493
|
-
const session = await harness.createSession('test');
|
|
494
|
-
await session.sendAndWaitForIdle('Hi');
|
|
495
|
-
const entryAgentId = session.getEntryAgentId();
|
|
496
|
-
await session.callPluginMethod('services.start', {
|
|
497
|
-
sessionId: String(session.sessionId),
|
|
498
|
-
agentId: String(entryAgentId),
|
|
499
|
-
serviceType: 'quick',
|
|
500
|
-
});
|
|
501
|
-
await waitForServiceStateStatus(session, 'quick', 'ready');
|
|
502
|
-
const portBefore = selectPluginState(session.state, 'services')?.get('quick')?.port;
|
|
503
|
-
expect(portBefore).toBeDefined();
|
|
504
|
-
await session.callPluginMethod('services.stop', {
|
|
505
|
-
sessionId: String(session.sessionId),
|
|
506
|
-
agentId: String(entryAgentId),
|
|
507
|
-
serviceType: 'quick',
|
|
508
|
-
});
|
|
509
|
-
await waitForServiceStateStatus(session, 'quick', 'stopped');
|
|
510
|
-
const stopped = selectPluginState(session.state, 'services')?.get('quick');
|
|
511
|
-
expect(stopped?.status).toBe('stopped');
|
|
512
|
-
expect(stopped?.port).toBe(portBefore);
|
|
513
|
-
expect(stopped?.pid).toBeUndefined();
|
|
514
|
-
});
|
|
515
|
-
it('kills orphaned process group from previous server instance', async () => {
|
|
516
|
-
const eventStore = new MemoryEventStore();
|
|
517
|
-
// Harness 1: start service, capture pid + port, then "crash" (shutdown
|
|
518
|
-
// without running onSessionClose — matches session.shutdown() behavior).
|
|
519
|
-
const harness1 = new TestHarness({
|
|
520
|
-
presets: [createServicesPreset([quickService], ['quick'], new PortPool())],
|
|
521
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
522
|
-
systemPlugins: [servicePlugin],
|
|
523
|
-
eventStore,
|
|
524
|
-
});
|
|
525
|
-
const session1 = await harness1.createSession('test');
|
|
526
|
-
await session1.sendAndWaitForIdle('Hi');
|
|
527
|
-
const entryAgentId = session1.getEntryAgentId();
|
|
528
|
-
await session1.callPluginMethod('services.start', {
|
|
529
|
-
sessionId: String(session1.sessionId),
|
|
530
|
-
agentId: String(entryAgentId),
|
|
531
|
-
serviceType: 'quick',
|
|
532
|
-
});
|
|
533
|
-
await waitForServiceStateStatus(session1, 'quick', 'ready');
|
|
534
|
-
const stateBefore = selectPluginState(session1.state, 'services')?.get('quick');
|
|
535
|
-
const orphanPid = stateBefore?.pid;
|
|
536
|
-
const orphanPort = stateBefore?.port;
|
|
537
|
-
expect(orphanPid).toBeDefined();
|
|
538
|
-
expect(orphanPort).toBeDefined();
|
|
539
|
-
// Process should be alive before restart
|
|
540
|
-
expect(() => process.kill(orphanPid, 0)).not.toThrow();
|
|
541
|
-
const sessionId = session1.sessionId;
|
|
542
|
-
// Simulate server crash: sessionManager.shutdown() clears in-memory state
|
|
543
|
-
// but does NOT run onSessionClose, so the detached service process survives.
|
|
544
|
-
await harness1.sessionManager.shutdown();
|
|
545
|
-
// Orphan must still be alive after "crash"
|
|
546
|
-
expect(() => process.kill(orphanPid, 0)).not.toThrow();
|
|
547
|
-
// Harness 2: fresh SessionManager over the same event store
|
|
548
|
-
const harness2 = new TestHarness({
|
|
549
|
-
presets: [createServicesPreset([quickService], ['quick'], new PortPool())],
|
|
550
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
551
|
-
systemPlugins: [servicePlugin],
|
|
552
|
-
eventStore,
|
|
553
|
-
});
|
|
554
|
-
currentHarness = harness2;
|
|
555
|
-
// Opening the session fires onSessionReady → reconcile kills the orphan
|
|
556
|
-
const session2 = await harness2.openSession(sessionId);
|
|
557
|
-
await waitForServiceStateStatus(session2, 'quick', 'stopped', 3000);
|
|
558
|
-
// Give the OS a beat to reap the killed process
|
|
559
|
-
for (let i = 0; i < 20; i++) {
|
|
560
|
-
try {
|
|
561
|
-
process.kill(orphanPid, 0);
|
|
562
|
-
}
|
|
563
|
-
catch {
|
|
564
|
-
break;
|
|
565
|
-
}
|
|
566
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
567
|
-
}
|
|
568
|
-
let isAlive = true;
|
|
569
|
-
try {
|
|
570
|
-
process.kill(orphanPid, 0);
|
|
571
|
-
}
|
|
572
|
-
catch {
|
|
573
|
-
isAlive = false;
|
|
574
|
-
}
|
|
575
|
-
// Safety net in case reconcile didn't kill it — don't leave zombies behind
|
|
576
|
-
if (isAlive) {
|
|
577
|
-
try {
|
|
578
|
-
process.kill(-orphanPid, 'SIGKILL');
|
|
579
|
-
}
|
|
580
|
-
catch {
|
|
581
|
-
// already gone
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
expect(isAlive).toBe(false);
|
|
585
|
-
// Port preserved in state — next start() would receive it via preferredPort
|
|
586
|
-
const stateAfter = selectPluginState(session2.state, 'services')?.get('quick');
|
|
587
|
-
expect(stateAfter?.status).toBe('stopped');
|
|
588
|
-
expect(stateAfter?.port).toBe(orphanPort);
|
|
589
|
-
expect(stateAfter?.pid).toBeUndefined();
|
|
590
|
-
});
|
|
591
|
-
});
|
|
592
|
-
describe('session close cleanup', () => {
|
|
593
|
-
it('closing session stops running services', async () => {
|
|
594
|
-
const portPool = new PortPool();
|
|
595
|
-
const harness = createServicesHarness({
|
|
596
|
-
presets: [createServicesPreset([quickService], ['quick'], portPool)],
|
|
597
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
598
|
-
});
|
|
599
|
-
const session = await harness.createSession('test');
|
|
600
|
-
await session.sendAndWaitForIdle('Hi');
|
|
601
|
-
const entryAgentId = session.getEntryAgentId();
|
|
602
|
-
await session.callPluginMethod('services.start', {
|
|
603
|
-
sessionId: String(session.sessionId),
|
|
604
|
-
agentId: String(entryAgentId),
|
|
605
|
-
serviceType: 'quick',
|
|
606
|
-
});
|
|
607
|
-
await waitForServiceStatus(session, 'quick', 'ready');
|
|
608
|
-
// Close session → should stop services
|
|
609
|
-
await session.close();
|
|
610
|
-
// Wait for stopped event
|
|
611
|
-
await waitForServiceStatus(session, 'quick', 'stopped', 10000);
|
|
612
|
-
const events = await session.getEventsByType(serviceEvents, 'service_status_changed');
|
|
613
|
-
const stoppedEvent = events.find((e) => e.serviceType === 'quick' && e.toStatus === 'stopped');
|
|
614
|
-
expect(stoppedEvent).toBeDefined();
|
|
615
|
-
});
|
|
616
|
-
});
|
|
617
|
-
// =========================================================================
|
|
618
|
-
// Port conflict recovery + concurrent start (ServiceExecutor unit-level)
|
|
619
|
-
// =========================================================================
|
|
620
|
-
describe('port conflict recovery and concurrent start', () => {
|
|
621
|
-
const waitUntil = async (predicate, timeoutMs = 8000) => {
|
|
622
|
-
const deadline = Date.now() + timeoutMs;
|
|
623
|
-
while (Date.now() < deadline) {
|
|
624
|
-
if (predicate())
|
|
625
|
-
return;
|
|
626
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
627
|
-
}
|
|
628
|
-
};
|
|
629
|
-
it('collapses concurrent start() calls onto a single process', async () => {
|
|
630
|
-
const platform = createNodePlatform();
|
|
631
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
632
|
-
const marker = join(tmpdir(), `roj-svc-mutex-${Date.now()}-${Math.floor(Math.random() * 1e6)}`);
|
|
633
|
-
const config = {
|
|
634
|
-
type: 'concurrent',
|
|
635
|
-
description: 'appends one line per spawned process',
|
|
636
|
-
command: `echo spawned >> ${marker} && sleep 30`,
|
|
637
|
-
};
|
|
638
|
-
try {
|
|
639
|
-
const [r1, r2] = await Promise.all([
|
|
640
|
-
executor.start(config, SessionId('s-concurrent')),
|
|
641
|
-
executor.start(config, SessionId('s-concurrent')),
|
|
642
|
-
]);
|
|
643
|
-
expect(r1.ok).toBe(true);
|
|
644
|
-
expect(r2.ok).toBe(true);
|
|
645
|
-
// Let the shell flush its append.
|
|
646
|
-
await new Promise((r) => setTimeout(r, 400));
|
|
647
|
-
const lines = (await readFile(marker, 'utf-8')).split('\n').filter((l) => l.length > 0);
|
|
648
|
-
// Without the in-flight lock both starts spawn and the file gets two lines.
|
|
649
|
-
expect(lines.length).toBe(1);
|
|
650
|
-
}
|
|
651
|
-
finally {
|
|
652
|
-
await executor.shutdown();
|
|
653
|
-
await rm(marker, { force: true });
|
|
654
|
-
}
|
|
655
|
-
});
|
|
656
|
-
it('recovers on a fresh port when the chosen port is in use (EADDRINUSE)', async () => {
|
|
657
|
-
const platform = createNodePlatform();
|
|
658
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
659
|
-
const marker = join(tmpdir(), `roj-svc-eaddr-${Date.now()}-${Math.floor(Math.random() * 1e6)}`);
|
|
660
|
-
// First spawn fails with an EADDRINUSE-style message; the marker makes the
|
|
661
|
-
// retry (a fresh process) succeed and match the ready pattern.
|
|
662
|
-
const config = {
|
|
663
|
-
type: 'flaky-port',
|
|
664
|
-
description: 'EADDRINUSE on first attempt, ready on retry',
|
|
665
|
-
command: `if [ -f ${marker} ]; then echo "listening READY"; sleep 30; else touch ${marker}; echo "error: listen EADDRINUSE: address already in use" 1>&2; exit 1; fi`,
|
|
666
|
-
readyPattern: 'READY',
|
|
667
|
-
startupTimeoutMs: 5000,
|
|
668
|
-
};
|
|
669
|
-
const observed = [];
|
|
670
|
-
executor.onStatusChanged = (_sessionId, _serviceType, status, details) => {
|
|
671
|
-
observed.push({ status, port: details.port });
|
|
672
|
-
};
|
|
673
|
-
try {
|
|
674
|
-
const result = await executor.start(config, SessionId('s-flaky'));
|
|
675
|
-
expect(result.ok).toBe(true);
|
|
676
|
-
await waitUntil(() => executor.getStatus('flaky-port') === 'ready');
|
|
677
|
-
expect(executor.getStatus('flaky-port')).toBe('ready');
|
|
678
|
-
// Two 'starting' events: the conflicted port, then a fresh, different one.
|
|
679
|
-
const startingPorts = observed.filter((e) => e.status === 'starting').map((e) => e.port);
|
|
680
|
-
expect(startingPorts.length).toBe(2);
|
|
681
|
-
expect(startingPorts[0]).not.toBe(startingPorts[1]);
|
|
682
|
-
// The transient EADDRINUSE must NOT surface as a terminal failure.
|
|
683
|
-
expect(observed.some((e) => e.status === 'failed')).toBe(false);
|
|
684
|
-
}
|
|
685
|
-
finally {
|
|
686
|
-
await executor.shutdown();
|
|
687
|
-
await rm(marker, { force: true });
|
|
688
|
-
}
|
|
689
|
-
});
|
|
690
|
-
});
|
|
691
|
-
// =========================================================================
|
|
692
|
-
// restartPolicy — reviving a service that exited on its own
|
|
693
|
-
// =========================================================================
|
|
694
|
-
describe('restartPolicy', () => {
|
|
695
|
-
const waitUntil = async (predicate, timeoutMs = 8000) => {
|
|
696
|
-
const deadline = Date.now() + timeoutMs;
|
|
697
|
-
while (Date.now() < deadline) {
|
|
698
|
-
if (predicate())
|
|
699
|
-
return;
|
|
700
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
701
|
-
}
|
|
702
|
-
};
|
|
703
|
-
const waitUntilAsync = async (predicate, timeoutMs = 8000) => {
|
|
704
|
-
const deadline = Date.now() + timeoutMs;
|
|
705
|
-
while (Date.now() < deadline) {
|
|
706
|
-
if (await predicate())
|
|
707
|
-
return;
|
|
708
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
709
|
-
}
|
|
710
|
-
};
|
|
711
|
-
const marker = (name) => join(tmpdir(), `roj-restart-${name}-${Date.now()}-${Math.floor(Math.random() * 1e6)}`);
|
|
712
|
-
/** Records every spawn, then crashes or stays up depending on the run count. */
|
|
713
|
-
const crashCommand = (path, crashRuns) => `echo x >> ${path}; runs=$(wc -l < ${path} | tr -d ' '); if [ "$runs" -le ${crashRuns} ]; then exit 1; fi; echo "listening READY"; sleep 30`;
|
|
714
|
-
const spawnCount = async (path) => {
|
|
715
|
-
try {
|
|
716
|
-
return (await readFile(path, 'utf-8')).split('\n').filter((l) => l.length > 0).length;
|
|
717
|
-
}
|
|
718
|
-
catch {
|
|
719
|
-
return 0;
|
|
720
|
-
}
|
|
721
|
-
};
|
|
722
|
-
it('revives a crashed service on the port it already holds', async () => {
|
|
723
|
-
const platform = createNodePlatform();
|
|
724
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
725
|
-
const path = marker('revive');
|
|
726
|
-
const config = {
|
|
727
|
-
type: 'revive-svc',
|
|
728
|
-
description: 'crashes once, then stays up',
|
|
729
|
-
command: crashCommand(path, 1),
|
|
730
|
-
readyPattern: 'READY',
|
|
731
|
-
startupTimeoutMs: 5000,
|
|
732
|
-
restartPolicy: { maxRetries: 3, initialDelayMs: 20 },
|
|
733
|
-
};
|
|
734
|
-
const ports = [];
|
|
735
|
-
executor.onStatusChanged = (_s, _t, status, details) => {
|
|
736
|
-
if (status === 'starting' && details.port !== undefined)
|
|
737
|
-
ports.push(details.port);
|
|
738
|
-
};
|
|
739
|
-
try {
|
|
740
|
-
await executor.start(config, SessionId('s-revive'));
|
|
741
|
-
await waitUntil(() => executor.getStatus('revive-svc') === 'ready');
|
|
742
|
-
expect(executor.getStatus('revive-svc')).toBe('ready');
|
|
743
|
-
expect(await spawnCount(path)).toBe(2);
|
|
744
|
-
// The preview URL must survive the bounce.
|
|
745
|
-
expect(new Set(ports).size).toBe(1);
|
|
746
|
-
}
|
|
747
|
-
finally {
|
|
748
|
-
await executor.shutdown();
|
|
749
|
-
await rm(path, { force: true });
|
|
750
|
-
}
|
|
751
|
-
});
|
|
752
|
-
it('leaves the service failed once the retry budget is spent', async () => {
|
|
753
|
-
const platform = createNodePlatform();
|
|
754
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
755
|
-
const path = marker('budget');
|
|
756
|
-
const config = {
|
|
757
|
-
type: 'budget-svc',
|
|
758
|
-
description: 'always crashes',
|
|
759
|
-
command: crashCommand(path, 99),
|
|
760
|
-
readyPattern: 'READY',
|
|
761
|
-
startupTimeoutMs: 5000,
|
|
762
|
-
restartPolicy: { maxRetries: 2, initialDelayMs: 20 },
|
|
763
|
-
};
|
|
764
|
-
try {
|
|
765
|
-
await executor.start(config, SessionId('s-budget'));
|
|
766
|
-
// One initial spawn plus two retries, then it stays down.
|
|
767
|
-
await waitUntilAsync(async () => (await spawnCount(path)) >= 3 && executor.getStatus('budget-svc') === 'failed');
|
|
768
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
769
|
-
expect(await spawnCount(path)).toBe(3);
|
|
770
|
-
expect(executor.getStatus('budget-svc')).toBe('failed');
|
|
771
|
-
}
|
|
772
|
-
finally {
|
|
773
|
-
await executor.shutdown();
|
|
774
|
-
await rm(path, { force: true });
|
|
775
|
-
}
|
|
776
|
-
});
|
|
777
|
-
it('without a policy a crash stays a crash', async () => {
|
|
778
|
-
const platform = createNodePlatform();
|
|
779
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
780
|
-
const path = marker('nopolicy');
|
|
781
|
-
const config = {
|
|
782
|
-
type: 'nopolicy-svc',
|
|
783
|
-
description: 'always crashes, no restartPolicy',
|
|
784
|
-
command: crashCommand(path, 99),
|
|
785
|
-
readyPattern: 'READY',
|
|
786
|
-
startupTimeoutMs: 5000,
|
|
787
|
-
};
|
|
788
|
-
try {
|
|
789
|
-
await executor.start(config, SessionId('s-nopolicy'));
|
|
790
|
-
await waitUntil(() => executor.getStatus('nopolicy-svc') === 'failed');
|
|
791
|
-
await new Promise((r) => setTimeout(r, 300));
|
|
792
|
-
expect(await spawnCount(path)).toBe(1);
|
|
793
|
-
}
|
|
794
|
-
finally {
|
|
795
|
-
await executor.shutdown();
|
|
796
|
-
await rm(path, { force: true });
|
|
797
|
-
}
|
|
798
|
-
});
|
|
799
|
-
it('a queued revival rides along on the failed status change', async () => {
|
|
800
|
-
const platform = createNodePlatform();
|
|
801
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
802
|
-
const path = marker('event');
|
|
803
|
-
const config = {
|
|
804
|
-
type: 'event-svc',
|
|
805
|
-
description: 'crashes once, then stays up',
|
|
806
|
-
command: crashCommand(path, 1),
|
|
807
|
-
readyPattern: 'READY',
|
|
808
|
-
startupTimeoutMs: 5000,
|
|
809
|
-
restartPolicy: { maxRetries: 3, initialDelayMs: 20 },
|
|
810
|
-
};
|
|
811
|
-
const changes = [];
|
|
812
|
-
executor.onStatusChanged = (_s, _t, status, details) => {
|
|
813
|
-
changes.push({ status, details });
|
|
814
|
-
};
|
|
815
|
-
try {
|
|
816
|
-
await executor.start(config, SessionId('s-event'));
|
|
817
|
-
await waitUntil(() => executor.getStatus('event-svc') === 'ready');
|
|
818
|
-
const failedIndex = changes.findIndex((c) => c.status === 'failed');
|
|
819
|
-
expect(failedIndex).toBeGreaterThanOrEqual(0);
|
|
820
|
-
const failed = changes[failedIndex];
|
|
821
|
-
expect(failed.details.restartAttempt).toBe(1);
|
|
822
|
-
expect(failed.details.restartMaxRetries).toBe(3);
|
|
823
|
-
expect(failed.details.restartAt).toBeGreaterThan(0);
|
|
824
|
-
// The revival's own start must not carry the intent it just honoured.
|
|
825
|
-
const revivalStart = changes.slice(failedIndex + 1).find((c) => c.status === 'starting');
|
|
826
|
-
expect(revivalStart).toBeDefined();
|
|
827
|
-
expect(revivalStart.details.restartAt).toBeUndefined();
|
|
828
|
-
}
|
|
829
|
-
finally {
|
|
830
|
-
await executor.shutdown();
|
|
831
|
-
await rm(path, { force: true });
|
|
832
|
-
}
|
|
833
|
-
});
|
|
834
|
-
it('the failure that spends the budget carries no revival', async () => {
|
|
835
|
-
const platform = createNodePlatform();
|
|
836
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
837
|
-
const path = marker('terminal');
|
|
838
|
-
const config = {
|
|
839
|
-
type: 'terminal-svc',
|
|
840
|
-
description: 'always crashes',
|
|
841
|
-
command: crashCommand(path, 99),
|
|
842
|
-
readyPattern: 'READY',
|
|
843
|
-
startupTimeoutMs: 5000,
|
|
844
|
-
restartPolicy: { maxRetries: 1, initialDelayMs: 20 },
|
|
845
|
-
};
|
|
846
|
-
const failures = [];
|
|
847
|
-
executor.onStatusChanged = (_s, _t, status, details) => {
|
|
848
|
-
if (status === 'failed')
|
|
849
|
-
failures.push(details);
|
|
850
|
-
};
|
|
851
|
-
try {
|
|
852
|
-
await executor.start(config, SessionId('s-terminal'));
|
|
853
|
-
await waitUntilAsync(async () => (await spawnCount(path)) >= 2 && failures.length >= 2);
|
|
854
|
-
expect(failures[0]?.restartAttempt).toBe(1);
|
|
855
|
-
expect(failures[1]?.restartAt).toBeUndefined();
|
|
856
|
-
expect(failures[1]?.restartAttempt).toBeUndefined();
|
|
857
|
-
}
|
|
858
|
-
finally {
|
|
859
|
-
await executor.shutdown();
|
|
860
|
-
await rm(path, { force: true });
|
|
861
|
-
}
|
|
862
|
-
});
|
|
863
|
-
it('session state shows the queued revival and drops it once called off', async () => {
|
|
864
|
-
const portPool = new PortPool();
|
|
865
|
-
const config = {
|
|
866
|
-
type: 'reviving',
|
|
867
|
-
description: 'crashes early, revival queued behind a long delay',
|
|
868
|
-
// The sleep keeps the exit from beating the executor's close listener.
|
|
869
|
-
command: 'sleep 0.2; exit 1',
|
|
870
|
-
restartPolicy: { maxRetries: 3, initialDelayMs: 3000 },
|
|
871
|
-
};
|
|
872
|
-
const harness = createServicesHarness({
|
|
873
|
-
presets: [createServicesPreset([config], ['reviving'], portPool)],
|
|
874
|
-
});
|
|
875
|
-
const session = await harness.createSession('test');
|
|
876
|
-
await session.callPluginMethod('services.start', { serviceType: 'reviving' });
|
|
877
|
-
await waitForServiceStateStatus(session, 'reviving', 'failed');
|
|
878
|
-
const entry = selectPluginState(session.state, 'services')?.get('reviving');
|
|
879
|
-
expect(entry?.status).toBe('failed');
|
|
880
|
-
expect(entry?.restartAt).toBeGreaterThan(Date.now());
|
|
881
|
-
expect(entry?.restartAttempt).toBe(1);
|
|
882
|
-
expect(entry?.restartMaxRetries).toBe(3);
|
|
883
|
-
const stopped = await session.callPluginMethod('services.stop', { serviceType: 'reviving' });
|
|
884
|
-
expect(stopped.ok).toBe(true);
|
|
885
|
-
await waitForServiceStateStatus(session, 'reviving', 'stopped');
|
|
886
|
-
const after = selectPluginState(session.state, 'services')?.get('reviving');
|
|
887
|
-
expect(after?.status).toBe('stopped');
|
|
888
|
-
expect(after?.restartAt).toBeUndefined();
|
|
889
|
-
expect(after?.restartAttempt).toBeUndefined();
|
|
890
|
-
});
|
|
891
|
-
it('closing the session calls off a queued revival', async () => {
|
|
892
|
-
const portPool = new PortPool();
|
|
893
|
-
const path = marker('close');
|
|
894
|
-
const config = {
|
|
895
|
-
type: 'close-svc',
|
|
896
|
-
description: 'crashes early, revival queued behind a delay',
|
|
897
|
-
// The sleep keeps the exit from beating the executor's close listener.
|
|
898
|
-
command: `echo x >> ${path}; sleep 0.2; exit 1`,
|
|
899
|
-
restartPolicy: { maxRetries: 3, initialDelayMs: 800 },
|
|
900
|
-
};
|
|
901
|
-
const harness = createServicesHarness({
|
|
902
|
-
presets: [createServicesPreset([config], ['close-svc'], portPool)],
|
|
903
|
-
});
|
|
904
|
-
const session = await harness.createSession('test');
|
|
905
|
-
try {
|
|
906
|
-
await session.callPluginMethod('services.start', { serviceType: 'close-svc' });
|
|
907
|
-
await waitForServiceStateStatus(session, 'close-svc', 'failed');
|
|
908
|
-
expect(await spawnCount(path)).toBe(1);
|
|
909
|
-
await session.close();
|
|
910
|
-
// Long enough for the revival to have fired had nothing called it off.
|
|
911
|
-
await new Promise((r) => setTimeout(r, 1500));
|
|
912
|
-
expect(await spawnCount(path)).toBe(1);
|
|
913
|
-
}
|
|
914
|
-
finally {
|
|
915
|
-
await rm(path, { force: true });
|
|
916
|
-
}
|
|
917
|
-
});
|
|
918
|
-
it('an explicit stop calls off a queued revival', async () => {
|
|
919
|
-
const platform = createNodePlatform();
|
|
920
|
-
const executor = new ServiceExecutor(silentLogger, new PortPool(), { fs: platform.fs, process: platform.process });
|
|
921
|
-
const path = marker('stop');
|
|
922
|
-
const config = {
|
|
923
|
-
type: 'stop-svc',
|
|
924
|
-
description: 'always crashes, revival queued behind a long delay',
|
|
925
|
-
command: crashCommand(path, 99),
|
|
926
|
-
readyPattern: 'READY',
|
|
927
|
-
startupTimeoutMs: 5000,
|
|
928
|
-
restartPolicy: { maxRetries: 3, initialDelayMs: 1500 },
|
|
929
|
-
};
|
|
930
|
-
try {
|
|
931
|
-
await executor.start(config, SessionId('s-stop'));
|
|
932
|
-
await waitUntil(() => executor.getStatus('stop-svc') === 'failed');
|
|
933
|
-
const stopped = await executor.stop('stop-svc', SessionId('s-stop'));
|
|
934
|
-
expect(stopped.ok).toBe(true);
|
|
935
|
-
expect(executor.getStatus('stop-svc')).toBe('stopped');
|
|
936
|
-
await new Promise((r) => setTimeout(r, 2000));
|
|
937
|
-
expect(await spawnCount(path)).toBe(1);
|
|
938
|
-
}
|
|
939
|
-
finally {
|
|
940
|
-
await executor.shutdown();
|
|
941
|
-
await rm(path, { force: true });
|
|
942
|
-
}
|
|
943
|
-
});
|
|
944
|
-
});
|
|
945
|
-
// =========================================================================
|
|
946
|
-
// agentVisible: false — infrastructure services hidden from agents
|
|
947
|
-
// =========================================================================
|
|
948
|
-
describe('agentVisible: false services', () => {
|
|
949
|
-
const hiddenService = {
|
|
950
|
-
type: 'hidden-svc',
|
|
951
|
-
description: 'Infra service driven by the platform, not agents',
|
|
952
|
-
command: 'sleep 60',
|
|
953
|
-
agentVisible: false,
|
|
954
|
-
};
|
|
955
|
-
it('auto-wired agent visibility excludes it: no tool mention, no status line, still method-controllable', async () => {
|
|
956
|
-
const portPool = new PortPool();
|
|
957
|
-
const base = createTestPreset({
|
|
958
|
-
plugins: [servicePlugin.configure({ services: [quickService, hiddenService], portPool })],
|
|
959
|
-
});
|
|
960
|
-
// Services attached on the agent definition (defineAgent-style auto-wiring),
|
|
961
|
-
// NOT via explicit configureAgent — exercises the getAgentConfig filter.
|
|
962
|
-
const preset = { ...base, orchestrator: { ...base.orchestrator, services: [quickService, hiddenService] } };
|
|
963
|
-
const harness = createServicesHarness({
|
|
964
|
-
presets: [preset],
|
|
965
|
-
llmProvider: MockLLMProvider.withFixedResponse({ content: 'Ok', toolCalls: [] }),
|
|
966
|
-
});
|
|
967
|
-
const session = await harness.createSession('test');
|
|
968
|
-
await session.sendAndWaitForIdle('Hi');
|
|
969
|
-
// Service tools exist (quick is visible) but never mention the hidden service
|
|
970
|
-
const lastRequest = harness.llmProvider.getLastRequest();
|
|
971
|
-
const serviceStart = lastRequest?.tools?.find((t) => t.name === 'service_start');
|
|
972
|
-
expect(serviceStart).toBeDefined();
|
|
973
|
-
expect(serviceStart?.description).toContain('quick');
|
|
974
|
-
expect(serviceStart?.description).not.toContain('hidden-svc');
|
|
975
|
-
// The session-context status block skips it too
|
|
976
|
-
const serialized = JSON.stringify(lastRequest?.messages ?? []);
|
|
977
|
-
expect(serialized).not.toContain('hidden-svc');
|
|
978
|
-
// Still fully controllable at the session level via services.* methods
|
|
979
|
-
const entryAgentId = session.getEntryAgentId();
|
|
980
|
-
const startResult = await session.callPluginMethod('services.start', {
|
|
981
|
-
sessionId: String(session.sessionId),
|
|
982
|
-
agentId: String(entryAgentId),
|
|
983
|
-
serviceType: 'hidden-svc',
|
|
984
|
-
});
|
|
985
|
-
expect(startResult).toMatchObject({ ok: true });
|
|
986
|
-
await waitForServiceStatus(session, 'hidden-svc', 'ready');
|
|
987
|
-
const statusResult = await session.callPluginMethod('services.status', {
|
|
988
|
-
sessionId: String(session.sessionId),
|
|
989
|
-
agentId: String(entryAgentId),
|
|
990
|
-
serviceType: 'hidden-svc',
|
|
991
|
-
});
|
|
992
|
-
expect(statusResult).toMatchObject({ ok: true, value: { status: 'ready' } });
|
|
993
|
-
});
|
|
994
|
-
});
|
|
995
|
-
// =========================================================================
|
|
996
|
-
// Real host paths must not leak into agent-facing surfaces
|
|
997
|
-
// =========================================================================
|
|
998
|
-
describe('host path hygiene', () => {
|
|
999
|
-
it('status block omits cwd even when the entry tracks one', () => {
|
|
1000
|
-
const message = buildServiceStatusMessage([{
|
|
1001
|
-
serviceType: 'quick',
|
|
1002
|
-
status: 'ready',
|
|
1003
|
-
port: 4321,
|
|
1004
|
-
cwd: '/home/user/sessions/0000-real-host-path/packages/web',
|
|
1005
|
-
}], [quickService]);
|
|
1006
|
-
expect(message).toContain('quick');
|
|
1007
|
-
expect(message).toContain('port 4321');
|
|
1008
|
-
expect(message).not.toContain('real-host-path');
|
|
1009
|
-
expect(message).not.toContain('cwd');
|
|
1010
|
-
});
|
|
1011
|
-
it('service_status tool output strips cwd', async () => {
|
|
1012
|
-
const portPool = new PortPool();
|
|
1013
|
-
// Absolute cwd so the tracked entry actually carries a host path to leak.
|
|
1014
|
-
const cwdService = {
|
|
1015
|
-
type: 'cwd-svc',
|
|
1016
|
-
description: 'Service with a resolved host cwd',
|
|
1017
|
-
command: 'sleep 60',
|
|
1018
|
-
cwd: tmpdir(),
|
|
1019
|
-
};
|
|
1020
|
-
const harness = createServicesHarness({
|
|
1021
|
-
presets: [createServicesPreset([cwdService], ['cwd-svc'], portPool)],
|
|
1022
|
-
llmProvider: MockLLMProvider.withSequence([
|
|
1023
|
-
{
|
|
1024
|
-
toolCalls: [{
|
|
1025
|
-
id: ToolCallId('tc-start'),
|
|
1026
|
-
name: 'service_start',
|
|
1027
|
-
input: { serviceType: 'cwd-svc' },
|
|
1028
|
-
}],
|
|
1029
|
-
},
|
|
1030
|
-
{
|
|
1031
|
-
toolCalls: [{
|
|
1032
|
-
id: ToolCallId('tc-status'),
|
|
1033
|
-
name: 'service_status',
|
|
1034
|
-
input: { serviceType: 'cwd-svc' },
|
|
1035
|
-
}],
|
|
1036
|
-
},
|
|
1037
|
-
{ content: 'Done', toolCalls: [] },
|
|
1038
|
-
]),
|
|
1039
|
-
});
|
|
1040
|
-
const session = await harness.createSession('test');
|
|
1041
|
-
await session.sendAndWaitForIdle('Check the service');
|
|
1042
|
-
await waitForServiceStatus(session, 'cwd-svc', 'ready');
|
|
1043
|
-
// The service_status tool result (fed back as a message) must not carry cwd,
|
|
1044
|
-
// while the session-level method keeps returning it for platform callers.
|
|
1045
|
-
const serialized = JSON.stringify(harness.llmProvider.getLastRequest()?.messages ?? []);
|
|
1046
|
-
expect(serialized).not.toContain('"cwd"');
|
|
1047
|
-
const entryAgentId = session.getEntryAgentId();
|
|
1048
|
-
const statusResult = await session.callPluginMethod('services.status', {
|
|
1049
|
-
sessionId: String(session.sessionId),
|
|
1050
|
-
agentId: String(entryAgentId),
|
|
1051
|
-
serviceType: 'cwd-svc',
|
|
1052
|
-
});
|
|
1053
|
-
expect(statusResult).toMatchObject({ ok: true, value: { cwd: expect.any(String) } });
|
|
1054
|
-
});
|
|
1055
|
-
});
|
|
1056
|
-
});
|
|
1057
|
-
//# sourceMappingURL=services.integration.test.js.map
|