dsh-a2a-server 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/CHANGELOG.zh-CN.md +39 -0
  3. package/README.md +122 -29
  4. package/README.zh-CN.md +91 -28
  5. package/cordis.patch.yml +10 -6
  6. package/docker/Dockerfile +5 -0
  7. package/docs/visitor-isolation.en.md +51 -0
  8. package/docs/visitor-isolation.md +75 -0
  9. package/lib/briefing.d.ts +39 -0
  10. package/lib/briefing.d.ts.map +1 -0
  11. package/lib/briefing.js +108 -0
  12. package/lib/briefing.js.map +1 -0
  13. package/lib/config.d.ts +58 -15
  14. package/lib/config.d.ts.map +1 -1
  15. package/lib/config.js +74 -5
  16. package/lib/config.js.map +1 -1
  17. package/lib/contexts.d.ts +9 -4
  18. package/lib/contexts.d.ts.map +1 -1
  19. package/lib/contexts.js +7 -13
  20. package/lib/contexts.js.map +1 -1
  21. package/lib/docker-executor.d.ts +11 -0
  22. package/lib/docker-executor.d.ts.map +1 -0
  23. package/lib/docker-executor.js +115 -0
  24. package/lib/docker-executor.js.map +1 -0
  25. package/lib/index.d.ts +1 -31
  26. package/lib/index.d.ts.map +1 -1
  27. package/lib/index.js +462 -440
  28. package/lib/index.js.map +1 -1
  29. package/lib/isolation.d.ts +21 -0
  30. package/lib/isolation.d.ts.map +1 -0
  31. package/lib/isolation.js +108 -0
  32. package/lib/isolation.js.map +1 -0
  33. package/lib/management.d.ts +5 -0
  34. package/lib/management.d.ts.map +1 -0
  35. package/lib/management.js +75 -0
  36. package/lib/management.js.map +1 -0
  37. package/lib/microsandbox-executor.d.ts +39 -0
  38. package/lib/microsandbox-executor.d.ts.map +1 -0
  39. package/lib/microsandbox-executor.js +316 -0
  40. package/lib/microsandbox-executor.js.map +1 -0
  41. package/lib/microsandbox-runtime.d.ts +28 -0
  42. package/lib/microsandbox-runtime.d.ts.map +1 -0
  43. package/lib/microsandbox-runtime.js +164 -0
  44. package/lib/microsandbox-runtime.js.map +1 -0
  45. package/lib/projection.d.ts +46 -3
  46. package/lib/projection.d.ts.map +1 -1
  47. package/lib/projection.js +19 -8
  48. package/lib/projection.js.map +1 -1
  49. package/lib/router.d.ts +47 -0
  50. package/lib/router.d.ts.map +1 -1
  51. package/lib/router.js +218 -65
  52. package/lib/router.js.map +1 -1
  53. package/lib/sandbox-files.d.ts +16 -0
  54. package/lib/sandbox-files.d.ts.map +1 -0
  55. package/lib/sandbox-files.js +168 -0
  56. package/lib/sandbox-files.js.map +1 -0
  57. package/lib/sandbox-lifecycle.d.ts +48 -0
  58. package/lib/sandbox-lifecycle.d.ts.map +1 -0
  59. package/lib/sandbox-lifecycle.js +125 -0
  60. package/lib/sandbox-lifecycle.js.map +1 -0
  61. package/lib/security.d.ts +4 -2
  62. package/lib/security.d.ts.map +1 -1
  63. package/lib/security.js +4 -2
  64. package/lib/security.js.map +1 -1
  65. package/lib/state.d.ts +37 -0
  66. package/lib/state.d.ts.map +1 -0
  67. package/lib/state.js +146 -0
  68. package/lib/state.js.map +1 -0
  69. package/lib/tasks.d.ts +4 -0
  70. package/lib/tasks.d.ts.map +1 -1
  71. package/lib/tasks.js +18 -0
  72. package/lib/tasks.js.map +1 -1
  73. package/lib/types.d.ts +9 -0
  74. package/lib/types.d.ts.map +1 -1
  75. package/lib/types.js.map +1 -1
  76. package/lib/version.d.ts +1 -1
  77. package/lib/version.js +1 -1
  78. package/lib/visitor-read.d.ts +4 -0
  79. package/lib/visitor-read.d.ts.map +1 -0
  80. package/lib/visitor-read.js +20 -0
  81. package/lib/visitor-read.js.map +1 -0
  82. package/lib/visitor-worker.d.ts +2 -0
  83. package/lib/visitor-worker.d.ts.map +1 -0
  84. package/lib/visitor-worker.js +18 -0
  85. package/lib/visitor-worker.js.map +1 -0
  86. package/lib/visitor-worker.mjs +14686 -0
  87. package/lib/visitor-worker.py +78 -0
  88. package/lib/workspace-read.d.ts +9 -0
  89. package/lib/workspace-read.d.ts.map +1 -0
  90. package/lib/workspace-read.js +152 -0
  91. package/lib/workspace-read.js.map +1 -0
  92. package/package.json +48 -31
