@lleverage-ai/agent-sdk 0.0.1
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/LICENSE +21 -0
- package/README.md +2321 -0
- package/dist/agent.d.ts +52 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +2122 -0
- package/dist/agent.js.map +1 -0
- package/dist/backend.d.ts +378 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +71 -0
- package/dist/backend.js.map +1 -0
- package/dist/backends/composite.d.ts +258 -0
- package/dist/backends/composite.d.ts.map +1 -0
- package/dist/backends/composite.js +437 -0
- package/dist/backends/composite.js.map +1 -0
- package/dist/backends/filesystem.d.ts +268 -0
- package/dist/backends/filesystem.d.ts.map +1 -0
- package/dist/backends/filesystem.js +623 -0
- package/dist/backends/filesystem.js.map +1 -0
- package/dist/backends/index.d.ts +14 -0
- package/dist/backends/index.d.ts.map +1 -0
- package/dist/backends/index.js +14 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/backends/persistent.d.ts +312 -0
- package/dist/backends/persistent.d.ts.map +1 -0
- package/dist/backends/persistent.js +519 -0
- package/dist/backends/persistent.js.map +1 -0
- package/dist/backends/sandbox.d.ts +315 -0
- package/dist/backends/sandbox.d.ts.map +1 -0
- package/dist/backends/sandbox.js +490 -0
- package/dist/backends/sandbox.js.map +1 -0
- package/dist/backends/state.d.ts +225 -0
- package/dist/backends/state.d.ts.map +1 -0
- package/dist/backends/state.js +396 -0
- package/dist/backends/state.js.map +1 -0
- package/dist/checkpointer/file-saver.d.ts +182 -0
- package/dist/checkpointer/file-saver.d.ts.map +1 -0
- package/dist/checkpointer/file-saver.js +298 -0
- package/dist/checkpointer/file-saver.js.map +1 -0
- package/dist/checkpointer/index.d.ts +40 -0
- package/dist/checkpointer/index.d.ts.map +1 -0
- package/dist/checkpointer/index.js +40 -0
- package/dist/checkpointer/index.js.map +1 -0
- package/dist/checkpointer/kv-saver.d.ts +142 -0
- package/dist/checkpointer/kv-saver.d.ts.map +1 -0
- package/dist/checkpointer/kv-saver.js +176 -0
- package/dist/checkpointer/kv-saver.js.map +1 -0
- package/dist/checkpointer/memory-saver.d.ts +158 -0
- package/dist/checkpointer/memory-saver.d.ts.map +1 -0
- package/dist/checkpointer/memory-saver.js +222 -0
- package/dist/checkpointer/memory-saver.js.map +1 -0
- package/dist/checkpointer/types.d.ts +353 -0
- package/dist/checkpointer/types.d.ts.map +1 -0
- package/dist/checkpointer/types.js +159 -0
- package/dist/checkpointer/types.js.map +1 -0
- package/dist/context-manager.d.ts +627 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +1039 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/context.d.ts +57 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +76 -0
- package/dist/context.js.map +1 -0
- package/dist/errors/index.d.ts +611 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +1023 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/generation-helpers.d.ts +126 -0
- package/dist/generation-helpers.d.ts.map +1 -0
- package/dist/generation-helpers.js +181 -0
- package/dist/generation-helpers.js.map +1 -0
- package/dist/hooks/audit.d.ts +210 -0
- package/dist/hooks/audit.d.ts.map +1 -0
- package/dist/hooks/audit.js +305 -0
- package/dist/hooks/audit.js.map +1 -0
- package/dist/hooks/cache.d.ts +180 -0
- package/dist/hooks/cache.d.ts.map +1 -0
- package/dist/hooks/cache.js +273 -0
- package/dist/hooks/cache.js.map +1 -0
- package/dist/hooks/guardrails.d.ts +145 -0
- package/dist/hooks/guardrails.d.ts.map +1 -0
- package/dist/hooks/guardrails.js +326 -0
- package/dist/hooks/guardrails.js.map +1 -0
- package/dist/hooks/index.d.ts +18 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +32 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/logging.d.ts +193 -0
- package/dist/hooks/logging.d.ts.map +1 -0
- package/dist/hooks/logging.js +345 -0
- package/dist/hooks/logging.js.map +1 -0
- package/dist/hooks/parallel-guardrails.d.ts +268 -0
- package/dist/hooks/parallel-guardrails.d.ts.map +1 -0
- package/dist/hooks/parallel-guardrails.js +416 -0
- package/dist/hooks/parallel-guardrails.js.map +1 -0
- package/dist/hooks/rate-limit.d.ts +305 -0
- package/dist/hooks/rate-limit.d.ts.map +1 -0
- package/dist/hooks/rate-limit.js +372 -0
- package/dist/hooks/rate-limit.js.map +1 -0
- package/dist/hooks/retry.d.ts +144 -0
- package/dist/hooks/retry.d.ts.map +1 -0
- package/dist/hooks/retry.js +210 -0
- package/dist/hooks/retry.js.map +1 -0
- package/dist/hooks/secrets.d.ts +174 -0
- package/dist/hooks/secrets.d.ts.map +1 -0
- package/dist/hooks/secrets.js +306 -0
- package/dist/hooks/secrets.js.map +1 -0
- package/dist/hooks.d.ts +229 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +352 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +97 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/env.d.ts +25 -0
- package/dist/mcp/env.d.ts.map +1 -0
- package/dist/mcp/env.js +18 -0
- package/dist/mcp/env.js.map +1 -0
- package/dist/mcp/index.d.ts +16 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +17 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +184 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +446 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/mcp/types.d.ts +58 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +7 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/mcp/validation.d.ts +119 -0
- package/dist/mcp/validation.d.ts.map +1 -0
- package/dist/mcp/validation.js +407 -0
- package/dist/mcp/validation.js.map +1 -0
- package/dist/mcp/virtual-server.d.ts +78 -0
- package/dist/mcp/virtual-server.d.ts.map +1 -0
- package/dist/mcp/virtual-server.js +137 -0
- package/dist/mcp/virtual-server.js.map +1 -0
- package/dist/memory/filesystem-store.d.ts +217 -0
- package/dist/memory/filesystem-store.d.ts.map +1 -0
- package/dist/memory/filesystem-store.js +343 -0
- package/dist/memory/filesystem-store.js.map +1 -0
- package/dist/memory/index.d.ts +46 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +46 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/loader.d.ts +396 -0
- package/dist/memory/loader.d.ts.map +1 -0
- package/dist/memory/loader.js +419 -0
- package/dist/memory/loader.js.map +1 -0
- package/dist/memory/permissions.d.ts +282 -0
- package/dist/memory/permissions.d.ts.map +1 -0
- package/dist/memory/permissions.js +297 -0
- package/dist/memory/permissions.js.map +1 -0
- package/dist/memory/rules.d.ts +249 -0
- package/dist/memory/rules.d.ts.map +1 -0
- package/dist/memory/rules.js +362 -0
- package/dist/memory/rules.js.map +1 -0
- package/dist/memory/store.d.ts +286 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +263 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/middleware/apply.d.ts +73 -0
- package/dist/middleware/apply.d.ts.map +1 -0
- package/dist/middleware/apply.js +219 -0
- package/dist/middleware/apply.js.map +1 -0
- package/dist/middleware/context.d.ts +33 -0
- package/dist/middleware/context.d.ts.map +1 -0
- package/dist/middleware/context.js +176 -0
- package/dist/middleware/context.js.map +1 -0
- package/dist/middleware/index.d.ts +31 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +32 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/logging.d.ts +137 -0
- package/dist/middleware/logging.d.ts.map +1 -0
- package/dist/middleware/logging.js +374 -0
- package/dist/middleware/logging.js.map +1 -0
- package/dist/middleware/types.d.ts +183 -0
- package/dist/middleware/types.d.ts.map +1 -0
- package/dist/middleware/types.js +11 -0
- package/dist/middleware/types.js.map +1 -0
- package/dist/observability/events.d.ts +183 -0
- package/dist/observability/events.d.ts.map +1 -0
- package/dist/observability/events.js +305 -0
- package/dist/observability/events.js.map +1 -0
- package/dist/observability/index.d.ts +55 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +87 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/logger.d.ts +318 -0
- package/dist/observability/logger.d.ts.map +1 -0
- package/dist/observability/logger.js +436 -0
- package/dist/observability/logger.js.map +1 -0
- package/dist/observability/metrics.d.ts +341 -0
- package/dist/observability/metrics.d.ts.map +1 -0
- package/dist/observability/metrics.js +490 -0
- package/dist/observability/metrics.js.map +1 -0
- package/dist/observability/preset.d.ts +161 -0
- package/dist/observability/preset.d.ts.map +1 -0
- package/dist/observability/preset.js +133 -0
- package/dist/observability/preset.js.map +1 -0
- package/dist/observability/streaming.d.ts +113 -0
- package/dist/observability/streaming.d.ts.map +1 -0
- package/dist/observability/streaming.js +114 -0
- package/dist/observability/streaming.js.map +1 -0
- package/dist/observability/tracing.d.ts +378 -0
- package/dist/observability/tracing.d.ts.map +1 -0
- package/dist/observability/tracing.js +539 -0
- package/dist/observability/tracing.js.map +1 -0
- package/dist/plugins.d.ts +55 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +63 -0
- package/dist/plugins.js.map +1 -0
- package/dist/presets/index.d.ts +7 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +7 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/production.d.ts +262 -0
- package/dist/presets/production.d.ts.map +1 -0
- package/dist/presets/production.js +295 -0
- package/dist/presets/production.js.map +1 -0
- package/dist/security/index.d.ts +179 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +323 -0
- package/dist/security/index.js.map +1 -0
- package/dist/subagents/advanced.d.ts +413 -0
- package/dist/subagents/advanced.d.ts.map +1 -0
- package/dist/subagents/advanced.js +396 -0
- package/dist/subagents/advanced.js.map +1 -0
- package/dist/subagents/index.d.ts +14 -0
- package/dist/subagents/index.d.ts.map +1 -0
- package/dist/subagents/index.js +15 -0
- package/dist/subagents/index.js.map +1 -0
- package/dist/subagents.d.ts +73 -0
- package/dist/subagents.d.ts.map +1 -0
- package/dist/subagents.js +213 -0
- package/dist/subagents.js.map +1 -0
- package/dist/task-store/file-store.d.ts +76 -0
- package/dist/task-store/file-store.d.ts.map +1 -0
- package/dist/task-store/file-store.js +190 -0
- package/dist/task-store/file-store.js.map +1 -0
- package/dist/task-store/index.d.ts +11 -0
- package/dist/task-store/index.d.ts.map +1 -0
- package/dist/task-store/index.js +10 -0
- package/dist/task-store/index.js.map +1 -0
- package/dist/task-store/kv-store.d.ts +140 -0
- package/dist/task-store/kv-store.d.ts.map +1 -0
- package/dist/task-store/kv-store.js +169 -0
- package/dist/task-store/kv-store.js.map +1 -0
- package/dist/task-store/memory-store.d.ts +66 -0
- package/dist/task-store/memory-store.d.ts.map +1 -0
- package/dist/task-store/memory-store.js +125 -0
- package/dist/task-store/memory-store.js.map +1 -0
- package/dist/task-store/types.d.ts +235 -0
- package/dist/task-store/types.d.ts.map +1 -0
- package/dist/task-store/types.js +110 -0
- package/dist/task-store/types.js.map +1 -0
- package/dist/testing/assertions.d.ts +401 -0
- package/dist/testing/assertions.d.ts.map +1 -0
- package/dist/testing/assertions.js +630 -0
- package/dist/testing/assertions.js.map +1 -0
- package/dist/testing/index.d.ts +343 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +360 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/mock-agent.d.ts +214 -0
- package/dist/testing/mock-agent.d.ts.map +1 -0
- package/dist/testing/mock-agent.js +448 -0
- package/dist/testing/mock-agent.js.map +1 -0
- package/dist/testing/recorder.d.ts +288 -0
- package/dist/testing/recorder.d.ts.map +1 -0
- package/dist/testing/recorder.js +499 -0
- package/dist/testing/recorder.js.map +1 -0
- package/dist/tools/execute.d.ts +104 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +191 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/factory.d.ts +260 -0
- package/dist/tools/factory.d.ts.map +1 -0
- package/dist/tools/factory.js +241 -0
- package/dist/tools/factory.js.map +1 -0
- package/dist/tools/filesystem.d.ts +215 -0
- package/dist/tools/filesystem.d.ts.map +1 -0
- package/dist/tools/filesystem.js +311 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/index.d.ts +33 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +33 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/search.d.ts +59 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +94 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/skills.d.ts +354 -0
- package/dist/tools/skills.d.ts.map +1 -0
- package/dist/tools/skills.js +413 -0
- package/dist/tools/skills.js.map +1 -0
- package/dist/tools/task.d.ts +272 -0
- package/dist/tools/task.d.ts.map +1 -0
- package/dist/tools/task.js +521 -0
- package/dist/tools/task.js.map +1 -0
- package/dist/tools/todos.d.ts +131 -0
- package/dist/tools/todos.d.ts.map +1 -0
- package/dist/tools/todos.js +120 -0
- package/dist/tools/todos.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +424 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +607 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/user-interaction.d.ts +116 -0
- package/dist/tools/user-interaction.d.ts.map +1 -0
- package/dist/tools/user-interaction.js +147 -0
- package/dist/tools/user-interaction.js.map +1 -0
- package/dist/tools/utils.d.ts +124 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +189 -0
- package/dist/tools/utils.js.map +1 -0
- package/dist/tools.d.ts +74 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +73 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +2421 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +55 -0
- package/dist/types.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite backend that routes operations to different backends based on path prefixes.
|
|
3
|
+
*
|
|
4
|
+
* CompositeBackend allows you to combine multiple backends, routing operations to
|
|
5
|
+
* the appropriate backend based on the file path. This enables scenarios like:
|
|
6
|
+
* - Memory files from a StateBackend
|
|
7
|
+
* - Persistent files from a PersistentBackend
|
|
8
|
+
* - Real filesystem access for specific directories
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const state = createAgentState();
|
|
13
|
+
* const backend = new CompositeBackend(
|
|
14
|
+
* new StateBackend(state), // Default for unmatched paths
|
|
15
|
+
* {
|
|
16
|
+
* '/memories/': new PersistentBackend({ store }),
|
|
17
|
+
* '/workspace/': new FilesystemBackend({ rootDir: './workspace' }),
|
|
18
|
+
* }
|
|
19
|
+
* );
|
|
20
|
+
*
|
|
21
|
+
* // Routes to PersistentBackend
|
|
22
|
+
* await backend.write('/memories/user-prefs.json', '{}');
|
|
23
|
+
*
|
|
24
|
+
* // Routes to FilesystemBackend
|
|
25
|
+
* await backend.read('/workspace/src/index.ts');
|
|
26
|
+
*
|
|
27
|
+
* // Routes to StateBackend (default)
|
|
28
|
+
* await backend.write('/scratch/notes.txt', 'temp notes');
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @packageDocumentation
|
|
32
|
+
*/
|
|
33
|
+
import type { BackendProtocol, EditResult, FileData, FileInfo, GrepMatch, WriteResult } from "../backend.js";
|
|
34
|
+
/**
|
|
35
|
+
* Configuration for routing paths to backends.
|
|
36
|
+
*
|
|
37
|
+
* Keys are path prefixes (should start with '/' and optionally end with '/').
|
|
38
|
+
* Values are the backends that handle those paths.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* const routes: RouteConfig = {
|
|
43
|
+
* '/memories/': persistentBackend,
|
|
44
|
+
* '/cache/': stateBackend,
|
|
45
|
+
* '/project/': filesystemBackend,
|
|
46
|
+
* };
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @category Backend
|
|
50
|
+
*/
|
|
51
|
+
export type RouteConfig = Record<string, BackendProtocol>;
|
|
52
|
+
/**
|
|
53
|
+
* Options for creating a CompositeBackend.
|
|
54
|
+
*
|
|
55
|
+
* @category Backend
|
|
56
|
+
*/
|
|
57
|
+
export interface CompositeBackendOptions {
|
|
58
|
+
/**
|
|
59
|
+
* The default backend for paths that don't match any route.
|
|
60
|
+
*/
|
|
61
|
+
defaultBackend: BackendProtocol;
|
|
62
|
+
/**
|
|
63
|
+
* Route configuration mapping path prefixes to backends.
|
|
64
|
+
*/
|
|
65
|
+
routes: RouteConfig;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A backend that routes operations to different backends based on path prefixes.
|
|
69
|
+
*
|
|
70
|
+
* Routes are matched by longest-prefix first. For example, if you have routes for
|
|
71
|
+
* `/memories/` and `/memories/archived/`, a path like `/memories/archived/old.txt`
|
|
72
|
+
* will route to the `/memories/archived/` backend.
|
|
73
|
+
*
|
|
74
|
+
* For aggregate operations (glob, grep), results are collected from all backends
|
|
75
|
+
* and merged together.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const backend = new CompositeBackend(
|
|
80
|
+
* new StateBackend(state),
|
|
81
|
+
* {
|
|
82
|
+
* '/memories/': new PersistentBackend({ store }),
|
|
83
|
+
* '/project/': new FilesystemBackend({ rootDir: './project' }),
|
|
84
|
+
* }
|
|
85
|
+
* );
|
|
86
|
+
*
|
|
87
|
+
* // Write to different backends based on path
|
|
88
|
+
* await backend.write('/memories/notes.md', '# Notes'); // PersistentBackend
|
|
89
|
+
* await backend.write('/project/src/app.ts', '...'); // FilesystemBackend
|
|
90
|
+
* await backend.write('/temp/scratch.txt', '...'); // StateBackend (default)
|
|
91
|
+
*
|
|
92
|
+
* // Glob across all backends
|
|
93
|
+
* const allFiles = await backend.globInfo('**\/*.ts');
|
|
94
|
+
* ```
|
|
95
|
+
*
|
|
96
|
+
* @category Backend
|
|
97
|
+
*/
|
|
98
|
+
export declare class CompositeBackend implements BackendProtocol {
|
|
99
|
+
private readonly defaultBackend;
|
|
100
|
+
private readonly routes;
|
|
101
|
+
/**
|
|
102
|
+
* Create a new CompositeBackend.
|
|
103
|
+
*
|
|
104
|
+
* @param defaultBackend - Backend for paths that don't match any route
|
|
105
|
+
* @param routes - Map of path prefixes to backends
|
|
106
|
+
*/
|
|
107
|
+
constructor(defaultBackend: BackendProtocol, routes: RouteConfig);
|
|
108
|
+
/**
|
|
109
|
+
* List files and directories at the given path.
|
|
110
|
+
*
|
|
111
|
+
* Routes to the appropriate backend based on path prefix.
|
|
112
|
+
*
|
|
113
|
+
* @param path - Directory path to list
|
|
114
|
+
* @returns Array of file/directory info
|
|
115
|
+
*/
|
|
116
|
+
lsInfo(path: string): Promise<FileInfo[]>;
|
|
117
|
+
/**
|
|
118
|
+
* Read file content with optional line numbers.
|
|
119
|
+
*
|
|
120
|
+
* @param filePath - Path to the file to read
|
|
121
|
+
* @param offset - Starting line offset (0-indexed)
|
|
122
|
+
* @param limit - Maximum number of lines to read
|
|
123
|
+
* @returns Formatted content with line numbers
|
|
124
|
+
*/
|
|
125
|
+
read(filePath: string, offset?: number, limit?: number): Promise<string>;
|
|
126
|
+
/**
|
|
127
|
+
* Read raw file content as FileData.
|
|
128
|
+
*
|
|
129
|
+
* @param filePath - Path to the file to read
|
|
130
|
+
* @returns Raw file data with content and timestamps
|
|
131
|
+
*/
|
|
132
|
+
readRaw(filePath: string): Promise<FileData>;
|
|
133
|
+
/**
|
|
134
|
+
* Search for pattern matches using regex across all backends.
|
|
135
|
+
*
|
|
136
|
+
* Results are aggregated from all backends. Each backend's grep
|
|
137
|
+
* is limited to its own path scope.
|
|
138
|
+
*
|
|
139
|
+
* @param pattern - Regular expression pattern to search for
|
|
140
|
+
* @param path - Directory to search in (defaults to root)
|
|
141
|
+
* @param glob - Glob pattern to filter files
|
|
142
|
+
* @returns Array of matches from all backends
|
|
143
|
+
*/
|
|
144
|
+
grepRaw(pattern: string, path?: string | null, glob?: string | null): Promise<GrepMatch[]>;
|
|
145
|
+
/**
|
|
146
|
+
* Find files matching a glob pattern across all backends.
|
|
147
|
+
*
|
|
148
|
+
* Results are aggregated from all backends that could contain
|
|
149
|
+
* matching files.
|
|
150
|
+
*
|
|
151
|
+
* @param pattern - Glob pattern
|
|
152
|
+
* @param path - Base directory for the search
|
|
153
|
+
* @returns Array of matching file info from all backends
|
|
154
|
+
*/
|
|
155
|
+
globInfo(pattern: string, path?: string): Promise<FileInfo[]>;
|
|
156
|
+
/**
|
|
157
|
+
* Create or overwrite a file.
|
|
158
|
+
*
|
|
159
|
+
* Routes to the appropriate backend based on path prefix.
|
|
160
|
+
*
|
|
161
|
+
* @param filePath - Path for the new file
|
|
162
|
+
* @param content - Content to write
|
|
163
|
+
* @returns Result indicating success or failure
|
|
164
|
+
*/
|
|
165
|
+
write(filePath: string, content: string): Promise<WriteResult>;
|
|
166
|
+
/**
|
|
167
|
+
* Edit a file by replacing text.
|
|
168
|
+
*
|
|
169
|
+
* Routes to the appropriate backend based on path prefix.
|
|
170
|
+
*
|
|
171
|
+
* @param filePath - Path to the file to edit
|
|
172
|
+
* @param oldString - Text to find and replace
|
|
173
|
+
* @param newString - Replacement text
|
|
174
|
+
* @param replaceAll - If true, replace all occurrences
|
|
175
|
+
* @returns Result indicating success or failure
|
|
176
|
+
*/
|
|
177
|
+
edit(filePath: string, oldString: string, newString: string, replaceAll?: boolean): Promise<EditResult>;
|
|
178
|
+
/**
|
|
179
|
+
* Get the backend that handles a specific path.
|
|
180
|
+
*
|
|
181
|
+
* Useful for debugging or when you need direct access to a specific backend.
|
|
182
|
+
*
|
|
183
|
+
* @param path - Path to check
|
|
184
|
+
* @returns The backend that handles this path
|
|
185
|
+
*/
|
|
186
|
+
getBackendForPath(path: string): BackendProtocol;
|
|
187
|
+
/**
|
|
188
|
+
* Get all configured routes.
|
|
189
|
+
*
|
|
190
|
+
* @returns Array of route configurations sorted by prefix length (longest first)
|
|
191
|
+
*/
|
|
192
|
+
getRoutes(): Array<{
|
|
193
|
+
prefix: string;
|
|
194
|
+
backend: BackendProtocol;
|
|
195
|
+
}>;
|
|
196
|
+
/**
|
|
197
|
+
* Get the default backend.
|
|
198
|
+
*
|
|
199
|
+
* @returns The default backend for unmatched paths
|
|
200
|
+
*/
|
|
201
|
+
getDefaultBackend(): BackendProtocol;
|
|
202
|
+
/**
|
|
203
|
+
* Normalize a route prefix.
|
|
204
|
+
* @internal
|
|
205
|
+
*/
|
|
206
|
+
private normalizePrefix;
|
|
207
|
+
/**
|
|
208
|
+
* Normalize a path.
|
|
209
|
+
* @internal
|
|
210
|
+
*/
|
|
211
|
+
private normalizePath;
|
|
212
|
+
/**
|
|
213
|
+
* Find the matching route for a path using longest-prefix matching.
|
|
214
|
+
* @internal
|
|
215
|
+
*/
|
|
216
|
+
private findMatchingRoute;
|
|
217
|
+
/**
|
|
218
|
+
* Resolve which backend handles a path and return the relative path.
|
|
219
|
+
* @internal
|
|
220
|
+
*/
|
|
221
|
+
private resolveBackend;
|
|
222
|
+
/**
|
|
223
|
+
* Convert a composite path to a relative path for the backend.
|
|
224
|
+
* @internal
|
|
225
|
+
*/
|
|
226
|
+
private toRelativePath;
|
|
227
|
+
/**
|
|
228
|
+
* Convert a backend-relative path to a composite path.
|
|
229
|
+
* @internal
|
|
230
|
+
*/
|
|
231
|
+
private toCompositePath;
|
|
232
|
+
/**
|
|
233
|
+
* Check if parentPath is a parent of (or equal to) childPath.
|
|
234
|
+
* @internal
|
|
235
|
+
*/
|
|
236
|
+
private isParentPath;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Create a CompositeBackend from options.
|
|
240
|
+
*
|
|
241
|
+
* @param options - Configuration options
|
|
242
|
+
* @returns A new CompositeBackend
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const backend = createCompositeBackend({
|
|
247
|
+
* defaultBackend: new StateBackend(state),
|
|
248
|
+
* routes: {
|
|
249
|
+
* '/memories/': persistentBackend,
|
|
250
|
+
* '/workspace/': filesystemBackend,
|
|
251
|
+
* },
|
|
252
|
+
* });
|
|
253
|
+
* ```
|
|
254
|
+
*
|
|
255
|
+
* @category Backend
|
|
256
|
+
*/
|
|
257
|
+
export declare function createCompositeBackend(options: CompositeBackendOptions): CompositeBackend;
|
|
258
|
+
//# sourceMappingURL=composite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composite.d.ts","sourceRoot":"","sources":["../../src/backends/composite.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,WAAW,EACZ,MAAM,eAAe,CAAC;AAMvB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,cAAc,EAAE,eAAe,CAAC;IAEhC;;OAEG;IACH,MAAM,EAAE,WAAW,CAAC;CACrB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,gBAAiB,YAAW,eAAe;IACtD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsD;IAE7E;;;;;OAKG;gBACS,cAAc,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW;IAYhE;;;;;;;OAOG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAgB/C;;;;;;;OAOG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK9E;;;;;OAKG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAKlD;;;;;;;;;;OAUG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAyDhG;;;;;;;;;OASG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAoDnE;;;;;;;;OAQG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAepE;;;;;;;;;;OAUG;IACG,IAAI,CACR,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,OAAO,GACnB,OAAO,CAAC,UAAU,CAAC;IAmBtB;;;;;;;OAOG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe;IAIhD;;;;OAIG;IACH,SAAS,IAAI,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,eAAe,CAAA;KAAE,CAAC;IAIhE;;;;OAIG;IACH,iBAAiB,IAAI,eAAe;IAQpC;;;OAGG;IACH,OAAO,CAAC,eAAe;IAQvB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAOrB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAiBzB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAmBtB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAkBtB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAavB;;;OAGG;IACH,OAAO,CAAC,YAAY;CAgBrB;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,gBAAgB,CAEzF"}
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composite backend that routes operations to different backends based on path prefixes.
|
|
3
|
+
*
|
|
4
|
+
* CompositeBackend allows you to combine multiple backends, routing operations to
|
|
5
|
+
* the appropriate backend based on the file path. This enables scenarios like:
|
|
6
|
+
* - Memory files from a StateBackend
|
|
7
|
+
* - Persistent files from a PersistentBackend
|
|
8
|
+
* - Real filesystem access for specific directories
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const state = createAgentState();
|
|
13
|
+
* const backend = new CompositeBackend(
|
|
14
|
+
* new StateBackend(state), // Default for unmatched paths
|
|
15
|
+
* {
|
|
16
|
+
* '/memories/': new PersistentBackend({ store }),
|
|
17
|
+
* '/workspace/': new FilesystemBackend({ rootDir: './workspace' }),
|
|
18
|
+
* }
|
|
19
|
+
* );
|
|
20
|
+
*
|
|
21
|
+
* // Routes to PersistentBackend
|
|
22
|
+
* await backend.write('/memories/user-prefs.json', '{}');
|
|
23
|
+
*
|
|
24
|
+
* // Routes to FilesystemBackend
|
|
25
|
+
* await backend.read('/workspace/src/index.ts');
|
|
26
|
+
*
|
|
27
|
+
* // Routes to StateBackend (default)
|
|
28
|
+
* await backend.write('/scratch/notes.txt', 'temp notes');
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @packageDocumentation
|
|
32
|
+
*/
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Composite Backend Implementation
|
|
35
|
+
// =============================================================================
|
|
36
|
+
/**
|
|
37
|
+
* A backend that routes operations to different backends based on path prefixes.
|
|
38
|
+
*
|
|
39
|
+
* Routes are matched by longest-prefix first. For example, if you have routes for
|
|
40
|
+
* `/memories/` and `/memories/archived/`, a path like `/memories/archived/old.txt`
|
|
41
|
+
* will route to the `/memories/archived/` backend.
|
|
42
|
+
*
|
|
43
|
+
* For aggregate operations (glob, grep), results are collected from all backends
|
|
44
|
+
* and merged together.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const backend = new CompositeBackend(
|
|
49
|
+
* new StateBackend(state),
|
|
50
|
+
* {
|
|
51
|
+
* '/memories/': new PersistentBackend({ store }),
|
|
52
|
+
* '/project/': new FilesystemBackend({ rootDir: './project' }),
|
|
53
|
+
* }
|
|
54
|
+
* );
|
|
55
|
+
*
|
|
56
|
+
* // Write to different backends based on path
|
|
57
|
+
* await backend.write('/memories/notes.md', '# Notes'); // PersistentBackend
|
|
58
|
+
* await backend.write('/project/src/app.ts', '...'); // FilesystemBackend
|
|
59
|
+
* await backend.write('/temp/scratch.txt', '...'); // StateBackend (default)
|
|
60
|
+
*
|
|
61
|
+
* // Glob across all backends
|
|
62
|
+
* const allFiles = await backend.globInfo('**\/*.ts');
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @category Backend
|
|
66
|
+
*/
|
|
67
|
+
export class CompositeBackend {
|
|
68
|
+
defaultBackend;
|
|
69
|
+
routes;
|
|
70
|
+
/**
|
|
71
|
+
* Create a new CompositeBackend.
|
|
72
|
+
*
|
|
73
|
+
* @param defaultBackend - Backend for paths that don't match any route
|
|
74
|
+
* @param routes - Map of path prefixes to backends
|
|
75
|
+
*/
|
|
76
|
+
constructor(defaultBackend, routes) {
|
|
77
|
+
this.defaultBackend = defaultBackend;
|
|
78
|
+
// Sort routes by prefix length descending for longest-prefix matching
|
|
79
|
+
this.routes = Object.entries(routes)
|
|
80
|
+
.map(([prefix, backend]) => ({
|
|
81
|
+
prefix: this.normalizePrefix(prefix),
|
|
82
|
+
backend,
|
|
83
|
+
}))
|
|
84
|
+
.sort((a, b) => b.prefix.length - a.prefix.length);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* List files and directories at the given path.
|
|
88
|
+
*
|
|
89
|
+
* Routes to the appropriate backend based on path prefix.
|
|
90
|
+
*
|
|
91
|
+
* @param path - Directory path to list
|
|
92
|
+
* @returns Array of file/directory info
|
|
93
|
+
*/
|
|
94
|
+
async lsInfo(path) {
|
|
95
|
+
const { backend, relativePath } = this.resolveBackend(path);
|
|
96
|
+
const results = await backend.lsInfo(relativePath);
|
|
97
|
+
// Map paths back to composite paths
|
|
98
|
+
const route = this.findMatchingRoute(path);
|
|
99
|
+
if (route) {
|
|
100
|
+
return results.map((info) => ({
|
|
101
|
+
...info,
|
|
102
|
+
path: this.toCompositePath(info.path, route.prefix),
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Read file content with optional line numbers.
|
|
109
|
+
*
|
|
110
|
+
* @param filePath - Path to the file to read
|
|
111
|
+
* @param offset - Starting line offset (0-indexed)
|
|
112
|
+
* @param limit - Maximum number of lines to read
|
|
113
|
+
* @returns Formatted content with line numbers
|
|
114
|
+
*/
|
|
115
|
+
async read(filePath, offset, limit) {
|
|
116
|
+
const { backend, relativePath } = this.resolveBackend(filePath);
|
|
117
|
+
return backend.read(relativePath, offset, limit);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Read raw file content as FileData.
|
|
121
|
+
*
|
|
122
|
+
* @param filePath - Path to the file to read
|
|
123
|
+
* @returns Raw file data with content and timestamps
|
|
124
|
+
*/
|
|
125
|
+
async readRaw(filePath) {
|
|
126
|
+
const { backend, relativePath } = this.resolveBackend(filePath);
|
|
127
|
+
return backend.readRaw(relativePath);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Search for pattern matches using regex across all backends.
|
|
131
|
+
*
|
|
132
|
+
* Results are aggregated from all backends. Each backend's grep
|
|
133
|
+
* is limited to its own path scope.
|
|
134
|
+
*
|
|
135
|
+
* @param pattern - Regular expression pattern to search for
|
|
136
|
+
* @param path - Directory to search in (defaults to root)
|
|
137
|
+
* @param glob - Glob pattern to filter files
|
|
138
|
+
* @returns Array of matches from all backends
|
|
139
|
+
*/
|
|
140
|
+
async grepRaw(pattern, path, glob) {
|
|
141
|
+
const searchPath = path ?? "/";
|
|
142
|
+
// Collect results from all relevant backends
|
|
143
|
+
const allMatches = [];
|
|
144
|
+
// Check if path targets a specific backend
|
|
145
|
+
const route = this.findMatchingRoute(searchPath);
|
|
146
|
+
if (route) {
|
|
147
|
+
// Single backend search
|
|
148
|
+
const relativePath = this.toRelativePath(searchPath, route.prefix);
|
|
149
|
+
const results = await route.backend.grepRaw(pattern, relativePath, glob);
|
|
150
|
+
const matches = typeof results === "string" ? [] : results;
|
|
151
|
+
allMatches.push(...matches.map((m) => ({
|
|
152
|
+
...m,
|
|
153
|
+
path: this.toCompositePath(m.path, route.prefix),
|
|
154
|
+
})));
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// Search across all backends
|
|
158
|
+
const searchPromises = [];
|
|
159
|
+
// Search default backend
|
|
160
|
+
searchPromises.push(Promise.resolve(this.defaultBackend.grepRaw(pattern, searchPath, glob))
|
|
161
|
+
.then((results) => (typeof results === "string" ? [] : results))
|
|
162
|
+
.catch(() => []));
|
|
163
|
+
// Search each routed backend if the search path is a parent of the route
|
|
164
|
+
for (const { prefix, backend } of this.routes) {
|
|
165
|
+
if (this.isParentPath(searchPath, prefix)) {
|
|
166
|
+
const relativePath = searchPath === "/" ? "/" : this.toRelativePath(prefix, searchPath);
|
|
167
|
+
searchPromises.push(Promise.resolve(backend.grepRaw(pattern, relativePath, glob))
|
|
168
|
+
.then((results) => (typeof results === "string" ? [] : results))
|
|
169
|
+
.then((matches) => matches.map((m) => ({
|
|
170
|
+
...m,
|
|
171
|
+
path: this.toCompositePath(m.path, prefix),
|
|
172
|
+
})))
|
|
173
|
+
.catch(() => []));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const allResults = await Promise.all(searchPromises);
|
|
177
|
+
for (const results of allResults) {
|
|
178
|
+
allMatches.push(...results);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return allMatches;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Find files matching a glob pattern across all backends.
|
|
185
|
+
*
|
|
186
|
+
* Results are aggregated from all backends that could contain
|
|
187
|
+
* matching files.
|
|
188
|
+
*
|
|
189
|
+
* @param pattern - Glob pattern
|
|
190
|
+
* @param path - Base directory for the search
|
|
191
|
+
* @returns Array of matching file info from all backends
|
|
192
|
+
*/
|
|
193
|
+
async globInfo(pattern, path) {
|
|
194
|
+
const searchPath = path ?? "/";
|
|
195
|
+
// Collect results from all relevant backends
|
|
196
|
+
const allFiles = [];
|
|
197
|
+
// Check if path targets a specific backend
|
|
198
|
+
const route = this.findMatchingRoute(searchPath);
|
|
199
|
+
if (route) {
|
|
200
|
+
// Single backend search
|
|
201
|
+
const relativePath = this.toRelativePath(searchPath, route.prefix);
|
|
202
|
+
const results = await route.backend.globInfo(pattern, relativePath);
|
|
203
|
+
allFiles.push(...results.map((f) => ({
|
|
204
|
+
...f,
|
|
205
|
+
path: this.toCompositePath(f.path, route.prefix),
|
|
206
|
+
})));
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
// Search across all backends
|
|
210
|
+
const searchPromises = [];
|
|
211
|
+
// Search default backend
|
|
212
|
+
searchPromises.push(Promise.resolve(this.defaultBackend.globInfo(pattern, searchPath)).catch(() => []));
|
|
213
|
+
// Search each routed backend if the search path is a parent of the route
|
|
214
|
+
for (const { prefix, backend } of this.routes) {
|
|
215
|
+
if (this.isParentPath(searchPath, prefix)) {
|
|
216
|
+
searchPromises.push(Promise.resolve(backend.globInfo(pattern, "/"))
|
|
217
|
+
.then((files) => files.map((f) => ({
|
|
218
|
+
...f,
|
|
219
|
+
path: this.toCompositePath(f.path, prefix),
|
|
220
|
+
})))
|
|
221
|
+
.catch(() => []));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const allResults = await Promise.all(searchPromises);
|
|
225
|
+
for (const results of allResults) {
|
|
226
|
+
allFiles.push(...results);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return allFiles;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Create or overwrite a file.
|
|
233
|
+
*
|
|
234
|
+
* Routes to the appropriate backend based on path prefix.
|
|
235
|
+
*
|
|
236
|
+
* @param filePath - Path for the new file
|
|
237
|
+
* @param content - Content to write
|
|
238
|
+
* @returns Result indicating success or failure
|
|
239
|
+
*/
|
|
240
|
+
async write(filePath, content) {
|
|
241
|
+
const { backend, relativePath } = this.resolveBackend(filePath);
|
|
242
|
+
const result = await backend.write(relativePath, content);
|
|
243
|
+
// Map the path back if needed
|
|
244
|
+
if (result.path) {
|
|
245
|
+
const route = this.findMatchingRoute(filePath);
|
|
246
|
+
if (route) {
|
|
247
|
+
result.path = this.toCompositePath(result.path, route.prefix);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return result;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Edit a file by replacing text.
|
|
254
|
+
*
|
|
255
|
+
* Routes to the appropriate backend based on path prefix.
|
|
256
|
+
*
|
|
257
|
+
* @param filePath - Path to the file to edit
|
|
258
|
+
* @param oldString - Text to find and replace
|
|
259
|
+
* @param newString - Replacement text
|
|
260
|
+
* @param replaceAll - If true, replace all occurrences
|
|
261
|
+
* @returns Result indicating success or failure
|
|
262
|
+
*/
|
|
263
|
+
async edit(filePath, oldString, newString, replaceAll) {
|
|
264
|
+
const { backend, relativePath } = this.resolveBackend(filePath);
|
|
265
|
+
const result = await backend.edit(relativePath, oldString, newString, replaceAll);
|
|
266
|
+
// Map the path back if needed
|
|
267
|
+
if (result.path) {
|
|
268
|
+
const route = this.findMatchingRoute(filePath);
|
|
269
|
+
if (route) {
|
|
270
|
+
result.path = this.toCompositePath(result.path, route.prefix);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
// ===========================================================================
|
|
276
|
+
// Public Utility Methods
|
|
277
|
+
// ===========================================================================
|
|
278
|
+
/**
|
|
279
|
+
* Get the backend that handles a specific path.
|
|
280
|
+
*
|
|
281
|
+
* Useful for debugging or when you need direct access to a specific backend.
|
|
282
|
+
*
|
|
283
|
+
* @param path - Path to check
|
|
284
|
+
* @returns The backend that handles this path
|
|
285
|
+
*/
|
|
286
|
+
getBackendForPath(path) {
|
|
287
|
+
return this.resolveBackend(path).backend;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get all configured routes.
|
|
291
|
+
*
|
|
292
|
+
* @returns Array of route configurations sorted by prefix length (longest first)
|
|
293
|
+
*/
|
|
294
|
+
getRoutes() {
|
|
295
|
+
return [...this.routes];
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Get the default backend.
|
|
299
|
+
*
|
|
300
|
+
* @returns The default backend for unmatched paths
|
|
301
|
+
*/
|
|
302
|
+
getDefaultBackend() {
|
|
303
|
+
return this.defaultBackend;
|
|
304
|
+
}
|
|
305
|
+
// ===========================================================================
|
|
306
|
+
// Private Helpers
|
|
307
|
+
// ===========================================================================
|
|
308
|
+
/**
|
|
309
|
+
* Normalize a route prefix.
|
|
310
|
+
* @internal
|
|
311
|
+
*/
|
|
312
|
+
normalizePrefix(prefix) {
|
|
313
|
+
let normalized = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
314
|
+
if (!normalized.endsWith("/")) {
|
|
315
|
+
normalized += "/";
|
|
316
|
+
}
|
|
317
|
+
return normalized;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Normalize a path.
|
|
321
|
+
* @internal
|
|
322
|
+
*/
|
|
323
|
+
normalizePath(path) {
|
|
324
|
+
let normalized = path.startsWith("/") ? path : `/${path}`;
|
|
325
|
+
// Collapse multiple slashes
|
|
326
|
+
normalized = normalized.replace(/\/+/g, "/");
|
|
327
|
+
return normalized;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Find the matching route for a path using longest-prefix matching.
|
|
331
|
+
* @internal
|
|
332
|
+
*/
|
|
333
|
+
findMatchingRoute(path) {
|
|
334
|
+
const normalizedPath = this.normalizePath(path);
|
|
335
|
+
// Ensure we match with trailing slash for prefix matching
|
|
336
|
+
const pathWithSlash = normalizedPath.endsWith("/") ? normalizedPath : `${normalizedPath}/`;
|
|
337
|
+
// Routes are already sorted by length descending
|
|
338
|
+
for (const route of this.routes) {
|
|
339
|
+
if (pathWithSlash.startsWith(route.prefix) || normalizedPath === route.prefix.slice(0, -1)) {
|
|
340
|
+
return route;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return undefined;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Resolve which backend handles a path and return the relative path.
|
|
347
|
+
* @internal
|
|
348
|
+
*/
|
|
349
|
+
resolveBackend(path) {
|
|
350
|
+
const route = this.findMatchingRoute(path);
|
|
351
|
+
if (route) {
|
|
352
|
+
return {
|
|
353
|
+
backend: route.backend,
|
|
354
|
+
relativePath: this.toRelativePath(path, route.prefix),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
backend: this.defaultBackend,
|
|
359
|
+
relativePath: this.normalizePath(path),
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Convert a composite path to a relative path for the backend.
|
|
364
|
+
* @internal
|
|
365
|
+
*/
|
|
366
|
+
toRelativePath(compositePath, prefix) {
|
|
367
|
+
const normalizedPath = this.normalizePath(compositePath);
|
|
368
|
+
// If path equals prefix (without trailing slash), return root
|
|
369
|
+
if (normalizedPath === prefix.slice(0, -1)) {
|
|
370
|
+
return "/";
|
|
371
|
+
}
|
|
372
|
+
// Remove the prefix
|
|
373
|
+
if (normalizedPath.startsWith(prefix)) {
|
|
374
|
+
const relative = normalizedPath.slice(prefix.length);
|
|
375
|
+
return relative.startsWith("/") ? relative : `/${relative}`;
|
|
376
|
+
}
|
|
377
|
+
// Path doesn't start with prefix, return as-is
|
|
378
|
+
return normalizedPath;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Convert a backend-relative path to a composite path.
|
|
382
|
+
* @internal
|
|
383
|
+
*/
|
|
384
|
+
toCompositePath(relativePath, prefix) {
|
|
385
|
+
const normalizedRelative = this.normalizePath(relativePath);
|
|
386
|
+
// If relative path is root, return prefix without trailing slash
|
|
387
|
+
if (normalizedRelative === "/") {
|
|
388
|
+
return prefix.slice(0, -1);
|
|
389
|
+
}
|
|
390
|
+
// Combine prefix and relative path
|
|
391
|
+
const combined = prefix + normalizedRelative.slice(1);
|
|
392
|
+
return combined;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Check if parentPath is a parent of (or equal to) childPath.
|
|
396
|
+
* @internal
|
|
397
|
+
*/
|
|
398
|
+
isParentPath(parentPath, childPath) {
|
|
399
|
+
const normalizedParent = this.normalizePath(parentPath);
|
|
400
|
+
const normalizedChild = this.normalizePath(childPath);
|
|
401
|
+
// Root is parent of everything
|
|
402
|
+
if (normalizedParent === "/") {
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
// Check if child starts with parent
|
|
406
|
+
const parentWithSlash = normalizedParent.endsWith("/")
|
|
407
|
+
? normalizedParent
|
|
408
|
+
: `${normalizedParent}/`;
|
|
409
|
+
return normalizedChild.startsWith(parentWithSlash) || normalizedChild === normalizedParent;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// =============================================================================
|
|
413
|
+
// Factory Function
|
|
414
|
+
// =============================================================================
|
|
415
|
+
/**
|
|
416
|
+
* Create a CompositeBackend from options.
|
|
417
|
+
*
|
|
418
|
+
* @param options - Configuration options
|
|
419
|
+
* @returns A new CompositeBackend
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* const backend = createCompositeBackend({
|
|
424
|
+
* defaultBackend: new StateBackend(state),
|
|
425
|
+
* routes: {
|
|
426
|
+
* '/memories/': persistentBackend,
|
|
427
|
+
* '/workspace/': filesystemBackend,
|
|
428
|
+
* },
|
|
429
|
+
* });
|
|
430
|
+
* ```
|
|
431
|
+
*
|
|
432
|
+
* @category Backend
|
|
433
|
+
*/
|
|
434
|
+
export function createCompositeBackend(options) {
|
|
435
|
+
return new CompositeBackend(options.defaultBackend, options.routes);
|
|
436
|
+
}
|
|
437
|
+
//# sourceMappingURL=composite.js.map
|