@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
package/src/core/events/file.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { dirname, join } from 'node:path'
|
|
2
2
|
import z from 'zod/v4'
|
|
3
3
|
import type { DomainEvent } from '~/core/events/types.js'
|
|
4
|
-
import type
|
|
5
|
-
import {
|
|
4
|
+
import { silentLogger, type Logger } from '~/lib/logger/logger.js'
|
|
5
|
+
import type { Dirent, FileSystem } from '~/platform/fs.js'
|
|
6
|
+
import { domainEventSchema, isValidSessionId, SessionId, sessionMetadataSchema } from '~/core/sessions/schema.js'
|
|
6
7
|
import type { SessionMetadata } from '~/core/sessions/schema.js'
|
|
7
8
|
import { BaseEventStore } from './base-event-store.js'
|
|
8
9
|
import type { LoadRangeOptions, LoadRangeResult } from './event-store.js'
|
|
@@ -99,6 +100,40 @@ async function readLastLines(fs: FileSystem, filePath: string, lineCount: number
|
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
/** Identity of the meta.json bytes a cached verdict was taken from. */
|
|
104
|
+
interface MetadataSource {
|
|
105
|
+
mtimeMs: number
|
|
106
|
+
size: number
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** A parsed record, or the verdict that the bytes it was read from do not parse. */
|
|
110
|
+
type MetadataCacheEntry =
|
|
111
|
+
| { kind: 'record'; record: SessionMetadata }
|
|
112
|
+
| { kind: 'invalid'; source: MetadataSource }
|
|
113
|
+
|
|
114
|
+
function isSameSource(a: MetadataSource, b: MetadataSource): boolean {
|
|
115
|
+
return a.mtimeMs === b.mtimeMs && a.size === b.size
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function errorCode(error: unknown): string | undefined {
|
|
119
|
+
return error instanceof Error && 'code' in error && typeof error.code === 'string' ? error.code : undefined
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function isNotFound(error: unknown): boolean {
|
|
123
|
+
return errorCode(error) === 'ENOENT'
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Before the cache every read parsed fresh JSON — keep that, so a mutating caller cannot corrupt it. */
|
|
127
|
+
function copyMetadata(metadata: SessionMetadata | null): SessionMetadata | null {
|
|
128
|
+
if (!metadata) return null
|
|
129
|
+
|
|
130
|
+
const copy: SessionMetadata = { ...metadata }
|
|
131
|
+
if (metadata.metrics) copy.metrics = { ...metadata.metrics }
|
|
132
|
+
if (metadata.tags) copy.tags = [...metadata.tags]
|
|
133
|
+
if (metadata.custom) copy.custom = { ...metadata.custom }
|
|
134
|
+
return copy
|
|
135
|
+
}
|
|
136
|
+
|
|
102
137
|
/**
|
|
103
138
|
* FileEventStore - Persists domain events to JSONL files.
|
|
104
139
|
*
|
|
@@ -121,7 +156,28 @@ async function readLastLines(fs: FileSystem, filePath: string, lineCount: number
|
|
|
121
156
|
export class FileEventStore extends BaseEventStore {
|
|
122
157
|
private readonly sessionLocks = new Map<SessionId, AsyncMutex>()
|
|
123
158
|
|
|
124
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Parsed meta.json per session, so a `/status` poll costs one readdir instead of
|
|
161
|
+
* one readFile per session directory that ever existed. An `invalid` entry records
|
|
162
|
+
* bytes that exist but do not parse, so a corrupt record is reported once rather
|
|
163
|
+
* than once per poll, and is re-read as soon as those bytes change.
|
|
164
|
+
*
|
|
165
|
+
* Coherence rule: writes win. writeMetadata is the only writer, and a read stores
|
|
166
|
+
* its result only if the entry did not move while the read was in flight — a read
|
|
167
|
+
* is a snapshot of older bytes, so it must never overwrite a newer write. A full
|
|
168
|
+
* listing prunes the map to the readdir set, which keeps deletion and out-of-band
|
|
169
|
+
* creation self-healing.
|
|
170
|
+
*/
|
|
171
|
+
private readonly metadataCache = new Map<SessionId, MetadataCacheEntry>()
|
|
172
|
+
|
|
173
|
+
/** Last reported read failure per session, so a permanent EACCES is not logged on every poll. */
|
|
174
|
+
private readonly reportedReadFailures = new Map<SessionId, string>()
|
|
175
|
+
|
|
176
|
+
constructor(
|
|
177
|
+
private readonly basePath: string,
|
|
178
|
+
private readonly fs: FileSystem,
|
|
179
|
+
private readonly logger: Logger = silentLogger,
|
|
180
|
+
) {
|
|
125
181
|
super()
|
|
126
182
|
}
|
|
127
183
|
|
|
@@ -242,11 +298,12 @@ export class FileEventStore extends BaseEventStore {
|
|
|
242
298
|
|
|
243
299
|
try {
|
|
244
300
|
const entries = await this.fs.readdir(sessionsDir, { withFileTypes: true })
|
|
301
|
+
// A directory whose name is not a valid id is not a session — the metadata listing drops it too.
|
|
245
302
|
return entries
|
|
246
|
-
.filter((entry) => entry.isDirectory())
|
|
247
|
-
.map((entry) => entry.name
|
|
303
|
+
.filter((entry) => entry.isDirectory() && isValidSessionId(entry.name))
|
|
304
|
+
.map((entry) => SessionId(entry.name))
|
|
248
305
|
} catch (error) {
|
|
249
|
-
if ((error
|
|
306
|
+
if (isNotFound(error)) {
|
|
250
307
|
return []
|
|
251
308
|
}
|
|
252
309
|
throw error
|
|
@@ -326,47 +383,166 @@ export class FileEventStore extends BaseEventStore {
|
|
|
326
383
|
// =========================================================================
|
|
327
384
|
|
|
328
385
|
protected async readMetadata(sessionId: SessionId): Promise<SessionMetadata | null> {
|
|
386
|
+
const cached = this.metadataCache.get(sessionId)
|
|
387
|
+
if (cached?.kind === 'record') return copyMetadata(cached.record)
|
|
388
|
+
|
|
329
389
|
const path = this.getMetaPath(sessionId)
|
|
330
390
|
|
|
331
391
|
try {
|
|
392
|
+
// Stat before the read, so a verdict is never keyed to bytes newer than the ones it judged.
|
|
393
|
+
const source = await this.readMetadataSource(path)
|
|
394
|
+
// A rejected record stays rejected only for the bytes that were rejected, so a repair is picked up.
|
|
395
|
+
if (cached && isSameSource(cached.source, source)) return null
|
|
396
|
+
|
|
332
397
|
const content = await this.fs.readFile(path, 'utf-8')
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
398
|
+
const record = this.parseMetadata(sessionId, content)
|
|
399
|
+
this.reportedReadFailures.delete(sessionId)
|
|
400
|
+
|
|
401
|
+
return copyMetadata(
|
|
402
|
+
this.commitRead(sessionId, cached, record ? { kind: 'record', record } : { kind: 'invalid', source }),
|
|
403
|
+
)
|
|
336
404
|
} catch (error) {
|
|
337
|
-
if ((error
|
|
405
|
+
if (isNotFound(error)) {
|
|
406
|
+
// A missing file is never cached — unknown ids must not be able to grow the map.
|
|
338
407
|
return null
|
|
339
408
|
}
|
|
409
|
+
this.reportReadFailure(sessionId, error)
|
|
340
410
|
throw error
|
|
341
411
|
}
|
|
342
412
|
}
|
|
343
413
|
|
|
414
|
+
/**
|
|
415
|
+
* Cache what the read found, unless a write landed while it was in flight.
|
|
416
|
+
*
|
|
417
|
+
* A read only ever sees the bytes it started from, so the concurrent writer holds the
|
|
418
|
+
* newer record and the reader reports that one instead of overwriting it with its own.
|
|
419
|
+
*/
|
|
420
|
+
private commitRead(
|
|
421
|
+
sessionId: SessionId,
|
|
422
|
+
before: MetadataCacheEntry | undefined,
|
|
423
|
+
entry: MetadataCacheEntry,
|
|
424
|
+
): SessionMetadata | null {
|
|
425
|
+
const current = this.metadataCache.get(sessionId)
|
|
426
|
+
if (current !== before) return current?.kind === 'record' ? current.record : null
|
|
427
|
+
|
|
428
|
+
this.metadataCache.set(sessionId, entry)
|
|
429
|
+
return entry.kind === 'record' ? entry.record : null
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
private async readMetadataSource(path: string): Promise<MetadataSource> {
|
|
433
|
+
const stats = await this.fs.stat(path)
|
|
434
|
+
return { mtimeMs: stats.mtimeMs, size: stats.size }
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** Reports a read that failed for anything but a missing file, once per failure kind. */
|
|
438
|
+
private reportReadFailure(sessionId: SessionId, error: unknown): void {
|
|
439
|
+
const code = errorCode(error) ?? 'unknown'
|
|
440
|
+
if (this.reportedReadFailures.get(sessionId) === code) return
|
|
441
|
+
|
|
442
|
+
this.reportedReadFailures.set(sessionId, code)
|
|
443
|
+
this.logger.error(
|
|
444
|
+
'Failed to read session metadata',
|
|
445
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
446
|
+
{ sessionId },
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Strict on write, tolerant on read.
|
|
452
|
+
*
|
|
453
|
+
* meta.json is written non-atomically and its schema tightened over time, so a
|
|
454
|
+
* single truncated or legacy record must not take the whole listing down with it.
|
|
455
|
+
*/
|
|
456
|
+
private parseMetadata(sessionId: SessionId, content: string): SessionMetadata | null {
|
|
457
|
+
let raw: unknown
|
|
458
|
+
try {
|
|
459
|
+
raw = JSON.parse(content)
|
|
460
|
+
} catch (error) {
|
|
461
|
+
this.logger.warn('Skipping unreadable session metadata', { sessionId, reason: String(error) })
|
|
462
|
+
return null
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const parsed = sessionMetadataSchema.safeParse(raw)
|
|
466
|
+
if (!parsed.success) {
|
|
467
|
+
this.logger.warn('Skipping invalid session metadata', { sessionId, reason: parsed.error.message })
|
|
468
|
+
return null
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return parsed.data
|
|
472
|
+
}
|
|
473
|
+
|
|
344
474
|
protected async writeMetadata(sessionId: SessionId, metadata: SessionMetadata): Promise<void> {
|
|
345
475
|
const path = this.getMetaPath(sessionId)
|
|
346
476
|
await this.fs.mkdir(dirname(path), { recursive: true })
|
|
347
477
|
await this.fs.writeFile(path, JSON.stringify(metadata, null, 2))
|
|
478
|
+
|
|
479
|
+
// The cache may only hold what a read would return, so the record goes in through the same schema.
|
|
480
|
+
const parsed = sessionMetadataSchema.safeParse(metadata)
|
|
481
|
+
if (!parsed.success) {
|
|
482
|
+
this.logger.warn('Not caching invalid session metadata', { sessionId, reason: parsed.error.message })
|
|
483
|
+
this.metadataCache.delete(sessionId)
|
|
484
|
+
return
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Cached only once the write lands, so a failed write leaves no phantom value.
|
|
488
|
+
this.metadataCache.set(sessionId, { kind: 'record', record: parsed.data })
|
|
489
|
+
this.reportedReadFailures.delete(sessionId)
|
|
348
490
|
}
|
|
349
491
|
|
|
350
492
|
protected async getAllSessionMetadata(): Promise<SessionMetadata[]> {
|
|
351
493
|
const sessionsDir = join(this.basePath, 'sessions')
|
|
352
494
|
|
|
495
|
+
let entries: Dirent[]
|
|
353
496
|
try {
|
|
354
|
-
|
|
355
|
-
const sessions: SessionMetadata[] = []
|
|
356
|
-
|
|
357
|
-
for (const entry of entries) {
|
|
358
|
-
if (!entry.isDirectory()) continue
|
|
359
|
-
|
|
360
|
-
const metadata = await this.readMetadata(entry.name as SessionId)
|
|
361
|
-
if (metadata) sessions.push(metadata)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
return sessions
|
|
497
|
+
entries = await this.fs.readdir(sessionsDir, { withFileTypes: true })
|
|
365
498
|
} catch (error) {
|
|
366
|
-
if ((error
|
|
499
|
+
if (isNotFound(error)) {
|
|
500
|
+
// The data root is gone, so every session cached from it is gone with it.
|
|
501
|
+
this.forgetAll()
|
|
367
502
|
return []
|
|
368
503
|
}
|
|
369
504
|
throw error
|
|
370
505
|
}
|
|
506
|
+
|
|
507
|
+
const sessions: SessionMetadata[] = []
|
|
508
|
+
const present = new Set<SessionId>()
|
|
509
|
+
|
|
510
|
+
for (const entry of entries) {
|
|
511
|
+
if (!entry.isDirectory()) continue
|
|
512
|
+
|
|
513
|
+
const sessionId = SessionId(entry.name)
|
|
514
|
+
present.add(sessionId)
|
|
515
|
+
|
|
516
|
+
const metadata = await this.readMetadataOrSkip(sessionId)
|
|
517
|
+
if (metadata) sessions.push(metadata)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// The directory listing is the only thing that can remove a session, so prune here.
|
|
521
|
+
this.forgetMissing(present)
|
|
522
|
+
|
|
523
|
+
return sessions
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/** One unreadable session must not take the listing down for every other one. */
|
|
527
|
+
private async readMetadataOrSkip(sessionId: SessionId): Promise<SessionMetadata | null> {
|
|
528
|
+
try {
|
|
529
|
+
return await this.readMetadata(sessionId)
|
|
530
|
+
} catch {
|
|
531
|
+
return null // already reported by readMetadata
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
private forgetMissing(present: Set<SessionId>): void {
|
|
536
|
+
for (const sessionId of this.metadataCache.keys()) {
|
|
537
|
+
if (!present.has(sessionId)) this.metadataCache.delete(sessionId)
|
|
538
|
+
}
|
|
539
|
+
for (const sessionId of this.reportedReadFailures.keys()) {
|
|
540
|
+
if (!present.has(sessionId)) this.reportedReadFailures.delete(sessionId)
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
private forgetAll(): void {
|
|
545
|
+
this.metadataCache.clear()
|
|
546
|
+
this.reportedReadFailures.clear()
|
|
371
547
|
}
|
|
372
548
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Containment check for paths that are about to be handed to the filesystem.
|
|
3
|
+
*
|
|
4
|
+
* A lexical check (`resolve()` then a prefix compare) only sees the path string,
|
|
5
|
+
* so a link inside a root can still point anywhere the process can reach. Both
|
|
6
|
+
* ends are canonicalized here instead. Links are not banned — one whose target
|
|
7
|
+
* lands back inside a root stays usable.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { basename, dirname, isAbsolute, join, relative, sep } from 'node:path'
|
|
11
|
+
import type { FileSystem } from '~/platform/fs.js'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Where a path's real target sits.
|
|
15
|
+
*
|
|
16
|
+
* `unresolvable` is a path that exists but cannot be canonicalized — a link with
|
|
17
|
+
* no target, a link loop. Only an operation that would create through it has to
|
|
18
|
+
* refuse; the ones that merely follow it fail on their own.
|
|
19
|
+
*/
|
|
20
|
+
export type Containment = 'inside' | 'outside' | 'unresolvable'
|
|
21
|
+
|
|
22
|
+
export async function containmentOf(
|
|
23
|
+
fs: FileSystem,
|
|
24
|
+
roots: readonly string[],
|
|
25
|
+
path: string,
|
|
26
|
+
): Promise<Containment> {
|
|
27
|
+
// A path that is one of its own roots is inside it whatever it resolves to.
|
|
28
|
+
if (roots.includes(path)) return 'inside'
|
|
29
|
+
|
|
30
|
+
const target = await canonicalize(fs, path)
|
|
31
|
+
if (target === null) return 'unresolvable'
|
|
32
|
+
|
|
33
|
+
for (const root of roots) {
|
|
34
|
+
const canonicalRoot = await canonicalize(fs, root)
|
|
35
|
+
if (canonicalRoot !== null && isUnder(canonicalRoot, target)) return 'inside'
|
|
36
|
+
}
|
|
37
|
+
return 'outside'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function isUnder(root: string, target: string): boolean {
|
|
41
|
+
const rel = relative(root, target)
|
|
42
|
+
return rel === '' || (!isAbsolute(rel) && rel !== '..' && !rel.startsWith(`..${sep}`))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Canonical form of `path`, resolving through its deepest existing ancestor so
|
|
47
|
+
* a not-yet-created file is judged by the directory it would land in.
|
|
48
|
+
* Null when a component exists but cannot be resolved.
|
|
49
|
+
*/
|
|
50
|
+
async function canonicalize(fs: FileSystem, path: string): Promise<string | null> {
|
|
51
|
+
const missing: string[] = []
|
|
52
|
+
let current = path
|
|
53
|
+
for (;;) {
|
|
54
|
+
try {
|
|
55
|
+
const real = await fs.realpath(current)
|
|
56
|
+
return missing.length > 0 ? join(real, ...missing) : real
|
|
57
|
+
} catch {
|
|
58
|
+
if (await entryExists(fs, current)) return null
|
|
59
|
+
const parent = dirname(current)
|
|
60
|
+
if (parent === current) return null
|
|
61
|
+
missing.unshift(basename(current))
|
|
62
|
+
current = parent
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Anything `lstat` rejects counts as absent, an unreadable parent included — the caller's own operation then reports it. */
|
|
68
|
+
async function entryExists(fs: FileSystem, path: string): Promise<boolean> {
|
|
69
|
+
try {
|
|
70
|
+
await fs.lstat(path)
|
|
71
|
+
return true
|
|
72
|
+
} catch {
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* validation, agent-visible path mapping). Replaces the separate path-resolver
|
|
6
6
|
* functions for FileStore consumers.
|
|
7
7
|
*
|
|
8
|
+
* Every operation resolves the path lexically and then checks that its real
|
|
9
|
+
* target is still inside the area the store may touch — session and workspace
|
|
10
|
+
* together, or whatever root a `scoped()` sub-store was carved out of. Links
|
|
11
|
+
* are not banned: one whose target lands back inside stays usable.
|
|
12
|
+
*
|
|
8
13
|
* Three scopes:
|
|
9
14
|
* - 'full': accepts agent-visible paths (/home/user/session/... or real paths)
|
|
10
15
|
* - 'session': paths relative to sessionDir
|
|
@@ -12,8 +17,9 @@
|
|
|
12
17
|
*/
|
|
13
18
|
|
|
14
19
|
import { dirname, join, normalize, resolve } from 'node:path'
|
|
20
|
+
import { containmentOf } from '~/core/file-store/containment.js'
|
|
15
21
|
import type { FileEntry, FileStore } from '~/core/file-store/types.js'
|
|
16
|
-
import type { FileSystem } from '~/platform/fs.js'
|
|
22
|
+
import type { FileSystem, WalkEntry } from '~/platform/fs.js'
|
|
17
23
|
import { Err, Ok } from '~/lib/utils/result.js'
|
|
18
24
|
import type { Result } from '~/lib/utils/result.js'
|
|
19
25
|
|
|
@@ -23,6 +29,19 @@ const VIRTUAL_WORKSPACE = '/home/user/workspace'
|
|
|
23
29
|
|
|
24
30
|
type FileStoreScope = 'full' | 'session' | 'workspace'
|
|
25
31
|
|
|
32
|
+
/** A lexically resolved path plus the roots its real target must stay inside. */
|
|
33
|
+
interface ResolvedPath {
|
|
34
|
+
absolute: string
|
|
35
|
+
roots: readonly string[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* What the operation does with the final link, which decides what an
|
|
40
|
+
* unresolvable one means: `follow` leaves it to the operation, `create` refuses
|
|
41
|
+
* it because writing would create the target, `entry` checks the parent instead.
|
|
42
|
+
*/
|
|
43
|
+
type ContainmentMode = 'follow' | 'create' | 'entry'
|
|
44
|
+
|
|
26
45
|
export class SessionFileStore implements FileStore {
|
|
27
46
|
constructor(
|
|
28
47
|
private readonly sessionDir: string,
|
|
@@ -30,25 +49,31 @@ export class SessionFileStore implements FileStore {
|
|
|
30
49
|
private readonly sandboxed: boolean,
|
|
31
50
|
private readonly fs: FileSystem,
|
|
32
51
|
private readonly scope: FileStoreScope = 'full',
|
|
52
|
+
/** Set by `scoped()` so a sub-store cannot escape the roots it was carved out of. */
|
|
53
|
+
private readonly containmentRoots?: readonly string[],
|
|
33
54
|
) {}
|
|
34
55
|
|
|
35
56
|
/** Create a session-scoped FileStore (relative paths → sessionDir) */
|
|
36
57
|
get session(): SessionFileStore {
|
|
37
|
-
return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'session')
|
|
58
|
+
return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'session', this.containmentRoots)
|
|
38
59
|
}
|
|
39
60
|
|
|
40
61
|
/** Create a workspace-scoped FileStore (relative paths → workspaceDir), or undefined if no workspace */
|
|
41
62
|
get workspace(): SessionFileStore | undefined {
|
|
42
63
|
if (!this.workspaceDir) return undefined
|
|
43
|
-
return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'workspace')
|
|
64
|
+
return new SessionFileStore(this.sessionDir, this.workspaceDir, this.sandboxed, this.fs, 'workspace', this.containmentRoots)
|
|
44
65
|
}
|
|
45
66
|
|
|
46
67
|
async write(path: string, content: string | Buffer): Promise<Result<{ path: string }, string>> {
|
|
47
|
-
const resolved = this.
|
|
68
|
+
const resolved = await this.resolveContained(path, 'create')
|
|
48
69
|
if (!resolved.ok) return resolved
|
|
49
70
|
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
try {
|
|
72
|
+
await this.fs.mkdir(dirname(resolved.value), { recursive: true })
|
|
73
|
+
await this.fs.writeFile(resolved.value, content)
|
|
74
|
+
} catch {
|
|
75
|
+
return Err(`Failed to write: ${path}`)
|
|
76
|
+
}
|
|
52
77
|
|
|
53
78
|
return Ok({ path: this.toAgentPath(resolved.value) })
|
|
54
79
|
}
|
|
@@ -56,7 +81,7 @@ export class SessionFileStore implements FileStore {
|
|
|
56
81
|
async read(path: string): Promise<Result<string, string>>
|
|
57
82
|
async read(path: string, opts: { type: 'buffer' }): Promise<Result<Buffer, string>>
|
|
58
83
|
async read(path: string, opts?: { type: 'buffer' }): Promise<Result<string | Buffer, string>> {
|
|
59
|
-
const resolved = this.
|
|
84
|
+
const resolved = await this.resolveContained(path, 'follow')
|
|
60
85
|
if (!resolved.ok) return resolved
|
|
61
86
|
|
|
62
87
|
try {
|
|
@@ -70,21 +95,22 @@ export class SessionFileStore implements FileStore {
|
|
|
70
95
|
}
|
|
71
96
|
|
|
72
97
|
async exists(path: string): Promise<Result<boolean, string>> {
|
|
73
|
-
const resolved = this.
|
|
98
|
+
const resolved = await this.resolveContained(path, 'follow')
|
|
74
99
|
if (!resolved.ok) return resolved
|
|
75
100
|
|
|
76
101
|
return Ok(await this.fs.exists(resolved.value))
|
|
77
102
|
}
|
|
78
103
|
|
|
79
104
|
async stat(path: string): Promise<Result<FileEntry, string>> {
|
|
80
|
-
const resolved = this.
|
|
105
|
+
const resolved = await this.resolveContained(path, 'follow')
|
|
81
106
|
if (!resolved.ok) return resolved
|
|
82
107
|
|
|
83
108
|
try {
|
|
109
|
+
// `stat` follows links on purpose — a link to a file inside the root is a file here.
|
|
84
110
|
const s = await this.fs.stat(resolved.value)
|
|
85
111
|
return Ok({
|
|
86
112
|
size: s.size,
|
|
87
|
-
type: s.isFile() ? 'file' : s.isDirectory() ? 'directory' :
|
|
113
|
+
type: s.isFile() ? 'file' : s.isDirectory() ? 'directory' : 'other',
|
|
88
114
|
name: resolved.value.split('/').pop() || '',
|
|
89
115
|
})
|
|
90
116
|
} catch {
|
|
@@ -96,15 +122,24 @@ export class SessionFileStore implements FileStore {
|
|
|
96
122
|
path: string,
|
|
97
123
|
options?: { maxDepth?: number; gitIgnore?: boolean },
|
|
98
124
|
): Promise<Result<FileEntry[], string>> {
|
|
99
|
-
const resolved = this.
|
|
125
|
+
const resolved = await this.resolveContained(path, 'follow')
|
|
100
126
|
if (!resolved.ok) return resolved
|
|
101
127
|
|
|
102
128
|
const maxDepth = options?.maxDepth ?? 1
|
|
103
129
|
if (maxDepth < 1) return Ok([])
|
|
104
130
|
|
|
105
131
|
try {
|
|
132
|
+
// A readdir plus a stat per file is one question asked in pieces. Where
|
|
133
|
+
// the platform takes it whole, ask it whole.
|
|
134
|
+
if (this.fs.walk) {
|
|
135
|
+
const base = resolved.value
|
|
136
|
+
const found = await this.fs.walk(base, { depth: maxDepth })
|
|
137
|
+
return Ok(found.map((entry) => toFileEntry(entry, base)))
|
|
138
|
+
}
|
|
139
|
+
|
|
106
140
|
const entries: FileEntry[] = []
|
|
107
|
-
|
|
141
|
+
const readAll = (): Promise<void> => this.walkInto(resolved.value, '', maxDepth, entries)
|
|
142
|
+
await (this.fs.scopeReads ? this.fs.scopeReads(readAll) : readAll())
|
|
108
143
|
return Ok(entries)
|
|
109
144
|
} catch {
|
|
110
145
|
return Err(`Directory not found: ${path}`)
|
|
@@ -142,7 +177,7 @@ export class SessionFileStore implements FileStore {
|
|
|
142
177
|
}
|
|
143
178
|
|
|
144
179
|
async remove(path: string): Promise<Result<void, string>> {
|
|
145
|
-
const resolved = this.
|
|
180
|
+
const resolved = await this.resolveContained(path, 'entry')
|
|
146
181
|
if (!resolved.ok) return resolved
|
|
147
182
|
|
|
148
183
|
try {
|
|
@@ -166,24 +201,60 @@ export class SessionFileStore implements FileStore {
|
|
|
166
201
|
}
|
|
167
202
|
}
|
|
168
203
|
|
|
204
|
+
/** Lexical resolution only — despite the name it never follows a symlink. See FileStore.realPath. */
|
|
169
205
|
realPath(path: string): Result<string, string> {
|
|
170
|
-
|
|
206
|
+
const resolved = this.resolveScoped(path)
|
|
207
|
+
return resolved.ok ? Ok(resolved.value.absolute) : resolved
|
|
171
208
|
}
|
|
172
209
|
|
|
210
|
+
/** See FileStore.containedPath. */
|
|
211
|
+
containedPath(path: string): Promise<Result<string, string>> {
|
|
212
|
+
return this.resolveContained(path, 'create')
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Throws on a path it cannot resolve — never hand it unvalidated request data; use `realPath` there. */
|
|
173
216
|
scoped(basePath: string): SessionFileStore {
|
|
174
217
|
// Resolve basePath relative to current scope
|
|
175
|
-
const resolved = this.
|
|
218
|
+
const resolved = this.resolveScoped(basePath)
|
|
176
219
|
if (!resolved.ok) {
|
|
177
220
|
throw new Error(`Cannot scope to invalid path: ${basePath}`)
|
|
178
221
|
}
|
|
179
|
-
return new SessionFileStore(resolved.value, undefined, false, this.fs, 'session')
|
|
222
|
+
return new SessionFileStore(resolved.value.absolute, undefined, false, this.fs, 'session', resolved.value.roots)
|
|
180
223
|
}
|
|
181
224
|
|
|
182
225
|
// ============================================================================
|
|
183
226
|
// Path resolution
|
|
184
227
|
// ============================================================================
|
|
185
228
|
|
|
186
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Lexical resolution, plus a check that the real target has not left the roots.
|
|
231
|
+
* `mode` says what the operation does with the final link — see ContainmentMode.
|
|
232
|
+
*/
|
|
233
|
+
private async resolveContained(path: string, mode: ContainmentMode): Promise<Result<string, string>> {
|
|
234
|
+
const resolved = this.resolveScoped(path)
|
|
235
|
+
if (!resolved.ok) return resolved
|
|
236
|
+
|
|
237
|
+
const { absolute, roots } = resolved.value
|
|
238
|
+
const subject = mode === 'entry' ? dirname(absolute) : absolute
|
|
239
|
+
switch (await containmentOf(this.fs, roots, subject)) {
|
|
240
|
+
case 'outside':
|
|
241
|
+
return Err(`Path '${path}' resolves outside allowed directories`)
|
|
242
|
+
case 'unresolvable':
|
|
243
|
+
return mode === 'create' ? Err(`Path '${path}' cannot be resolved`) : Ok(absolute)
|
|
244
|
+
case 'inside':
|
|
245
|
+
return Ok(absolute)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/** The area this store may touch — both roots where a workspace is configured. */
|
|
250
|
+
private allowedRoots(): readonly string[] {
|
|
251
|
+
if (this.containmentRoots) return this.containmentRoots
|
|
252
|
+
const roots = [resolve(this.sessionDir)]
|
|
253
|
+
if (this.workspaceDir) roots.push(resolve(this.workspaceDir))
|
|
254
|
+
return roots
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private resolveScoped(path: string): Result<ResolvedPath, string> {
|
|
187
258
|
switch (this.scope) {
|
|
188
259
|
case 'full':
|
|
189
260
|
return this.resolveAgentPath(path)
|
|
@@ -196,7 +267,7 @@ export class SessionFileStore implements FileStore {
|
|
|
196
267
|
}
|
|
197
268
|
|
|
198
269
|
/** Resolve a relative path within a root directory */
|
|
199
|
-
private resolveRelativePath(path: string, rootDir: string): Result<
|
|
270
|
+
private resolveRelativePath(path: string, rootDir: string): Result<ResolvedPath, string> {
|
|
200
271
|
const normalized = normalize(path)
|
|
201
272
|
if (normalized.startsWith('..') || normalized.startsWith('/')) {
|
|
202
273
|
return Err(`Path traversal not allowed: ${path}`)
|
|
@@ -205,18 +276,18 @@ export class SessionFileStore implements FileStore {
|
|
|
205
276
|
if (!absolute.startsWith(rootDir)) {
|
|
206
277
|
return Err(`Path traversal not allowed: ${path}`)
|
|
207
278
|
}
|
|
208
|
-
return Ok(absolute)
|
|
279
|
+
return Ok({ absolute, roots: this.allowedRoots() })
|
|
209
280
|
}
|
|
210
281
|
|
|
211
282
|
/** Resolve an agent-visible path to real filesystem path (handles sandboxed virtual paths) */
|
|
212
|
-
private resolveAgentPath(agentPath: string): Result<
|
|
283
|
+
private resolveAgentPath(agentPath: string): Result<ResolvedPath, string> {
|
|
213
284
|
if (this.sandboxed) {
|
|
214
285
|
return this.resolveSandboxedPath(agentPath)
|
|
215
286
|
}
|
|
216
287
|
return this.resolveNonSandboxedPath(agentPath)
|
|
217
288
|
}
|
|
218
289
|
|
|
219
|
-
private resolveSandboxedPath(agentPath: string): Result<
|
|
290
|
+
private resolveSandboxedPath(agentPath: string): Result<ResolvedPath, string> {
|
|
220
291
|
if (agentPath.startsWith(VIRTUAL_SESSION + '/') || agentPath === VIRTUAL_SESSION) {
|
|
221
292
|
const relative = agentPath.slice(VIRTUAL_SESSION.length)
|
|
222
293
|
const absolutePath = resolve(this.sessionDir, relative.slice(1) || '.')
|
|
@@ -239,7 +310,7 @@ export class SessionFileStore implements FileStore {
|
|
|
239
310
|
return Err(`Path must start with ${validPrefixes}. Got: '${agentPath}'`)
|
|
240
311
|
}
|
|
241
312
|
|
|
242
|
-
private resolveNonSandboxedPath(agentPath: string): Result<
|
|
313
|
+
private resolveNonSandboxedPath(agentPath: string): Result<ResolvedPath, string> {
|
|
243
314
|
const absolutePath = resolve(agentPath)
|
|
244
315
|
const normalizedSession = resolve(this.sessionDir)
|
|
245
316
|
const normalizedWorkspace = this.workspaceDir ? resolve(this.workspaceDir) : null
|
|
@@ -252,10 +323,10 @@ export class SessionFileStore implements FileStore {
|
|
|
252
323
|
return Err(`Path '${agentPath}' is outside allowed directories`)
|
|
253
324
|
}
|
|
254
325
|
|
|
255
|
-
return Ok(absolutePath)
|
|
326
|
+
return Ok({ absolute: absolutePath, roots: this.allowedRoots() })
|
|
256
327
|
}
|
|
257
328
|
|
|
258
|
-
private validateWithinRoot(absolutePath: string, rootDir: string, originalPath: string): Result<
|
|
329
|
+
private validateWithinRoot(absolutePath: string, rootDir: string, originalPath: string): Result<ResolvedPath, string> {
|
|
259
330
|
const normalizedRoot = resolve(rootDir)
|
|
260
331
|
const isWithin = absolutePath === normalizedRoot || absolutePath.startsWith(normalizedRoot + '/')
|
|
261
332
|
|
|
@@ -263,7 +334,7 @@ export class SessionFileStore implements FileStore {
|
|
|
263
334
|
return Err(`Path '${originalPath}' resolves outside allowed directories`)
|
|
264
335
|
}
|
|
265
336
|
|
|
266
|
-
return Ok(absolutePath)
|
|
337
|
+
return Ok({ absolute: absolutePath, roots: this.allowedRoots() })
|
|
267
338
|
}
|
|
268
339
|
|
|
269
340
|
// ============================================================================
|
|
@@ -293,3 +364,13 @@ export class SessionFileStore implements FileStore {
|
|
|
293
364
|
return realPath
|
|
294
365
|
}
|
|
295
366
|
}
|
|
367
|
+
|
|
368
|
+
/** A walked entry as the store reports it: name relative to the listed directory. */
|
|
369
|
+
function toFileEntry(entry: WalkEntry, baseDir: string): FileEntry {
|
|
370
|
+
const prefixLength = baseDir.endsWith('/') ? baseDir.length : baseDir.length + 1
|
|
371
|
+
return {
|
|
372
|
+
name: entry.path.slice(prefixLength),
|
|
373
|
+
type: entry.type,
|
|
374
|
+
size: entry.type === 'file' ? entry.size : undefined,
|
|
375
|
+
}
|
|
376
|
+
}
|
|
@@ -39,9 +39,22 @@ export interface FileStore {
|
|
|
39
39
|
/** Remove a file. */
|
|
40
40
|
remove(path: string): Promise<Result<void, string>>
|
|
41
41
|
|
|
42
|
-
/**
|
|
42
|
+
/**
|
|
43
|
+
* Resolve an agent-visible path to a real filesystem path, lexically.
|
|
44
|
+
*
|
|
45
|
+
* Does not follow symlinks, so it cannot decide containment on its own. Use
|
|
46
|
+
* it only where the path is never handed to the filesystem — everything that
|
|
47
|
+
* goes on to read, write or spawn wants `containedPath` instead.
|
|
48
|
+
*/
|
|
43
49
|
realPath(path: string): Result<string, string>
|
|
44
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Resolve to a real filesystem path, refusing one whose real target leaves
|
|
53
|
+
* the store's roots. What a caller that reaches the filesystem itself, rather
|
|
54
|
+
* than through this store, should ask for.
|
|
55
|
+
*/
|
|
56
|
+
containedPath(path: string): Promise<Result<string, string>>
|
|
57
|
+
|
|
45
58
|
/** Get the agent-visible root paths (virtual when sandboxed, real otherwise) */
|
|
46
59
|
getRoots(): { session: string; workspace?: string }
|
|
47
60
|
|
|
@@ -80,7 +80,9 @@ export class DefaultImageProcessor implements ImageProcessor {
|
|
|
80
80
|
return { type: 'text', text: `[Image unavailable: ${path} - unsupported format]` }
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
// Not `realPath`: the URL comes back from conversation history, and what it
|
|
84
|
+
// names may have become a link out of the store since it was first read.
|
|
85
|
+
const resolved = await fileStore.containedPath(path)
|
|
84
86
|
if (!resolved.ok) {
|
|
85
87
|
return { type: 'text', text: `[Image unavailable: ${path} - ${resolved.error}]` }
|
|
86
88
|
}
|