@@ -0,0 +1,78 @@
1
+ """Trusted bounded reader. Public data and a visitor's disk are the only roots."""
2
+ import json
3
+ import os
4
+ import pathlib
5
+ import stat
6
+ import sys
7
+
8
+ def read_request(args):
9
+ if not isinstance(args, dict) or set(args) - {'root', 'path', 'offset', 'limit'}:
10
+ raise ValueError('Invalid read request')
11
+ root_name = args.get('root', 'public')
12
+ if root_name not in ('public', 'workspace'):
13
+ raise ValueError('Unknown data root')
14
+ root = pathlib.Path('/source' if root_name == 'public' else '/work')
15
+ requested = args.get('path')
16
+ offset, limit = args.get('offset', 1), args.get('limit', 200)
17
+ if not isinstance(requested, str) or not 1 <= len(requested) <= 4096 or any(c in requested for c in ('\0', '\\', ':')):
18
+ raise ValueError('Invalid file path')
19
+ if type(offset) is not int or not 1 <= offset <= 10000000 or type(limit) is not int or not 1 <= limit <= 500:
20
+ raise ValueError('Invalid read pagination')
21
+ target = pathlib.Path(os.path.abspath(root / requested))
22
+ try:
23
+ parts = target.relative_to(root).parts
24
+ except ValueError:
25
+ raise ValueError('Path is outside the authorized data directory')
26
+ current = root
27
+ for component in ('',) + parts:
28
+ current = current / component
29
+ if stat.S_ISLNK(current.lstat().st_mode):
30
+ raise ValueError('Symbolic links are not available')
31
+ before = target.lstat()
32
+ if stat.S_ISDIR(before.st_mode):
33
+ entries, truncated = [], False
34
+ with os.scandir(target) as iterator:
35
+ for index, entry in enumerate(iterator):
36
+ if index >= 1000:
37
+ truncated = True
38
+ break
39
+ if entry.is_symlink():
40
+ continue
41
+ if entry.is_file(follow_symlinks=False) or entry.is_dir(follow_symlinks=False):
42
+ entries.append(entry.name + ('/' if entry.is_dir(follow_symlinks=False) else ''))
43
+ entries.sort()
44
+ text = '\n'.join(entries[offset - 1:offset - 1 + limit])
45
+ truncated = truncated or len(entries) > offset - 1 + limit
46
+ kind = 'directory'
47
+ else:
48
+ if not stat.S_ISREG(before.st_mode) or before.st_nlink != 1:
49
+ raise ValueError('Only regular files without hard links can be read')
50
+ if before.st_size > 2 * 1024 * 1024:
51
+ raise ValueError('File exceeds the 2 MiB read limit')
52
+ fd = os.open(target, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
53
+ with os.fdopen(fd, 'rb') as stream:
54
+ opened = os.fstat(stream.fileno())
55
+ if (opened.st_dev, opened.st_ino, opened.st_nlink) != (before.st_dev, before.st_ino, 1):
56
+ raise ValueError('File changed during open')
57
+ data = stream.read(2 * 1024 * 1024 + 1)
58
+ if len(data) > 2 * 1024 * 1024:
59
+ raise ValueError('File exceeds the 2 MiB read limit')
60
+ text = data.decode('utf-8', errors='strict')
61
+ if '\0' in text:
62
+ raise ValueError('Binary files are not supported by read_file')
63
+ lines = text.replace('\r\n', '\n').split('\n')
64
+ text = '\n'.join(lines[offset - 1:offset - 1 + limit])
65
+ truncated = len(lines) > offset - 1 + limit
66
+ kind = 'file'
67
+ after = target.lstat()
68
+ if (before.st_dev, before.st_ino) != (after.st_dev, after.st_ino):
69
+ raise ValueError('Path changed during read')
70
+ return {'kind': kind, 'path': str(target.relative_to(root)), 'content': text[:32000], 'truncated': truncated or len(text) > 32000}
71
+
72
+ try:
73
+ if len(sys.argv[1].encode('utf-8')) > 8192:
74
+ raise ValueError('Read request too large')
75
+ print(json.dumps({'result': read_request(json.loads(sys.argv[1]))}, ensure_ascii=False))
76
+ except Exception as error:
77
+ print(json.dumps({'error': str(error)}, ensure_ascii=False))
78
+ sys.exit(1)
@@ -0,0 +1,9 @@
1
+ import type { ToolDefinition } from '@deepseek-ai/dsh-tools';
2
+ export declare const WORKSPACE_READ_TOOL = "read_file";
3
+ /**
4
+ * Pin a canonical root for this activation. Never mount the host's general read
5
+ * tool: its path policy is different. State directories remain private even
6
+ * when an operator puts them inside the shared data root.
7
+ */
8
+ export declare function workspaceReadTool(directory: string, privateDirectories: readonly string[]): Promise<ToolDefinition>;
9
+ //# sourceMappingURL=workspace-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-read.d.ts","sourceRoot":"","sources":["../src/workspace-read.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAG5D,eAAO,MAAM,mBAAmB,cAAc,CAAA;AAe9C;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CA0GzH"}
@@ -0,0 +1,152 @@
1
+ /** A single read capability rooted in the owner's configured data directory. */
2
+ import { constants } from 'node:fs';
3
+ import { lstat, open, opendir, realpath } from 'node:fs/promises';
4
+ import { isAbsolute, join, relative, resolve, sep } from 'node:path';
5
+ import { z } from 'zod';
6
+ export const WORKSPACE_READ_TOOL = 'read_file';
7
+ const MAX_FILE_BYTES = 2 * 1024 * 1024;
8
+ const MAX_TEXT_CHARS = 32_000;
9
+ const MAX_DIRECTORY_SCAN = 1000;
10
+ const argsSchema = z.object({
11
+ path: z.string().min(1).max(4096),
12
+ offset: z.number().int().min(1).max(10_000_000).default(1),
13
+ limit: z.number().int().min(1).max(500).default(200),
14
+ }).strict();
15
+ function within(root, target) {
16
+ const suffix = relative(root, target);
17
+ return suffix === '' || (!isAbsolute(suffix) && suffix !== '..' && !suffix.startsWith(`..${sep}`));
18
+ }
19
+ /**
20
+ * Pin a canonical root for this activation. Never mount the host's general read
21
+ * tool: its path policy is different. State directories remain private even
22
+ * when an operator puts them inside the shared data root.
23
+ */
24
+ export async function workspaceReadTool(directory, privateDirectories) {
25
+ const configuredRoot = resolve(directory);
26
+ const root = await realpath(directory);
27
+ const privatePaths = await Promise.all(privateDirectories.map(async (path) => {
28
+ const absolute = resolve(path);
29
+ return { absolute, canonical: await realpath(absolute).catch(() => absolute) };
30
+ }));
31
+ const isPrivate = (path) => privatePaths.some(p => within(p.absolute, path) || within(p.canonical, path));
32
+ const validatePath = async (input) => {
33
+ if (input.includes('\0'))
34
+ throw new Error('Invalid file path');
35
+ // Reject NT device namespaces and alternate data streams before normalization.
36
+ if (process.platform === 'win32' && (/^[/\\]{2}[?.][/\\]/.test(input) || input.replace(/^[a-z]:/i, '').includes(':'))) {
37
+ throw new Error('Device paths and alternate data streams are not available');
38
+ }
39
+ const absolute = resolve(root, input);
40
+ // Windows may return an expanded path for a configured 8.3 directory alias.
41
+ const candidate = isAbsolute(input) && within(configuredRoot, absolute)
42
+ ? resolve(root, relative(configuredRoot, absolute)) : absolute;
43
+ if (!within(root, candidate) || isPrivate(candidate))
44
+ throw new Error('Path is outside the authorized data directory');
45
+ const canonical = await realpath(candidate);
46
+ if (!within(root, canonical) || isPrivate(canonical))
47
+ throw new Error('Path is outside the authorized data directory');
48
+ // Refuse links/junctions along the entire relative path, even when a link
49
+ // currently targets this root. An authorized directory is not a link portal.
50
+ let current = root;
51
+ for (const component of ['', ...relative(root, candidate).split(sep).filter(Boolean)]) {
52
+ if (component)
53
+ current = join(current, component);
54
+ if ((await lstat(current)).isSymbolicLink())
55
+ throw new Error('Symbolic links and junctions are not available');
56
+ }
57
+ return candidate;
58
+ };
59
+ return {
60
+ name: WORKSPACE_READ_TOOL,
61
+ description: 'Read a UTF-8 text file from the owner-authorized data directory. Paths are relative to that directory (not the agent cwd); absolute paths must remain inside it. Use path "." to list its entries, or a subdirectory path to list that directory. offset is a 1-based line/entry offset; limit is at most 500. Other tools and writes are unavailable.',
62
+ parameters: {
63
+ type: 'object', additionalProperties: false, required: ['path'], properties: {
64
+ path: { type: 'string', minLength: 1, maxLength: 4096 },
65
+ offset: { type: 'integer', minimum: 1, maximum: 10_000_000 },
66
+ limit: { type: 'integer', minimum: 1, maximum: 500 },
67
+ },
68
+ },
69
+ output: {
70
+ schema: { type: 'object', required: ['kind', 'path', 'content', 'truncated'], properties: {
71
+ kind: { type: 'string' }, path: { type: 'string' }, content: { type: 'string' }, truncated: { type: 'boolean' },
72
+ } },
73
+ render: (_args, value) => [{ type: 'text', text: JSON.stringify(value) }],
74
+ },
75
+ execute: async (raw, { signal }) => {
76
+ const args = argsSchema.parse(raw);
77
+ signal.throwIfAborted();
78
+ const path = await validatePath(args.path);
79
+ const before = await lstat(path);
80
+ if (before.isDirectory()) {
81
+ const entries = [];
82
+ let scanned = 0;
83
+ let truncated = false;
84
+ // Read at most a bounded prefix; do not build an unbounded directory tree.
85
+ const dir = await opendir(path);
86
+ for await (const entry of dir) {
87
+ signal.throwIfAborted();
88
+ if (++scanned > MAX_DIRECTORY_SCAN) {
89
+ truncated = true;
90
+ break;
91
+ }
92
+ if (entry.isSymbolicLink() || isPrivate(join(path, entry.name)))
93
+ continue;
94
+ if (!entry.isFile() && !entry.isDirectory())
95
+ continue;
96
+ entries.push(`${entry.name}${entry.isDirectory() ? '/' : ''}`);
97
+ }
98
+ const after = await lstat(await validatePath(args.path));
99
+ if (before.dev !== after.dev || before.ino !== after.ino)
100
+ throw new Error('Directory changed during read; retry');
101
+ entries.sort();
102
+ const selected = entries.slice(args.offset - 1, args.offset - 1 + args.limit).join('\n');
103
+ return { kind: 'directory', path: relative(root, path) || '.', content: selected.slice(0, MAX_TEXT_CHARS),
104
+ truncated: truncated || entries.length > args.offset - 1 + args.limit || selected.length > MAX_TEXT_CHARS };
105
+ }
106
+ if (!before.isFile())
107
+ throw new Error('Only regular text files and directories can be read');
108
+ if (before.nlink > 1)
109
+ throw new Error('Hard-linked files are not available');
110
+ if (before.size > MAX_FILE_BYTES)
111
+ throw new Error('File exceeds the 2 MiB read limit');
112
+ // O_NOFOLLOW is supported on Unix. Windows is covered by the component
113
+ // checks and comparing the opened file's identity before reading any bytes.
114
+ const handle = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
115
+ try {
116
+ const opened = await handle.stat();
117
+ if (!opened.isFile() || opened.nlink > 1 || opened.dev !== before.dev || opened.ino !== before.ino)
118
+ throw new Error('File changed during open; retry');
119
+ if (opened.size > MAX_FILE_BYTES)
120
+ throw new Error('File exceeds the 2 MiB read limit');
121
+ await validatePath(args.path);
122
+ // Explicit byte limit also bounds reads if a local writer grows the file.
123
+ const bytes = Buffer.alloc(MAX_FILE_BYTES + 1);
124
+ let used = 0;
125
+ while (used < bytes.length) {
126
+ signal.throwIfAborted();
127
+ const part = await handle.read(bytes, used, bytes.length - used, used);
128
+ if (!part.bytesRead)
129
+ break;
130
+ used += part.bytesRead;
131
+ }
132
+ if (used > MAX_FILE_BYTES)
133
+ throw new Error('File exceeds the 2 MiB read limit');
134
+ const after = await lstat(await validatePath(args.path));
135
+ if (opened.dev !== after.dev || opened.ino !== after.ino || after.nlink > 1)
136
+ throw new Error('File changed during read; retry');
137
+ signal.throwIfAborted();
138
+ const content = new TextDecoder('utf-8', { fatal: true }).decode(bytes.subarray(0, used));
139
+ if (content.includes('\0'))
140
+ throw new Error('Binary files are not supported by read_file');
141
+ const lines = content.split(/\r?\n/);
142
+ const selected = lines.slice(args.offset - 1, args.offset - 1 + args.limit).join('\n');
143
+ return { kind: 'file', path: relative(root, path), content: selected.slice(0, MAX_TEXT_CHARS),
144
+ truncated: lines.length > args.offset - 1 + args.limit || selected.length > MAX_TEXT_CHARS };
145
+ }
146
+ finally {
147
+ await handle.close();
148
+ }
149
+ },
150
+ };
151
+ }
152
+ //# sourceMappingURL=workspace-read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-read.js","sourceRoot":"","sources":["../src/workspace-read.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-a2a-server",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Inbound A2A (Agent2Agent) protocol server for DeepSeek Harness: publish an Agent Card and let any A2A-compliant peer submit tasks to a harness agent",
5
5
  "keywords": [
6
6
  "dsh",
@@ -27,57 +27,74 @@
27
27
  },
28
28
  "files": [
29
29
  "lib",
30
- "cordis.patch.yml"
30
+ "docker",
31
+ "cordis.patch.yml",
32
+ "README.zh-CN.md",
33
+ "docs/visitor-isolation.md",
34
+ "docs/visitor-isolation.en.md",
35
+ "CHANGELOG.md",
36
+ "CHANGELOG.zh-CN.md"
31
37
  ],
32
38
  "dsh": {
33
39
  "bundle": {
34
40
  "patch": "./cordis.patch.yml"
35
41
  }
36
42
  },
43
+ "engines": {
44
+ "dsh": ">=0.2.1-rc.2 <0.3.0"
45
+ },
37
46
  "scripts": {
38
- "build": "tsc -p tsconfig.build.json",
47
+ "build": "tsc -p tsconfig.build.json && node scripts/build-worker.mjs",
39
48
  "typecheck": "tsc -p tsconfig.json --noEmit",
40
49
  "test": "vitest run",
41
50
  "test:watch": "vitest",
51
+ "test:docker": "pnpm build && node scripts/test-docker.mjs",
52
+ "test:microsandbox": "pnpm build && node scripts/test-microsandbox.mjs",
53
+ "test:package": "pnpm build && node scripts/test-package.mjs",
42
54
  "serve": "tsx example/serve.ts",
43
55
  "probe": "node example/probe.mjs",
44
- "prepublishOnly": "pnpm typecheck && pnpm test && pnpm build"
56
+ "prepublishOnly": "pnpm typecheck && pnpm test && pnpm test:package"
45
57
  },
46
58
  "peerDependencies": {
47
- "@deepseek-ai/cordis": "4.0.1",
48
- "@deepseek-ai/dsh-agent": "0.1.0-rc.6",
49
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
50
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
51
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
52
- "@deepseek-ai/dsh-session": "0.1.0-rc.6"
59
+ "@deepseek-ai/cordis": "^4.0.5",
60
+ "@deepseek-ai/dsh-agent": ">=0.2.1-rc.2 <0.3.0",
61
+ "@deepseek-ai/dsh-credentials": ">=0.2.1-rc.2 <0.3.0",
62
+ "@deepseek-ai/dsh-host-webserver": ">=0.2.1-rc.2 <0.3.0",
63
+ "@deepseek-ai/dsh-llm": ">=0.2.1-rc.2 <0.3.0",
64
+ "@deepseek-ai/dsh-session": ">=0.2.1-rc.2 <0.3.0",
65
+ "@deepseek-ai/dsh-session-projection": ">=0.2.1-rc.2 <0.3.0",
66
+ "@deepseek-ai/dsh-system-prompt": ">=0.2.1-rc.2 <0.3.0",
67
+ "@deepseek-ai/dsh-tools": ">=0.2.1-rc.2 <0.3.0"
53
68
  },
54
69
  "dependencies": {
55
- "@deepseek-ai/schemastery": "3.18.1"
70
+ "@deepseek-ai/schemastery": "^3.18.5",
71
+ "zod": "^4.4.3"
56
72
  },
57
73
  "devDependencies": {
58
- "@deepseek-ai/cordis": "4.0.1",
59
- "@deepseek-ai/cordis-plugin-loader": "1.0.2",
60
- "@deepseek-ai/dsh-agent": "0.1.0-rc.6",
61
- "@deepseek-ai/dsh-agent-loop": "0.1.0-rc.6",
62
- "@deepseek-ai/dsh-agent-loop-testkit": "0.1.0-rc.6",
63
- "@deepseek-ai/dsh-brand": "0.1.0-rc.6",
64
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
65
- "@deepseek-ai/dsh-credentials-local": "0.1.0-rc.6",
66
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.6",
67
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
68
- "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
69
- "@deepseek-ai/dsh-llm-deepseek": "0.1.0-rc.6",
70
- "@deepseek-ai/dsh-llm-replay": "0.1.0-rc.6",
71
- "@deepseek-ai/dsh-scope": "0.1.0-rc.6",
72
- "@deepseek-ai/dsh-session": "0.1.0-rc.6",
73
- "@deepseek-ai/dsh-session-projection": "0.1.0-rc.6",
74
- "@deepseek-ai/dsh-system-prompt": "0.1.0-rc.6",
75
- "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
74
+ "@deepseek-ai/cordis": "4.0.5",
75
+ "@deepseek-ai/cordis-plugin-loader": "1.0.6",
76
+ "@deepseek-ai/dsh-agent": "0.2.1-rc.2",
77
+ "@deepseek-ai/dsh-agent-loop": "0.2.1-rc.2",
78
+ "@deepseek-ai/dsh-agent-loop-testkit": "0.2.1-rc.2",
79
+ "@deepseek-ai/dsh-brand": "0.2.1-rc.2",
80
+ "@deepseek-ai/dsh-credentials": "0.2.1-rc.2",
81
+ "@deepseek-ai/dsh-credentials-local": "0.2.1-rc.2",
82
+ "@deepseek-ai/dsh-host-webserver": "0.2.1-rc.2",
83
+ "@deepseek-ai/dsh-llm": "0.2.1-rc.2",
84
+ "@deepseek-ai/dsh-llm-deepseek": "0.2.1-rc.2",
85
+ "@deepseek-ai/dsh-llm-deepseek-api-key": "0.2.1-rc.2",
86
+ "@deepseek-ai/dsh-llm-replay": "0.2.1-rc.2",
87
+ "@deepseek-ai/dsh-scope": "0.2.1-rc.2",
88
+ "@deepseek-ai/dsh-session": "0.2.1-rc.2",
89
+ "@deepseek-ai/dsh-session-projection": "0.2.1-rc.2",
90
+ "@deepseek-ai/dsh-system-prompt": "0.2.1-rc.2",
91
+ "@deepseek-ai/dsh-tools": "0.2.1-rc.2",
76
92
  "@types/node": "^22.10.0",
93
+ "esbuild": "0.28.2",
94
+ "microsandbox": "0.7.11",
77
95
  "tsx": "^4.19.2",
78
96
  "typescript": "^5.7.2",
79
- "vitest": "^2.1.8",
80
- "zod": "^4.4.3"
97
+ "vitest": "^2.1.8"
81
98
  },
82
99
  "repository": {
83
100
  "type": "git",