zeitlich 0.2.28 → 0.2.30

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.
Files changed (144) hide show
  1. package/README.md +121 -13
  2. package/dist/{activities-3xj_fEJK.d.ts → activities-BeveyY9b.d.cts} +2 -3
  3. package/dist/{activities-BzYq6jf7.d.cts → activities-NT3rcw66.d.ts} +2 -3
  4. package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
  5. package/dist/adapters/sandbox/bedrock/index.d.cts +3 -3
  6. package/dist/adapters/sandbox/bedrock/index.d.ts +3 -3
  7. package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
  8. package/dist/adapters/sandbox/bedrock/workflow.d.cts +2 -2
  9. package/dist/adapters/sandbox/bedrock/workflow.d.ts +2 -2
  10. package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
  11. package/dist/adapters/sandbox/daytona/index.d.cts +1 -1
  12. package/dist/adapters/sandbox/daytona/index.d.ts +1 -1
  13. package/dist/adapters/sandbox/daytona/index.js.map +1 -1
  14. package/dist/adapters/sandbox/daytona/workflow.d.cts +1 -1
  15. package/dist/adapters/sandbox/daytona/workflow.d.ts +1 -1
  16. package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
  17. package/dist/adapters/sandbox/e2b/index.d.cts +1 -1
  18. package/dist/adapters/sandbox/e2b/index.d.ts +1 -1
  19. package/dist/adapters/sandbox/e2b/index.js.map +1 -1
  20. package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
  21. package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
  22. package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -1
  23. package/dist/adapters/sandbox/inmemory/index.d.cts +1 -1
  24. package/dist/adapters/sandbox/inmemory/index.d.ts +1 -1
  25. package/dist/adapters/sandbox/inmemory/index.js.map +1 -1
  26. package/dist/adapters/sandbox/inmemory/workflow.d.cts +1 -1
  27. package/dist/adapters/sandbox/inmemory/workflow.d.ts +1 -1
  28. package/dist/adapters/thread/anthropic/index.cjs +0 -1
  29. package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
  30. package/dist/adapters/thread/anthropic/index.d.cts +6 -7
  31. package/dist/adapters/thread/anthropic/index.d.ts +6 -7
  32. package/dist/adapters/thread/anthropic/index.js +0 -1
  33. package/dist/adapters/thread/anthropic/index.js.map +1 -1
  34. package/dist/adapters/thread/anthropic/workflow.d.cts +5 -6
  35. package/dist/adapters/thread/anthropic/workflow.d.ts +5 -6
  36. package/dist/adapters/thread/google-genai/index.cjs +0 -1
  37. package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
  38. package/dist/adapters/thread/google-genai/index.d.cts +6 -7
  39. package/dist/adapters/thread/google-genai/index.d.ts +6 -7
  40. package/dist/adapters/thread/google-genai/index.js +0 -1
  41. package/dist/adapters/thread/google-genai/index.js.map +1 -1
  42. package/dist/adapters/thread/google-genai/workflow.d.cts +5 -6
  43. package/dist/adapters/thread/google-genai/workflow.d.ts +5 -6
  44. package/dist/adapters/thread/langchain/index.cjs +0 -1
  45. package/dist/adapters/thread/langchain/index.cjs.map +1 -1
  46. package/dist/adapters/thread/langchain/index.d.cts +6 -7
  47. package/dist/adapters/thread/langchain/index.d.ts +6 -7
  48. package/dist/adapters/thread/langchain/index.js +0 -1
  49. package/dist/adapters/thread/langchain/index.js.map +1 -1
  50. package/dist/adapters/thread/langchain/workflow.d.cts +5 -6
  51. package/dist/adapters/thread/langchain/workflow.d.ts +5 -6
  52. package/dist/index.cjs +558 -50
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +136 -22
  55. package/dist/index.d.ts +136 -22
  56. package/dist/index.js +554 -52
  57. package/dist/index.js.map +1 -1
  58. package/dist/{proxy-7e7v8ccg.d.ts → proxy-BgswT47M.d.ts} +1 -1
  59. package/dist/{proxy-CsB8r0RR.d.cts → proxy-OJihshQF.d.cts} +1 -1
  60. package/dist/{thread-manager-D8C5QvLi.d.ts → thread-manager-BS477gj8.d.ts} +1 -1
  61. package/dist/{thread-manager-DdVFl1IY.d.cts → thread-manager-DH0zv05W.d.cts} +1 -1
  62. package/dist/{thread-manager-B5qA4v7V.d.ts → thread-manager-iUplxEZt.d.ts} +1 -1
  63. package/dist/{thread-manager-DFJ3sKKU.d.cts → thread-manager-lfN0V-gH.d.cts} +1 -1
  64. package/dist/{types-ChAMwU3q.d.cts → types-AujBIMMn.d.cts} +5 -8
  65. package/dist/{types-ChAMwU3q.d.ts → types-AujBIMMn.d.ts} +5 -8
  66. package/dist/{types-BZ75HpYd.d.ts → types-CCIc7Eam.d.ts} +1 -1
  67. package/dist/types-D90Q5aOh.d.ts +1212 -0
  68. package/dist/{types-BdCdR41N.d.ts → types-DBk-C8zM.d.ts} +1 -1
  69. package/dist/{types-ZHs2v9Ap.d.cts → types-DUvEZSDe.d.cts} +1 -1
  70. package/dist/types-DVdT5ybA.d.cts +1212 -0
  71. package/dist/{types-HbjqzyJH.d.cts → types-DgIVPOa1.d.cts} +1 -1
  72. package/dist/workflow-Cj4DxGdM.d.cts +750 -0
  73. package/dist/workflow-CzrBdCcJ.d.ts +750 -0
  74. package/dist/workflow.cjs +194 -40
  75. package/dist/workflow.cjs.map +1 -1
  76. package/dist/workflow.d.cts +5 -579
  77. package/dist/workflow.d.ts +5 -579
  78. package/dist/workflow.js +193 -42
  79. package/dist/workflow.js.map +1 -1
  80. package/package.json +3 -23
  81. package/src/adapters/thread/anthropic/thread-manager.ts +6 -6
  82. package/src/adapters/thread/google-genai/thread-manager.ts +6 -6
  83. package/src/adapters/thread/langchain/thread-manager.ts +6 -6
  84. package/src/index.ts +8 -0
  85. package/src/lib/lifecycle.ts +8 -3
  86. package/src/lib/observability/hooks.ts +117 -0
  87. package/src/lib/observability/index.ts +13 -0
  88. package/src/lib/observability/sinks.ts +88 -0
  89. package/src/lib/sandbox/index.ts +2 -4
  90. package/src/lib/sandbox/manager.ts +131 -16
  91. package/src/lib/sandbox/sandbox.test.ts +136 -16
  92. package/src/lib/sandbox/types.ts +6 -5
  93. package/src/lib/session/session-edge-cases.integration.test.ts +1 -0
  94. package/src/lib/session/session.integration.test.ts +7 -39
  95. package/src/lib/session/session.ts +119 -42
  96. package/src/lib/session/types.ts +39 -9
  97. package/src/lib/state/manager.integration.test.ts +1 -0
  98. package/src/lib/state/types.ts +9 -6
  99. package/src/lib/subagent/handler.ts +35 -12
  100. package/src/lib/subagent/register.ts +11 -12
  101. package/src/lib/subagent/subagent.integration.test.ts +1 -0
  102. package/src/lib/tool-router/router-edge-cases.integration.test.ts +2 -0
  103. package/src/lib/tool-router/router.integration.test.ts +2 -0
  104. package/src/lib/tool-router/router.ts +24 -2
  105. package/src/lib/types.ts +2 -0
  106. package/src/{adapters/sandbox/virtual → lib/virtual-fs}/filesystem.ts +4 -4
  107. package/src/lib/virtual-fs/index.ts +18 -0
  108. package/src/lib/virtual-fs/manager.ts +48 -0
  109. package/src/lib/virtual-fs/proxy.ts +45 -0
  110. package/src/{adapters/sandbox/virtual → lib/virtual-fs}/types.ts +41 -37
  111. package/src/{adapters/sandbox/virtual/virtual-sandbox.test.ts → lib/virtual-fs/virtual-fs.test.ts} +15 -130
  112. package/src/lib/virtual-fs/with-virtual-fs.ts +94 -0
  113. package/src/tools/bash/bash.test.ts +2 -1
  114. package/src/workflow.ts +25 -8
  115. package/tsup.config.ts +0 -2
  116. package/dist/adapters/sandbox/virtual/index.cjs +0 -487
  117. package/dist/adapters/sandbox/virtual/index.cjs.map +0 -1
  118. package/dist/adapters/sandbox/virtual/index.d.cts +0 -90
  119. package/dist/adapters/sandbox/virtual/index.d.ts +0 -90
  120. package/dist/adapters/sandbox/virtual/index.js +0 -479
  121. package/dist/adapters/sandbox/virtual/index.js.map +0 -1
  122. package/dist/adapters/sandbox/virtual/workflow.cjs +0 -33
  123. package/dist/adapters/sandbox/virtual/workflow.cjs.map +0 -1
  124. package/dist/adapters/sandbox/virtual/workflow.d.cts +0 -28
  125. package/dist/adapters/sandbox/virtual/workflow.d.ts +0 -28
  126. package/dist/adapters/sandbox/virtual/workflow.js +0 -31
  127. package/dist/adapters/sandbox/virtual/workflow.js.map +0 -1
  128. package/dist/queries-DVnukByF.d.cts +0 -44
  129. package/dist/queries-kjlvsUfz.d.ts +0 -44
  130. package/dist/types-BclYm5Ic.d.cts +0 -581
  131. package/dist/types-BclYm5Ic.d.ts +0 -581
  132. package/dist/types-BgsAwN3L.d.cts +0 -125
  133. package/dist/types-BtqbM1bO.d.ts +0 -490
  134. package/dist/types-BuCEZ4dF.d.cts +0 -490
  135. package/dist/types-yU5AINiP.d.ts +0 -125
  136. package/src/adapters/sandbox/virtual/index.ts +0 -92
  137. package/src/adapters/sandbox/virtual/provider.ts +0 -121
  138. package/src/adapters/sandbox/virtual/proxy.ts +0 -53
  139. package/src/adapters/sandbox/virtual/with-virtual-sandbox.ts +0 -97
  140. package/src/lib/.env +0 -1
  141. package/src/tools/bash/.env +0 -1
  142. /package/src/{adapters/sandbox/virtual → lib/virtual-fs}/mutations.ts +0 -0
  143. /package/src/{adapters/sandbox/virtual → lib/virtual-fs}/queries.ts +0 -0
  144. /package/src/{adapters/sandbox/virtual → lib/virtual-fs}/tree.ts +0 -0
@@ -1,90 +0,0 @@
1
- import { a as FileEntryMetadata, V as VirtualSandboxCreateOptions, b as FileResolver, c as VirtualSandboxContext, T as TreeMutation, F as FileEntry, d as VirtualSandbox } from '../../../types-BgsAwN3L.cjs';
2
- export { e as VirtualFileTree, f as VirtualSandboxFileSystem, g as VirtualSandboxState } from '../../../types-BgsAwN3L.cjs';
3
- import { b as SandboxProvider, c as SandboxCapabilities, e as SandboxCreateResult } from '../../../types-ChAMwU3q.cjs';
4
- import { WorkflowClient } from '@temporalio/client';
5
- import { J as JsonValue, A as ActivityToolHandler, R as RouterContext } from '../../../types-BclYm5Ic.cjs';
6
- export { F as FileTreeAccessor, f as filesWithMimeType, h as hasDirectory, a as hasFileWithMimeType } from '../../../queries-DVnukByF.cjs';
7
- import '@temporalio/common';
8
- import '@temporalio/workflow';
9
- import '@temporalio/common/lib/interfaces';
10
- import 'zod';
11
-
12
- /**
13
- * Stateless {@link SandboxProvider} backed by a {@link FileResolver}.
14
- *
15
- * The provider holds **no internal state**. All sandbox state (sandboxId,
16
- * fileTree, resolverContext, workspaceBase) is returned as a `stateUpdate` from
17
- * {@link create} and merged into the workflow's `AgentState` by the session.
18
- * {@link withVirtualSandbox} reads this state back on every tool invocation.
19
- *
20
- * @example
21
- * ```typescript
22
- * const provider = new VirtualSandboxProvider(resolver);
23
- * const manager = new SandboxManager(provider);
24
- *
25
- * export const activities = {
26
- * ...manager.createActivities("CodingAgent"),
27
- * readFile: withVirtualSandbox(client, provider, readHandler),
28
- * };
29
- * ```
30
- */
31
- declare class VirtualSandboxProvider<TCtx = unknown, TMeta = FileEntryMetadata> implements SandboxProvider<VirtualSandboxCreateOptions<TCtx>> {
32
- readonly id = "virtual";
33
- readonly capabilities: SandboxCapabilities;
34
- readonly resolver: FileResolver<TCtx, TMeta>;
35
- constructor(resolver: FileResolver<TCtx, TMeta>);
36
- create(options?: VirtualSandboxCreateOptions<TCtx>): Promise<SandboxCreateResult>;
37
- get(): Promise<never>;
38
- destroy(): Promise<void>;
39
- pause(): Promise<void>;
40
- fork(_sandboxId: string): Promise<never>;
41
- snapshot(): Promise<never>;
42
- restore(): Promise<never>;
43
- }
44
-
45
- /**
46
- * Wraps a tool handler that needs a virtual sandbox, automatically querying
47
- * the parent workflow for the current file tree and resolver context.
48
- *
49
- * On each invocation the wrapper:
50
- * 1. Queries the workflow's `AgentState` for `fileTree`, `resolverContext`, and `workspaceBase`
51
- * 2. Creates an ephemeral {@link VirtualSandbox} from tree + provider's resolver
52
- * 3. Runs the inner handler
53
- * 4. Returns the handler's result together with any {@link TreeMutation}s
54
- *
55
- * The consumer applies mutations back to workflow state via a post-tool hook.
56
- *
57
- * @param client - Temporal `WorkflowClient` for querying the parent workflow
58
- * @param agentName - Agent name (used to derive the state query name)
59
- * @param provider - {@link VirtualSandboxProvider} (wraps the resolver)
60
- * @param handler - Inner handler expecting a {@link VirtualSandboxContext}
61
- *
62
- * @example
63
- * ```typescript
64
- * import { withVirtualSandbox, type VirtualSandboxContext } from 'zeitlich';
65
- *
66
- * const readHandler: ActivityToolHandler<FileReadArgs, ReadResult, VirtualSandboxContext> =
67
- * async (args, { sandbox }) => {
68
- * const content = await sandbox.fs.readFile(args.path);
69
- * return { toolResponse: content, data: { path: args.path, content } };
70
- * };
71
- *
72
- * // At activity registration:
73
- * const provider = new VirtualSandboxProvider(resolver);
74
- * const handler = withVirtualSandbox(client, "myAgent", provider, readHandler);
75
- * ```
76
- */
77
- declare function withVirtualSandbox<TArgs, TResult, TCtx, TMeta = FileEntryMetadata, TToolResponse = JsonValue>(client: WorkflowClient, provider: VirtualSandboxProvider<TCtx, TMeta>, handler: ActivityToolHandler<TArgs, TResult, VirtualSandboxContext<TCtx, TMeta>, TToolResponse>): ActivityToolHandler<TArgs, (TResult & {
78
- treeMutations: TreeMutation<TMeta>[];
79
- }) | null, RouterContext, TToolResponse | string>;
80
-
81
- /**
82
- * Create an ephemeral {@link Sandbox} from a file tree and resolver.
83
- *
84
- * Used internally by {@link withVirtualSandbox} and
85
- * {@link VirtualSandboxProvider}; consumers can also call this directly
86
- * if they need a sandbox outside the wrapper pattern.
87
- */
88
- declare function createVirtualSandbox<TCtx, TMeta = FileEntryMetadata>(id: string, tree: FileEntry<TMeta>[], resolver: FileResolver<TCtx, TMeta>, ctx: TCtx, workspaceBase?: string): VirtualSandbox<TCtx, TMeta>;
89
-
90
- export { FileEntry, FileEntryMetadata, FileResolver, TreeMutation, VirtualSandbox, VirtualSandboxContext, VirtualSandboxCreateOptions, VirtualSandboxProvider, createVirtualSandbox, withVirtualSandbox };
@@ -1,90 +0,0 @@
1
- import { a as FileEntryMetadata, V as VirtualSandboxCreateOptions, b as FileResolver, c as VirtualSandboxContext, T as TreeMutation, F as FileEntry, d as VirtualSandbox } from '../../../types-yU5AINiP.js';
2
- export { e as VirtualFileTree, f as VirtualSandboxFileSystem, g as VirtualSandboxState } from '../../../types-yU5AINiP.js';
3
- import { b as SandboxProvider, c as SandboxCapabilities, e as SandboxCreateResult } from '../../../types-ChAMwU3q.js';
4
- import { WorkflowClient } from '@temporalio/client';
5
- import { J as JsonValue, A as ActivityToolHandler, R as RouterContext } from '../../../types-BclYm5Ic.js';
6
- export { F as FileTreeAccessor, f as filesWithMimeType, h as hasDirectory, a as hasFileWithMimeType } from '../../../queries-kjlvsUfz.js';
7
- import '@temporalio/common';
8
- import '@temporalio/workflow';
9
- import '@temporalio/common/lib/interfaces';
10
- import 'zod';
11
-
12
- /**
13
- * Stateless {@link SandboxProvider} backed by a {@link FileResolver}.
14
- *
15
- * The provider holds **no internal state**. All sandbox state (sandboxId,
16
- * fileTree, resolverContext, workspaceBase) is returned as a `stateUpdate` from
17
- * {@link create} and merged into the workflow's `AgentState` by the session.
18
- * {@link withVirtualSandbox} reads this state back on every tool invocation.
19
- *
20
- * @example
21
- * ```typescript
22
- * const provider = new VirtualSandboxProvider(resolver);
23
- * const manager = new SandboxManager(provider);
24
- *
25
- * export const activities = {
26
- * ...manager.createActivities("CodingAgent"),
27
- * readFile: withVirtualSandbox(client, provider, readHandler),
28
- * };
29
- * ```
30
- */
31
- declare class VirtualSandboxProvider<TCtx = unknown, TMeta = FileEntryMetadata> implements SandboxProvider<VirtualSandboxCreateOptions<TCtx>> {
32
- readonly id = "virtual";
33
- readonly capabilities: SandboxCapabilities;
34
- readonly resolver: FileResolver<TCtx, TMeta>;
35
- constructor(resolver: FileResolver<TCtx, TMeta>);
36
- create(options?: VirtualSandboxCreateOptions<TCtx>): Promise<SandboxCreateResult>;
37
- get(): Promise<never>;
38
- destroy(): Promise<void>;
39
- pause(): Promise<void>;
40
- fork(_sandboxId: string): Promise<never>;
41
- snapshot(): Promise<never>;
42
- restore(): Promise<never>;
43
- }
44
-
45
- /**
46
- * Wraps a tool handler that needs a virtual sandbox, automatically querying
47
- * the parent workflow for the current file tree and resolver context.
48
- *
49
- * On each invocation the wrapper:
50
- * 1. Queries the workflow's `AgentState` for `fileTree`, `resolverContext`, and `workspaceBase`
51
- * 2. Creates an ephemeral {@link VirtualSandbox} from tree + provider's resolver
52
- * 3. Runs the inner handler
53
- * 4. Returns the handler's result together with any {@link TreeMutation}s
54
- *
55
- * The consumer applies mutations back to workflow state via a post-tool hook.
56
- *
57
- * @param client - Temporal `WorkflowClient` for querying the parent workflow
58
- * @param agentName - Agent name (used to derive the state query name)
59
- * @param provider - {@link VirtualSandboxProvider} (wraps the resolver)
60
- * @param handler - Inner handler expecting a {@link VirtualSandboxContext}
61
- *
62
- * @example
63
- * ```typescript
64
- * import { withVirtualSandbox, type VirtualSandboxContext } from 'zeitlich';
65
- *
66
- * const readHandler: ActivityToolHandler<FileReadArgs, ReadResult, VirtualSandboxContext> =
67
- * async (args, { sandbox }) => {
68
- * const content = await sandbox.fs.readFile(args.path);
69
- * return { toolResponse: content, data: { path: args.path, content } };
70
- * };
71
- *
72
- * // At activity registration:
73
- * const provider = new VirtualSandboxProvider(resolver);
74
- * const handler = withVirtualSandbox(client, "myAgent", provider, readHandler);
75
- * ```
76
- */
77
- declare function withVirtualSandbox<TArgs, TResult, TCtx, TMeta = FileEntryMetadata, TToolResponse = JsonValue>(client: WorkflowClient, provider: VirtualSandboxProvider<TCtx, TMeta>, handler: ActivityToolHandler<TArgs, TResult, VirtualSandboxContext<TCtx, TMeta>, TToolResponse>): ActivityToolHandler<TArgs, (TResult & {
78
- treeMutations: TreeMutation<TMeta>[];
79
- }) | null, RouterContext, TToolResponse | string>;
80
-
81
- /**
82
- * Create an ephemeral {@link Sandbox} from a file tree and resolver.
83
- *
84
- * Used internally by {@link withVirtualSandbox} and
85
- * {@link VirtualSandboxProvider}; consumers can also call this directly
86
- * if they need a sandbox outside the wrapper pattern.
87
- */
88
- declare function createVirtualSandbox<TCtx, TMeta = FileEntryMetadata>(id: string, tree: FileEntry<TMeta>[], resolver: FileResolver<TCtx, TMeta>, ctx: TCtx, workspaceBase?: string): VirtualSandbox<TCtx, TMeta>;
89
-
90
- export { FileEntry, FileEntryMetadata, FileResolver, TreeMutation, VirtualSandbox, VirtualSandboxContext, VirtualSandboxCreateOptions, VirtualSandboxProvider, createVirtualSandbox, withVirtualSandbox };
@@ -1,479 +0,0 @@
1
- import { ApplicationFailure } from '@temporalio/common';
2
- import { posix } from 'path';
3
- import { uuid4 } from '@temporalio/workflow';
4
- import { Context } from '@temporalio/activity';
5
-
6
- // src/lib/sandbox/types.ts
7
- var SandboxNotSupportedError = class extends ApplicationFailure {
8
- constructor(operation) {
9
- super(
10
- `Sandbox does not support: ${operation}`,
11
- "SandboxNotSupportedError",
12
- true
13
- );
14
- }
15
- };
16
- function normalisePath(p, workspaceBase = "/") {
17
- return posix.resolve(workspaceBase, p);
18
- }
19
- function parentDir(p) {
20
- const idx = p.lastIndexOf("/");
21
- return idx <= 0 ? "/" : p.slice(0, idx);
22
- }
23
- function inferDirectories(entries, workspaceBase) {
24
- const dirs = /* @__PURE__ */ new Set();
25
- dirs.add("/");
26
- for (const entry of entries) {
27
- let dir = parentDir(normalisePath(entry.path, workspaceBase));
28
- while (dir !== "/" && !dirs.has(dir)) {
29
- dirs.add(dir);
30
- dir = parentDir(dir);
31
- }
32
- dirs.add("/");
33
- }
34
- return dirs;
35
- }
36
- var VirtualSandboxFileSystem = class {
37
- constructor(tree, resolver, ctx, workspaceBase = "/") {
38
- this.resolver = resolver;
39
- this.ctx = ctx;
40
- this.workspaceBase = normalisePath(workspaceBase);
41
- this.entries = new Map(
42
- tree.map((e) => [normalisePath(e.path, this.workspaceBase), e])
43
- );
44
- this.directories = inferDirectories(tree, this.workspaceBase);
45
- }
46
- workspaceBase;
47
- entries;
48
- directories;
49
- mutations = [];
50
- /** Return all mutations accumulated during this invocation. */
51
- getMutations() {
52
- return this.mutations;
53
- }
54
- /** Look up a file entry by virtual path. */
55
- getEntry(path) {
56
- return this.entries.get(normalisePath(path, this.workspaceBase));
57
- }
58
- // --------------------------------------------------------------------------
59
- // Read operations — delegate to resolver lazily
60
- // --------------------------------------------------------------------------
61
- async readFile(path) {
62
- const norm = normalisePath(path, this.workspaceBase);
63
- const entry = this.entries.get(norm);
64
- if (!entry) throw new Error(`ENOENT: no such file: ${path}`);
65
- return this.resolver.readFile(entry.id, this.ctx, entry.metadata);
66
- }
67
- async readFileBuffer(path) {
68
- const norm = normalisePath(path, this.workspaceBase);
69
- const entry = this.entries.get(norm);
70
- if (!entry) throw new Error(`ENOENT: no such file: ${path}`);
71
- return this.resolver.readFileBuffer(entry.id, this.ctx, entry.metadata);
72
- }
73
- // --------------------------------------------------------------------------
74
- // Metadata operations — pure, resolved from the tree
75
- // --------------------------------------------------------------------------
76
- async exists(path) {
77
- const norm = normalisePath(path, this.workspaceBase);
78
- return this.entries.has(norm) || this.directories.has(norm);
79
- }
80
- async stat(path) {
81
- const norm = normalisePath(path, this.workspaceBase);
82
- const entry = this.entries.get(norm);
83
- if (entry) {
84
- return {
85
- isFile: true,
86
- isDirectory: false,
87
- isSymbolicLink: false,
88
- size: entry.size,
89
- mtime: new Date(entry.mtime)
90
- };
91
- }
92
- if (this.directories.has(norm)) {
93
- return {
94
- isFile: false,
95
- isDirectory: true,
96
- isSymbolicLink: false,
97
- size: 0,
98
- mtime: /* @__PURE__ */ new Date()
99
- };
100
- }
101
- throw new Error(`ENOENT: no such file or directory: ${path}`);
102
- }
103
- async readdir(path) {
104
- const norm = normalisePath(path, this.workspaceBase);
105
- if (!this.directories.has(norm)) {
106
- throw new Error(`ENOENT: no such directory: ${path}`);
107
- }
108
- const prefix = norm === "/" ? "/" : norm + "/";
109
- const names = /* @__PURE__ */ new Set();
110
- for (const p of this.entries.keys()) {
111
- if (p.startsWith(prefix)) {
112
- const rest = p.slice(prefix.length);
113
- const seg = rest.split("/")[0];
114
- if (seg) names.add(seg);
115
- }
116
- }
117
- for (const d of this.directories) {
118
- if (d.startsWith(prefix) && d !== norm) {
119
- const rest = d.slice(prefix.length);
120
- const seg = rest.split("/")[0];
121
- if (seg) names.add(seg);
122
- }
123
- }
124
- return [...names].sort();
125
- }
126
- async readdirWithFileTypes(path) {
127
- const names = await this.readdir(path);
128
- const norm = normalisePath(path, this.workspaceBase);
129
- const prefix = norm === "/" ? "/" : norm + "/";
130
- return names.map((name) => {
131
- const full = prefix + name;
132
- const isFile = this.entries.has(full);
133
- const isDirectory = this.directories.has(full);
134
- return { name, isFile, isDirectory, isSymbolicLink: false };
135
- });
136
- }
137
- // --------------------------------------------------------------------------
138
- // Write operations — delegate to resolver, record mutations
139
- // --------------------------------------------------------------------------
140
- async writeFile(path, content) {
141
- const norm = normalisePath(path, this.workspaceBase);
142
- const existing = this.entries.get(norm);
143
- if (existing) {
144
- await this.resolver.writeFile(
145
- existing.id,
146
- content,
147
- this.ctx,
148
- existing.metadata
149
- );
150
- const size = typeof content === "string" ? new TextEncoder().encode(content).byteLength : content.byteLength;
151
- const updated = {
152
- ...existing,
153
- size,
154
- mtime: (/* @__PURE__ */ new Date()).toISOString()
155
- };
156
- this.entries.set(norm, updated);
157
- this.mutations.push({ type: "update", path: norm, entry: updated });
158
- } else {
159
- const entry = await this.resolver.createFile(norm, content, this.ctx);
160
- const normalised = { ...entry, path: norm };
161
- this.entries.set(norm, normalised);
162
- this.addParentDirectories(norm);
163
- this.mutations.push({ type: "add", entry: normalised });
164
- }
165
- }
166
- async appendFile(path, content) {
167
- const norm = normalisePath(path, this.workspaceBase);
168
- const existing = this.entries.get(norm);
169
- if (!existing) {
170
- return this.writeFile(path, content);
171
- }
172
- const current = await this.resolver.readFile(
173
- existing.id,
174
- this.ctx,
175
- existing.metadata
176
- );
177
- const appended = typeof content === "string" ? current + content : current + new TextDecoder().decode(content);
178
- await this.resolver.writeFile(
179
- existing.id,
180
- appended,
181
- this.ctx,
182
- existing.metadata
183
- );
184
- const size = new TextEncoder().encode(appended).byteLength;
185
- const updated = {
186
- ...existing,
187
- size,
188
- mtime: (/* @__PURE__ */ new Date()).toISOString()
189
- };
190
- this.entries.set(norm, updated);
191
- this.mutations.push({ type: "update", path: norm, entry: updated });
192
- }
193
- async mkdir(_path, _options) {
194
- const norm = normalisePath(_path, this.workspaceBase);
195
- if (this.directories.has(norm)) return;
196
- if (_options?.recursive) {
197
- this.addParentDirectories(norm + "/placeholder");
198
- this.directories.add(norm);
199
- } else {
200
- const parent = parentDir(norm);
201
- if (!this.directories.has(parent)) {
202
- throw new Error(`ENOENT: no such directory: ${parent}`);
203
- }
204
- this.directories.add(norm);
205
- }
206
- }
207
- async rm(path, options) {
208
- const norm = normalisePath(path, this.workspaceBase);
209
- const entry = this.entries.get(norm);
210
- if (entry) {
211
- await this.resolver.deleteFile(entry.id, this.ctx, entry.metadata);
212
- this.entries.delete(norm);
213
- this.mutations.push({ type: "remove", path: norm });
214
- return;
215
- }
216
- if (this.directories.has(norm)) {
217
- if (!options?.recursive) {
218
- throw new Error(`EISDIR: is a directory (use recursive): ${path}`);
219
- }
220
- const prefix = norm === "/" ? "/" : norm + "/";
221
- for (const [p, e] of this.entries) {
222
- if (p.startsWith(prefix)) {
223
- await this.resolver.deleteFile(e.id, this.ctx, e.metadata);
224
- this.entries.delete(p);
225
- this.mutations.push({ type: "remove", path: p });
226
- }
227
- }
228
- for (const d of this.directories) {
229
- if (d.startsWith(prefix)) this.directories.delete(d);
230
- }
231
- this.directories.delete(norm);
232
- return;
233
- }
234
- if (!options?.force) {
235
- throw new Error(`ENOENT: no such file or directory: ${path}`);
236
- }
237
- }
238
- async cp(src, dest, _options) {
239
- const normSrc = normalisePath(src, this.workspaceBase);
240
- const normDest = normalisePath(dest, this.workspaceBase);
241
- const entry = this.entries.get(normSrc);
242
- if (entry) {
243
- const content = await this.resolver.readFile(
244
- entry.id,
245
- this.ctx,
246
- entry.metadata
247
- );
248
- await this.writeFile(normDest, content);
249
- return;
250
- }
251
- if (!this.directories.has(normSrc)) {
252
- throw new Error(`ENOENT: no such file or directory: ${src}`);
253
- }
254
- if (!_options?.recursive) {
255
- throw new Error(`EISDIR: is a directory (use recursive): ${src}`);
256
- }
257
- const prefix = normSrc === "/" ? "/" : normSrc + "/";
258
- for (const [p, e] of this.entries) {
259
- if (p.startsWith(prefix)) {
260
- const relative = p.slice(normSrc.length);
261
- const content = await this.resolver.readFile(
262
- e.id,
263
- this.ctx,
264
- e.metadata
265
- );
266
- await this.writeFile(normDest + relative, content);
267
- }
268
- }
269
- }
270
- async mv(src, dest) {
271
- await this.cp(src, dest, { recursive: true });
272
- await this.rm(src, { recursive: true });
273
- }
274
- // --------------------------------------------------------------------------
275
- // Unsupported
276
- // --------------------------------------------------------------------------
277
- async readlink(_path) {
278
- throw new SandboxNotSupportedError("readlink");
279
- }
280
- resolvePath(base, path) {
281
- return posix.resolve(normalisePath(base, this.workspaceBase), path);
282
- }
283
- // --------------------------------------------------------------------------
284
- // Helpers
285
- // --------------------------------------------------------------------------
286
- addParentDirectories(filePath) {
287
- let dir = parentDir(normalisePath(filePath, this.workspaceBase));
288
- while (!this.directories.has(dir)) {
289
- this.directories.add(dir);
290
- dir = parentDir(dir);
291
- }
292
- }
293
- };
294
- var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
295
- function getShortId(length = 12) {
296
- const hex = uuid4().replace(/-/g, "");
297
- let result = "";
298
- for (let i = 0; i < length; i++) {
299
- const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
300
- result += BASE62[byte % BASE62.length];
301
- }
302
- return result;
303
- }
304
-
305
- // src/adapters/sandbox/virtual/provider.ts
306
- var VirtualSandboxProvider = class {
307
- id = "virtual";
308
- capabilities = {
309
- filesystem: true,
310
- execution: false,
311
- persistence: true
312
- };
313
- resolver;
314
- constructor(resolver) {
315
- this.resolver = resolver;
316
- }
317
- async create(options) {
318
- if (!options || !("resolverContext" in options)) {
319
- throw new Error("VirtualSandboxProvider.create requires resolverContext");
320
- }
321
- const sandboxId = options.id ?? getShortId();
322
- const fileTree = await this.resolver.resolveEntries(
323
- options.resolverContext
324
- );
325
- const workspaceBase = options.workspaceBase ?? "/";
326
- const sandbox = createVirtualSandbox(
327
- sandboxId,
328
- fileTree,
329
- this.resolver,
330
- options.resolverContext,
331
- workspaceBase
332
- );
333
- if (options.initialFiles) {
334
- for (const [path, content] of Object.entries(options.initialFiles)) {
335
- await sandbox.fs.writeFile(path, content);
336
- }
337
- for (const m of sandbox.fs.getMutations()) {
338
- if (m.type === "add") fileTree.push(m.entry);
339
- }
340
- }
341
- return {
342
- sandbox,
343
- stateUpdate: {
344
- sandboxId,
345
- fileTree,
346
- resolverContext: options.resolverContext,
347
- workspaceBase
348
- }
349
- };
350
- }
351
- async get() {
352
- throw new SandboxNotSupportedError(
353
- "get (virtual sandbox state lives in workflow AgentState)"
354
- );
355
- }
356
- async destroy() {
357
- }
358
- async pause() {
359
- }
360
- async fork(_sandboxId) {
361
- throw new Error("Not implemented");
362
- }
363
- async snapshot() {
364
- throw new SandboxNotSupportedError(
365
- "snapshot (virtual sandbox state lives in workflow AgentState)"
366
- );
367
- }
368
- async restore() {
369
- throw new SandboxNotSupportedError(
370
- "restore (virtual sandbox state lives in workflow AgentState)"
371
- );
372
- }
373
- };
374
- async function queryParentWorkflowState(client) {
375
- const { workflowExecution } = Context.current().info;
376
- const handle = client.getHandle(
377
- workflowExecution.workflowId,
378
- workflowExecution.runId
379
- );
380
- return handle.query("getAgentState");
381
- }
382
-
383
- // src/adapters/sandbox/virtual/with-virtual-sandbox.ts
384
- function withVirtualSandbox(client, provider, handler) {
385
- return async (args, context) => {
386
- const state = await queryParentWorkflowState(client);
387
- const { sandboxId, fileTree, resolverContext, workspaceBase } = state;
388
- if (!fileTree || !sandboxId) {
389
- return {
390
- toolResponse: `Error: No fileTree/sandboxId in agent state. The ${context.toolName} tool requires a virtual sandbox.`,
391
- data: null
392
- };
393
- }
394
- const sandbox = createVirtualSandbox(
395
- sandboxId,
396
- fileTree,
397
- provider.resolver,
398
- resolverContext,
399
- workspaceBase ?? "/"
400
- );
401
- const response = await handler(args, { ...context, sandbox });
402
- const mutations = sandbox.fs.getMutations();
403
- return {
404
- toolResponse: response.toolResponse,
405
- data: {
406
- ...response.data ?? {},
407
- treeMutations: mutations
408
- }
409
- };
410
- };
411
- }
412
-
413
- // src/adapters/sandbox/virtual/queries.ts
414
- function hasFileWithMimeType(stateManager, pattern) {
415
- const tree = stateManager.get("fileTree");
416
- const matchers = (Array.isArray(pattern) ? pattern : [pattern]).map(buildMatcher);
417
- return tree.some((entry) => {
418
- const meta = entry.metadata;
419
- const mime = meta?.mimeType;
420
- return typeof mime === "string" && matchers.some((m) => m(mime));
421
- });
422
- }
423
- function filesWithMimeType(stateManager, pattern) {
424
- const tree = stateManager.get("fileTree");
425
- const match = buildMatcher(pattern);
426
- return tree.filter((entry) => {
427
- const meta = entry.metadata;
428
- const mime = meta?.mimeType;
429
- return typeof mime === "string" && match(mime);
430
- });
431
- }
432
- function hasDirectory(stateManager, pattern) {
433
- const tree = stateManager.get("fileTree");
434
- const match = buildGlobMatcher(pattern);
435
- return tree.some((entry) => {
436
- const segments = entry.path.split("/").filter(Boolean);
437
- return segments.slice(0, -1).some(match);
438
- });
439
- }
440
- function buildMatcher(pattern) {
441
- if (pattern.endsWith("/*")) {
442
- const prefix = pattern.slice(0, -1);
443
- return (v) => v.startsWith(prefix);
444
- }
445
- return (v) => v === pattern;
446
- }
447
- function buildGlobMatcher(pattern) {
448
- if (!pattern.includes("*")) return (v) => v === pattern;
449
- const re = new RegExp(
450
- "^" + pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$"
451
- );
452
- return (v) => re.test(v);
453
- }
454
-
455
- // src/adapters/sandbox/virtual/index.ts
456
- var VirtualSandboxImpl = class {
457
- constructor(id, tree, resolver, ctx, workspaceBase = "/") {
458
- this.id = id;
459
- this.fs = new VirtualSandboxFileSystem(tree, resolver, ctx, workspaceBase);
460
- }
461
- capabilities = {
462
- filesystem: true,
463
- execution: false,
464
- persistence: true
465
- };
466
- fs;
467
- async exec(_command, _options) {
468
- throw new SandboxNotSupportedError("exec");
469
- }
470
- async destroy() {
471
- }
472
- };
473
- function createVirtualSandbox(id, tree, resolver, ctx, workspaceBase = "/") {
474
- return new VirtualSandboxImpl(id, tree, resolver, ctx, workspaceBase);
475
- }
476
-
477
- export { VirtualSandboxFileSystem, VirtualSandboxProvider, createVirtualSandbox, filesWithMimeType, hasDirectory, hasFileWithMimeType, withVirtualSandbox };
478
- //# sourceMappingURL=index.js.map
479
- //# sourceMappingURL=index.js.map