e2e-pilot 0.0.69

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 (152) hide show
  1. package/bin.js +3 -0
  2. package/dist/aria-snapshot.d.ts +95 -0
  3. package/dist/aria-snapshot.d.ts.map +1 -0
  4. package/dist/aria-snapshot.js +490 -0
  5. package/dist/aria-snapshot.js.map +1 -0
  6. package/dist/bippy.js +971 -0
  7. package/dist/cdp-relay.d.ts +16 -0
  8. package/dist/cdp-relay.d.ts.map +1 -0
  9. package/dist/cdp-relay.js +715 -0
  10. package/dist/cdp-relay.js.map +1 -0
  11. package/dist/cdp-session.d.ts +42 -0
  12. package/dist/cdp-session.d.ts.map +1 -0
  13. package/dist/cdp-session.js +154 -0
  14. package/dist/cdp-session.js.map +1 -0
  15. package/dist/cdp-types.d.ts +63 -0
  16. package/dist/cdp-types.d.ts.map +1 -0
  17. package/dist/cdp-types.js +91 -0
  18. package/dist/cdp-types.js.map +1 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +213 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/create-logger.d.ts +9 -0
  24. package/dist/create-logger.d.ts.map +1 -0
  25. package/dist/create-logger.js +25 -0
  26. package/dist/create-logger.js.map +1 -0
  27. package/dist/debugger-api.md +458 -0
  28. package/dist/debugger-examples-types.d.ts +24 -0
  29. package/dist/debugger-examples-types.d.ts.map +1 -0
  30. package/dist/debugger-examples-types.js +2 -0
  31. package/dist/debugger-examples-types.js.map +1 -0
  32. package/dist/debugger-examples.d.ts +6 -0
  33. package/dist/debugger-examples.d.ts.map +1 -0
  34. package/dist/debugger-examples.js +53 -0
  35. package/dist/debugger-examples.js.map +1 -0
  36. package/dist/debugger.d.ts +381 -0
  37. package/dist/debugger.d.ts.map +1 -0
  38. package/dist/debugger.js +633 -0
  39. package/dist/debugger.js.map +1 -0
  40. package/dist/editor-api.md +364 -0
  41. package/dist/editor-examples.d.ts +11 -0
  42. package/dist/editor-examples.d.ts.map +1 -0
  43. package/dist/editor-examples.js +124 -0
  44. package/dist/editor-examples.js.map +1 -0
  45. package/dist/editor.d.ts +203 -0
  46. package/dist/editor.d.ts.map +1 -0
  47. package/dist/editor.js +336 -0
  48. package/dist/editor.js.map +1 -0
  49. package/dist/execute.d.ts +50 -0
  50. package/dist/execute.d.ts.map +1 -0
  51. package/dist/execute.js +576 -0
  52. package/dist/execute.js.map +1 -0
  53. package/dist/index.d.ts +11 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +7 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/mcp-client.d.ts +20 -0
  58. package/dist/mcp-client.d.ts.map +1 -0
  59. package/dist/mcp-client.js +56 -0
  60. package/dist/mcp-client.js.map +1 -0
  61. package/dist/mcp.d.ts +5 -0
  62. package/dist/mcp.d.ts.map +1 -0
  63. package/dist/mcp.js +720 -0
  64. package/dist/mcp.js.map +1 -0
  65. package/dist/mcp.test.d.ts +10 -0
  66. package/dist/mcp.test.d.ts.map +1 -0
  67. package/dist/mcp.test.js +2999 -0
  68. package/dist/mcp.test.js.map +1 -0
  69. package/dist/network-capture.d.ts +23 -0
  70. package/dist/network-capture.d.ts.map +1 -0
  71. package/dist/network-capture.js +98 -0
  72. package/dist/network-capture.js.map +1 -0
  73. package/dist/protocol.d.ts +54 -0
  74. package/dist/protocol.d.ts.map +1 -0
  75. package/dist/protocol.js +2 -0
  76. package/dist/protocol.js.map +1 -0
  77. package/dist/react-source.d.ts +13 -0
  78. package/dist/react-source.d.ts.map +1 -0
  79. package/dist/react-source.js +68 -0
  80. package/dist/react-source.js.map +1 -0
  81. package/dist/scoped-fs.d.ts +94 -0
  82. package/dist/scoped-fs.d.ts.map +1 -0
  83. package/dist/scoped-fs.js +356 -0
  84. package/dist/scoped-fs.js.map +1 -0
  85. package/dist/selector-generator.js +8126 -0
  86. package/dist/start-relay-server.d.ts +6 -0
  87. package/dist/start-relay-server.d.ts.map +1 -0
  88. package/dist/start-relay-server.js +33 -0
  89. package/dist/start-relay-server.js.map +1 -0
  90. package/dist/styles-api.md +117 -0
  91. package/dist/styles-examples.d.ts +8 -0
  92. package/dist/styles-examples.d.ts.map +1 -0
  93. package/dist/styles-examples.js +64 -0
  94. package/dist/styles-examples.js.map +1 -0
  95. package/dist/styles.d.ts +27 -0
  96. package/dist/styles.d.ts.map +1 -0
  97. package/dist/styles.js +234 -0
  98. package/dist/styles.js.map +1 -0
  99. package/dist/trace-utils.d.ts +14 -0
  100. package/dist/trace-utils.d.ts.map +1 -0
  101. package/dist/trace-utils.js +21 -0
  102. package/dist/trace-utils.js.map +1 -0
  103. package/dist/utils.d.ts +20 -0
  104. package/dist/utils.d.ts.map +1 -0
  105. package/dist/utils.js +75 -0
  106. package/dist/utils.js.map +1 -0
  107. package/dist/wait-for-page-load.d.ts +16 -0
  108. package/dist/wait-for-page-load.d.ts.map +1 -0
  109. package/dist/wait-for-page-load.js +127 -0
  110. package/dist/wait-for-page-load.js.map +1 -0
  111. package/package.json +67 -0
  112. package/src/aria-snapshot.ts +610 -0
  113. package/src/assets/aria-labels-github-snapshot.txt +605 -0
  114. package/src/assets/aria-labels-github.png +0 -0
  115. package/src/assets/aria-labels-google-snapshot.txt +49 -0
  116. package/src/assets/aria-labels-google.png +0 -0
  117. package/src/assets/aria-labels-hacker-news-snapshot.txt +1023 -0
  118. package/src/assets/aria-labels-hacker-news.png +0 -0
  119. package/src/cdp-relay.ts +925 -0
  120. package/src/cdp-session.ts +203 -0
  121. package/src/cdp-timing.md +128 -0
  122. package/src/cdp-types.ts +155 -0
  123. package/src/cli.ts +250 -0
  124. package/src/create-logger.ts +36 -0
  125. package/src/debugger-examples-types.ts +13 -0
  126. package/src/debugger-examples.ts +66 -0
  127. package/src/debugger.md +453 -0
  128. package/src/debugger.ts +713 -0
  129. package/src/editor-examples.ts +148 -0
  130. package/src/editor.ts +390 -0
  131. package/src/execute.ts +763 -0
  132. package/src/index.ts +10 -0
  133. package/src/mcp-client.ts +78 -0
  134. package/src/mcp.test.ts +3596 -0
  135. package/src/mcp.ts +876 -0
  136. package/src/network-capture.ts +140 -0
  137. package/src/prompt.bak.md +323 -0
  138. package/src/prompt.md +7 -0
  139. package/src/protocol.ts +63 -0
  140. package/src/react-source.ts +94 -0
  141. package/src/resource.md +436 -0
  142. package/src/scoped-fs.ts +411 -0
  143. package/src/snapshots/hacker-news-focused-accessibility.md +202 -0
  144. package/src/snapshots/hacker-news-initial-accessibility.md +11 -0
  145. package/src/snapshots/hacker-news-tabbed-accessibility.md +202 -0
  146. package/src/snapshots/shadcn-ui-accessibility.md +11 -0
  147. package/src/start-relay-server.ts +43 -0
  148. package/src/styles-examples.ts +77 -0
  149. package/src/styles.ts +345 -0
  150. package/src/trace-utils.ts +43 -0
  151. package/src/utils.ts +91 -0
  152. package/src/wait-for-page-load.ts +174 -0
@@ -0,0 +1,411 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+ import os from 'node:os'
4
+
5
+ /**
6
+ * A sandboxed fs wrapper that restricts all file operations to allowed directories.
7
+ * Any attempt to access files outside the allowed directories will throw an EPERM error.
8
+ *
9
+ * By default, allows access to:
10
+ * - Current working directory (process.cwd())
11
+ * - /tmp
12
+ * - os.tmpdir()
13
+ *
14
+ * This is used in the MCP VM context to prevent agents from accessing sensitive system files.
15
+ */
16
+ export class ScopedFS {
17
+ private allowedDirs: string[]
18
+
19
+ constructor(allowedDirs?: string[]) {
20
+ // Default allowed directories: cwd, /tmp, os.tmpdir()
21
+ const defaultDirs = [process.cwd(), '/tmp', os.tmpdir()]
22
+
23
+ // Use provided dirs or defaults, resolve all to absolute paths
24
+ const dirs = allowedDirs ?? defaultDirs
25
+ this.allowedDirs = [...new Set(dirs.map((d) => path.resolve(d)))]
26
+ }
27
+
28
+ /**
29
+ * Check if a resolved path is within any of the allowed directories.
30
+ */
31
+ private isPathAllowed(resolved: string): boolean {
32
+ return this.allowedDirs.some((dir) => {
33
+ return resolved === dir || resolved.startsWith(dir + path.sep)
34
+ })
35
+ }
36
+
37
+ /**
38
+ * Resolve a path and ensure it stays within allowed directories.
39
+ * Throws EPERM if the resolved path escapes the sandbox.
40
+ */
41
+ private resolvePath(filePath: string): string {
42
+ // If it's an absolute path, use it directly
43
+ // If it's relative, resolve from cwd
44
+ const resolved = path.resolve(filePath)
45
+
46
+ if (!this.isPathAllowed(resolved)) {
47
+ const error = new Error(
48
+ `EPERM: operation not permitted, access outside allowed directories: ${filePath}`,
49
+ ) as NodeJS.ErrnoException
50
+ error.code = 'EPERM'
51
+ error.errno = -1
52
+ error.syscall = 'access'
53
+ error.path = filePath
54
+ throw error
55
+ }
56
+ return resolved
57
+ }
58
+
59
+ // Sync methods
60
+
61
+ readFileSync = (filePath: fs.PathOrFileDescriptor, options?: any): any => {
62
+ const resolved = this.resolvePath(filePath.toString())
63
+ return fs.readFileSync(resolved, options)
64
+ }
65
+
66
+ writeFileSync = (filePath: fs.PathOrFileDescriptor, data: any, options?: any): void => {
67
+ const resolved = this.resolvePath(filePath.toString())
68
+ fs.writeFileSync(resolved, data, options)
69
+ }
70
+
71
+ appendFileSync = (filePath: fs.PathOrFileDescriptor, data: any, options?: any): void => {
72
+ const resolved = this.resolvePath(filePath.toString())
73
+ fs.appendFileSync(resolved, data, options)
74
+ }
75
+
76
+ readdirSync = (dirPath: fs.PathLike, options?: any): any => {
77
+ const resolved = this.resolvePath(dirPath.toString())
78
+ return fs.readdirSync(resolved, options)
79
+ }
80
+
81
+ mkdirSync = (dirPath: fs.PathLike, options?: any): any => {
82
+ const resolved = this.resolvePath(dirPath.toString())
83
+ return fs.mkdirSync(resolved, options)
84
+ }
85
+
86
+ rmdirSync = (dirPath: fs.PathLike, options?: any): void => {
87
+ const resolved = this.resolvePath(dirPath.toString())
88
+ fs.rmdirSync(resolved, options)
89
+ }
90
+
91
+ unlinkSync = (filePath: fs.PathLike): void => {
92
+ const resolved = this.resolvePath(filePath.toString())
93
+ fs.unlinkSync(resolved)
94
+ }
95
+
96
+ statSync = (filePath: fs.PathLike, options?: any): any => {
97
+ const resolved = this.resolvePath(filePath.toString())
98
+ return fs.statSync(resolved, options)
99
+ }
100
+
101
+ lstatSync = (filePath: fs.PathLike, options?: any): any => {
102
+ const resolved = this.resolvePath(filePath.toString())
103
+ return fs.lstatSync(resolved, options)
104
+ }
105
+
106
+ existsSync = (filePath: fs.PathLike): boolean => {
107
+ try {
108
+ const resolved = this.resolvePath(filePath.toString())
109
+ return fs.existsSync(resolved)
110
+ } catch {
111
+ return false
112
+ }
113
+ }
114
+
115
+ accessSync = (filePath: fs.PathLike, mode?: number): void => {
116
+ const resolved = this.resolvePath(filePath.toString())
117
+ fs.accessSync(resolved, mode)
118
+ }
119
+
120
+ copyFileSync = (src: fs.PathLike, dest: fs.PathLike, mode?: number): void => {
121
+ const resolvedSrc = this.resolvePath(src.toString())
122
+ const resolvedDest = this.resolvePath(dest.toString())
123
+ fs.copyFileSync(resolvedSrc, resolvedDest, mode)
124
+ }
125
+
126
+ renameSync = (oldPath: fs.PathLike, newPath: fs.PathLike): void => {
127
+ const resolvedOld = this.resolvePath(oldPath.toString())
128
+ const resolvedNew = this.resolvePath(newPath.toString())
129
+ fs.renameSync(resolvedOld, resolvedNew)
130
+ }
131
+
132
+ chmodSync = (filePath: fs.PathLike, mode: fs.Mode): void => {
133
+ const resolved = this.resolvePath(filePath.toString())
134
+ fs.chmodSync(resolved, mode)
135
+ }
136
+
137
+ chownSync = (filePath: fs.PathLike, uid: number, gid: number): void => {
138
+ const resolved = this.resolvePath(filePath.toString())
139
+ fs.chownSync(resolved, uid, gid)
140
+ }
141
+
142
+ utimesSync = (filePath: fs.PathLike, atime: fs.TimeLike, mtime: fs.TimeLike): void => {
143
+ const resolved = this.resolvePath(filePath.toString())
144
+ fs.utimesSync(resolved, atime, mtime)
145
+ }
146
+
147
+ realpathSync = (filePath: fs.PathLike, options?: any): any => {
148
+ const resolved = this.resolvePath(filePath.toString())
149
+ const real = fs.realpathSync(resolved, options)
150
+ // Verify the real path is also within allowed directories (handles symlinks)
151
+ const realStr = real.toString()
152
+ if (!this.isPathAllowed(realStr)) {
153
+ const error = new Error(`EPERM: operation not permitted, realpath escapes allowed directories`) as NodeJS.ErrnoException
154
+ error.code = 'EPERM'
155
+ throw error
156
+ }
157
+ return real
158
+ }
159
+
160
+ readlinkSync = (filePath: fs.PathLike, options?: any): any => {
161
+ const resolved = this.resolvePath(filePath.toString())
162
+ return fs.readlinkSync(resolved, options)
163
+ }
164
+
165
+ symlinkSync = (target: fs.PathLike, linkPath: fs.PathLike, type?: fs.symlink.Type | null): void => {
166
+ const resolvedLink = this.resolvePath(linkPath.toString())
167
+ // Target is relative to link location, resolve it to check bounds
168
+ const linkDir = path.dirname(resolvedLink)
169
+ const resolvedTarget = path.resolve(linkDir, target.toString())
170
+ if (!this.isPathAllowed(resolvedTarget)) {
171
+ const error = new Error(`EPERM: operation not permitted, symlink target outside allowed directories`) as NodeJS.ErrnoException
172
+ error.code = 'EPERM'
173
+ throw error
174
+ }
175
+ fs.symlinkSync(target, resolvedLink, type)
176
+ }
177
+
178
+ rmSync = (filePath: fs.PathLike, options?: fs.RmOptions): void => {
179
+ const resolved = this.resolvePath(filePath.toString())
180
+ fs.rmSync(resolved, options)
181
+ }
182
+
183
+ // Async callback methods
184
+
185
+ readFile = (filePath: any, ...args: any[]): void => {
186
+ const resolved = this.resolvePath(filePath.toString())
187
+ ;(fs.readFile as any)(resolved, ...args)
188
+ }
189
+
190
+ writeFile = (filePath: any, data: any, ...args: any[]): void => {
191
+ const resolved = this.resolvePath(filePath.toString())
192
+ ;(fs.writeFile as any)(resolved, data, ...args)
193
+ }
194
+
195
+ appendFile = (filePath: any, data: any, ...args: any[]): void => {
196
+ const resolved = this.resolvePath(filePath.toString())
197
+ ;(fs.appendFile as any)(resolved, data, ...args)
198
+ }
199
+
200
+ readdir = (dirPath: any, ...args: any[]): void => {
201
+ const resolved = this.resolvePath(dirPath.toString())
202
+ ;(fs.readdir as any)(resolved, ...args)
203
+ }
204
+
205
+ mkdir = (dirPath: any, ...args: any[]): void => {
206
+ const resolved = this.resolvePath(dirPath.toString())
207
+ ;(fs.mkdir as any)(resolved, ...args)
208
+ }
209
+
210
+ rmdir = (dirPath: any, ...args: any[]): void => {
211
+ const resolved = this.resolvePath(dirPath.toString())
212
+ ;(fs.rmdir as any)(resolved, ...args)
213
+ }
214
+
215
+ unlink = (filePath: any, callback: any): void => {
216
+ const resolved = this.resolvePath(filePath.toString())
217
+ fs.unlink(resolved, callback)
218
+ }
219
+
220
+ stat = (filePath: any, ...args: any[]): void => {
221
+ const resolved = this.resolvePath(filePath.toString())
222
+ ;(fs.stat as any)(resolved, ...args)
223
+ }
224
+
225
+ lstat = (filePath: any, ...args: any[]): void => {
226
+ const resolved = this.resolvePath(filePath.toString())
227
+ ;(fs.lstat as any)(resolved, ...args)
228
+ }
229
+
230
+ access = (filePath: any, ...args: any[]): void => {
231
+ const resolved = this.resolvePath(filePath.toString())
232
+ ;(fs.access as any)(resolved, ...args)
233
+ }
234
+
235
+ copyFile = (src: any, dest: any, ...args: any[]): void => {
236
+ const resolvedSrc = this.resolvePath(src.toString())
237
+ const resolvedDest = this.resolvePath(dest.toString())
238
+ ;(fs.copyFile as any)(resolvedSrc, resolvedDest, ...args)
239
+ }
240
+
241
+ rename = (oldPath: any, newPath: any, callback: any): void => {
242
+ const resolvedOld = this.resolvePath(oldPath.toString())
243
+ const resolvedNew = this.resolvePath(newPath.toString())
244
+ fs.rename(resolvedOld, resolvedNew, callback)
245
+ }
246
+
247
+ chmod = (filePath: any, mode: any, callback: any): void => {
248
+ const resolved = this.resolvePath(filePath.toString())
249
+ fs.chmod(resolved, mode, callback)
250
+ }
251
+
252
+ chown = (filePath: any, uid: any, gid: any, callback: any): void => {
253
+ const resolved = this.resolvePath(filePath.toString())
254
+ fs.chown(resolved, uid, gid, callback)
255
+ }
256
+
257
+ rm = (filePath: any, ...args: any[]): void => {
258
+ const resolved = this.resolvePath(filePath.toString())
259
+ ;(fs.rm as any)(resolved, ...args)
260
+ }
261
+
262
+ exists = (filePath: any, callback: any): void => {
263
+ try {
264
+ const resolved = this.resolvePath(filePath.toString())
265
+ fs.exists(resolved, callback)
266
+ } catch {
267
+ callback(false)
268
+ }
269
+ }
270
+
271
+ // Stream methods
272
+
273
+ createReadStream = (filePath: fs.PathLike, options?: any): fs.ReadStream => {
274
+ const resolved = this.resolvePath(filePath.toString())
275
+ return fs.createReadStream(resolved, options)
276
+ }
277
+
278
+ createWriteStream = (filePath: fs.PathLike, options?: any): fs.WriteStream => {
279
+ const resolved = this.resolvePath(filePath.toString())
280
+ return fs.createWriteStream(resolved, options)
281
+ }
282
+
283
+ // Watch methods
284
+
285
+ watch = (filePath: any, ...args: any[]): fs.FSWatcher => {
286
+ const resolved = this.resolvePath(filePath.toString())
287
+ return (fs.watch as any)(resolved, ...args)
288
+ }
289
+
290
+ watchFile = (filePath: any, ...args: any[]): fs.StatWatcher => {
291
+ const resolved = this.resolvePath(filePath.toString())
292
+ return (fs.watchFile as any)(resolved, ...args)
293
+ }
294
+
295
+ unwatchFile = (filePath: any, listener?: any): void => {
296
+ const resolved = this.resolvePath(filePath.toString())
297
+ fs.unwatchFile(resolved, listener)
298
+ }
299
+
300
+ // Promise-based API (fs.promises equivalent)
301
+ get promises() {
302
+ const self = this
303
+ return {
304
+ readFile: async (filePath: fs.PathLike, options?: any) => {
305
+ const resolved = self.resolvePath(filePath.toString())
306
+ return fs.promises.readFile(resolved, options)
307
+ },
308
+ writeFile: async (filePath: fs.PathLike, data: any, options?: any) => {
309
+ const resolved = self.resolvePath(filePath.toString())
310
+ return fs.promises.writeFile(resolved, data, options)
311
+ },
312
+ appendFile: async (filePath: fs.PathLike, data: any, options?: any) => {
313
+ const resolved = self.resolvePath(filePath.toString())
314
+ return fs.promises.appendFile(resolved, data, options)
315
+ },
316
+ readdir: async (dirPath: fs.PathLike, options?: any) => {
317
+ const resolved = self.resolvePath(dirPath.toString())
318
+ return fs.promises.readdir(resolved, options)
319
+ },
320
+ mkdir: async (dirPath: fs.PathLike, options?: any) => {
321
+ const resolved = self.resolvePath(dirPath.toString())
322
+ return fs.promises.mkdir(resolved, options)
323
+ },
324
+ rmdir: async (dirPath: fs.PathLike, options?: any) => {
325
+ const resolved = self.resolvePath(dirPath.toString())
326
+ return fs.promises.rmdir(resolved, options)
327
+ },
328
+ unlink: async (filePath: fs.PathLike) => {
329
+ const resolved = self.resolvePath(filePath.toString())
330
+ return fs.promises.unlink(resolved)
331
+ },
332
+ stat: async (filePath: fs.PathLike, options?: any) => {
333
+ const resolved = self.resolvePath(filePath.toString())
334
+ return fs.promises.stat(resolved, options)
335
+ },
336
+ lstat: async (filePath: fs.PathLike, options?: any) => {
337
+ const resolved = self.resolvePath(filePath.toString())
338
+ return fs.promises.lstat(resolved, options)
339
+ },
340
+ access: async (filePath: fs.PathLike, mode?: number) => {
341
+ const resolved = self.resolvePath(filePath.toString())
342
+ return fs.promises.access(resolved, mode)
343
+ },
344
+ copyFile: async (src: fs.PathLike, dest: fs.PathLike, mode?: number) => {
345
+ const resolved = self.resolvePath(src.toString())
346
+ const resolvedDest = self.resolvePath(dest.toString())
347
+ return fs.promises.copyFile(resolved, resolvedDest, mode)
348
+ },
349
+ rename: async (oldPath: fs.PathLike, newPath: fs.PathLike) => {
350
+ const resolvedOld = self.resolvePath(oldPath.toString())
351
+ const resolvedNew = self.resolvePath(newPath.toString())
352
+ return fs.promises.rename(resolvedOld, resolvedNew)
353
+ },
354
+ chmod: async (filePath: fs.PathLike, mode: fs.Mode) => {
355
+ const resolved = self.resolvePath(filePath.toString())
356
+ return fs.promises.chmod(resolved, mode)
357
+ },
358
+ chown: async (filePath: fs.PathLike, uid: number, gid: number) => {
359
+ const resolved = self.resolvePath(filePath.toString())
360
+ return fs.promises.chown(resolved, uid, gid)
361
+ },
362
+ rm: async (filePath: fs.PathLike, options?: fs.RmOptions) => {
363
+ const resolved = self.resolvePath(filePath.toString())
364
+ return fs.promises.rm(resolved, options)
365
+ },
366
+ realpath: async (filePath: fs.PathLike, options?: any) => {
367
+ const resolved = self.resolvePath(filePath.toString())
368
+ const real = await fs.promises.realpath(resolved, options)
369
+ const realStr = real.toString()
370
+ if (!self.isPathAllowed(realStr)) {
371
+ const error = new Error(`EPERM: operation not permitted, realpath escapes allowed directories`) as NodeJS.ErrnoException
372
+ error.code = 'EPERM'
373
+ throw error
374
+ }
375
+ return real
376
+ },
377
+ readlink: async (filePath: fs.PathLike, options?: any) => {
378
+ const resolved = self.resolvePath(filePath.toString())
379
+ return fs.promises.readlink(resolved, options)
380
+ },
381
+ symlink: async (target: fs.PathLike, linkPath: fs.PathLike, type?: string) => {
382
+ const resolvedLink = self.resolvePath(linkPath.toString())
383
+ const linkDir = path.dirname(resolvedLink)
384
+ const resolvedTarget = path.resolve(linkDir, target.toString())
385
+ if (!self.isPathAllowed(resolvedTarget)) {
386
+ const error = new Error(
387
+ `EPERM: operation not permitted, symlink target outside allowed directories`,
388
+ ) as NodeJS.ErrnoException
389
+ error.code = 'EPERM'
390
+ throw error
391
+ }
392
+ return fs.promises.symlink(target, resolvedLink, type as any)
393
+ },
394
+ utimes: async (filePath: fs.PathLike, atime: fs.TimeLike, mtime: fs.TimeLike) => {
395
+ const resolved = self.resolvePath(filePath.toString())
396
+ return fs.promises.utimes(resolved, atime, mtime)
397
+ },
398
+ }
399
+ }
400
+
401
+ // Constants passthrough
402
+ constants = fs.constants
403
+ }
404
+
405
+ /**
406
+ * Create a scoped fs instance with allowed directories.
407
+ * Defaults to cwd, /tmp, and os.tmpdir() if no directories specified.
408
+ */
409
+ export function createScopedFS(allowedDirs?: string[]): ScopedFS {
410
+ return new ScopedFS(allowedDirs)
411
+ }
@@ -0,0 +1,202 @@
1
+ - table [ref=e3]:
2
+ - rowgroup [ref=e4]:
3
+ - row "Hacker Newsnew | past | comments | ask | show | jobs | submit login" [ref=e5]:
4
+ - cell "Hacker Newsnew | past | comments | ask | show | jobs | submit login" [ref=e6]:
5
+ - table [ref=e7]:
6
+ - rowgroup [ref=e8]:
7
+ - row "Hacker Newsnew | past | comments | ask | show | jobs | submit login" [ref=e9]:
8
+ - cell [ref=e10]:
9
+ - link [active] [ref=e11] [cursor=pointer]:
10
+ - /url: https://news.ycombinator.com
11
+ - img [ref=e12] [cursor=pointer]
12
+ - cell "Hacker Newsnew | past | comments | ask | show | jobs | submit" [ref=e13]:
13
+ - generic [ref=e14]:
14
+ - link "Hacker News" [ref=e16] [cursor=pointer]:
15
+ - /url: news
16
+ - link "new" [ref=e17] [cursor=pointer]:
17
+ - /url: newest
18
+ - text: "|"
19
+ - link "past" [ref=e18] [cursor=pointer]:
20
+ - /url: front
21
+ - text: "|"
22
+ - link "comments" [ref=e19] [cursor=pointer]:
23
+ - /url: newcomments
24
+ - text: "|"
25
+ - link "ask" [ref=e20] [cursor=pointer]:
26
+ - /url: ask
27
+ - text: "|"
28
+ - link "show" [ref=e21] [cursor=pointer]:
29
+ - /url: show
30
+ - text: "|"
31
+ - link "jobs" [ref=e22] [cursor=pointer]:
32
+ - /url: jobs
33
+ - text: "|"
34
+ - link "submit" [ref=e23] [cursor=pointer]:
35
+ - /url: submit
36
+ - cell "login" [ref=e24]:
37
+ - link "login" [ref=e26] [cursor=pointer]:
38
+ - /url: login?goto=item%3Fid%3D1
39
+ - row [ref=e27]
40
+ - row "upvote Y Combinator (ycombinator.com) 57 points by pg on Oct 9, 2006 | hide | past | favorite | 3 comments upvote sama on Oct 9, 2006 [–] \"the rising star of venture capital\" -unknown VC eating lunch on SHR upvote pg on Oct 9, 2006 | [–] Is there anywhere to eat on Sandhill Road? upvote dmon on Feb 25, 2007 | | [–] sure" [ref=e28]:
41
+ - cell "upvote Y Combinator (ycombinator.com) 57 points by pg on Oct 9, 2006 | hide | past | favorite | 3 comments upvote sama on Oct 9, 2006 [–] \"the rising star of venture capital\" -unknown VC eating lunch on SHR upvote pg on Oct 9, 2006 | [–] Is there anywhere to eat on Sandhill Road? upvote dmon on Feb 25, 2007 | | [–] sure" [ref=e29]:
42
+ - table [ref=e30]:
43
+ - rowgroup [ref=e31]:
44
+ - row "upvote Y Combinator (ycombinator.com)" [ref=e32]:
45
+ - cell [ref=e33]
46
+ - cell "upvote" [ref=e35]:
47
+ - link "upvote" [ref=e37] [cursor=pointer]:
48
+ - /url: vote?id=1&how=up&goto=item%3Fid%3D1
49
+ - cell "Y Combinator (ycombinator.com)" [ref=e39]:
50
+ - generic [ref=e40]:
51
+ - link "Y Combinator" [ref=e41] [cursor=pointer]:
52
+ - /url: http://ycombinator.com
53
+ - generic [ref=e42]:
54
+ - text: (
55
+ - link "ycombinator.com" [ref=e43] [cursor=pointer]:
56
+ - /url: from?site=ycombinator.com
57
+ - generic [ref=e44] [cursor=pointer]: ycombinator.com
58
+ - text: )
59
+ - row "57 points by pg on Oct 9, 2006 | hide | past | favorite | 3 comments" [ref=e45]:
60
+ - cell [ref=e46]
61
+ - cell "57 points by pg on Oct 9, 2006 | hide | past | favorite | 3 comments" [ref=e47]:
62
+ - generic [ref=e48]:
63
+ - generic [ref=e49]: 57 points
64
+ - text: by
65
+ - link "pg" [ref=e50] [cursor=pointer]:
66
+ - /url: user?id=pg
67
+ - link "on Oct 9, 2006" [ref=e52] [cursor=pointer]:
68
+ - /url: item?id=1
69
+ - text: "|"
70
+ - link "hide" [ref=e54] [cursor=pointer]:
71
+ - /url: hide?id=1&goto=item%3Fid%3D1
72
+ - text: "|"
73
+ - link "past" [ref=e55] [cursor=pointer]:
74
+ - /url: https://hn.algolia.com/?query=Y%20Combinator&type=story&dateRange=all&sort=byDate&storyText=false&prefix&page=0
75
+ - text: "|"
76
+ - link "favorite" [ref=e56] [cursor=pointer]:
77
+ - /url: fave?id=1&auth=5328fcfde7333d68e67a8a2334e25acee5599932
78
+ - text: "|"
79
+ - link "3 comments" [ref=e57] [cursor=pointer]:
80
+ - /url: item?id=1
81
+ - row [ref=e58]:
82
+ - cell [ref=e59]
83
+ - cell [ref=e60]
84
+ - table [ref=e63]:
85
+ - rowgroup [ref=e64]:
86
+ - row "upvote sama on Oct 9, 2006 [–] \"the rising star of venture capital\" -unknown VC eating lunch on SHR" [ref=e65]:
87
+ - cell "upvote sama on Oct 9, 2006 [–] \"the rising star of venture capital\" -unknown VC eating lunch on SHR" [ref=e66]:
88
+ - table [ref=e67]:
89
+ - rowgroup [ref=e68]:
90
+ - row "upvote sama on Oct 9, 2006 [–] \"the rising star of venture capital\" -unknown VC eating lunch on SHR" [ref=e69]:
91
+ - cell [ref=e70]:
92
+ - img
93
+ - cell "upvote" [ref=e72]:
94
+ - link "upvote" [ref=e74] [cursor=pointer]:
95
+ - /url: vote?id=15&how=up&goto=item%3Fid%3D1
96
+ - cell "sama on Oct 9, 2006 [–] \"the rising star of venture capital\" -unknown VC eating lunch on SHR" [ref=e76]:
97
+ - generic [ref=e78]:
98
+ - link "sama" [ref=e79] [cursor=pointer]:
99
+ - /url: user?id=sama
100
+ - link "on Oct 9, 2006" [ref=e81] [cursor=pointer]:
101
+ - /url: item?id=15
102
+ - link "[–]" [ref=e84] [cursor=pointer]:
103
+ - /url: javascript:void(0)
104
+ - generic [ref=e87]:
105
+ - generic [ref=e88]: "\"the rising star of venture capital\" -unknown VC eating lunch on SHR"
106
+ - generic:
107
+ - paragraph
108
+ - row "upvote pg on Oct 9, 2006 | [–] Is there anywhere to eat on Sandhill Road?" [ref=e92]:
109
+ - cell "upvote pg on Oct 9, 2006 | [–] Is there anywhere to eat on Sandhill Road?" [ref=e93]:
110
+ - table [ref=e94]:
111
+ - rowgroup [ref=e95]:
112
+ - row "upvote pg on Oct 9, 2006 | [–] Is there anywhere to eat on Sandhill Road?" [ref=e96]:
113
+ - cell [ref=e97]:
114
+ - img [ref=e98]
115
+ - cell "upvote" [ref=e99]:
116
+ - link "upvote" [ref=e101] [cursor=pointer]:
117
+ - /url: vote?id=17&how=up&goto=item%3Fid%3D1
118
+ - cell "pg on Oct 9, 2006 | [–] Is there anywhere to eat on Sandhill Road?" [ref=e103]:
119
+ - generic [ref=e105]:
120
+ - link "pg" [ref=e106] [cursor=pointer]:
121
+ - /url: user?id=pg
122
+ - link "on Oct 9, 2006" [ref=e108] [cursor=pointer]:
123
+ - /url: item?id=17
124
+ - generic [ref=e110]:
125
+ - text: "|"
126
+ - link [ref=e111] [cursor=pointer]:
127
+ - /url: "#15"
128
+ - text: parent
129
+ - link "[–]" [ref=e112] [cursor=pointer]:
130
+ - /url: javascript:void(0)
131
+ - generic [ref=e115]:
132
+ - generic [ref=e116]: Is there anywhere to eat on Sandhill Road?
133
+ - generic:
134
+ - paragraph
135
+ - row "upvote dmon on Feb 25, 2007 | | [–] sure" [ref=e120]:
136
+ - cell "upvote dmon on Feb 25, 2007 | | [–] sure" [ref=e121]:
137
+ - table [ref=e122]:
138
+ - rowgroup [ref=e123]:
139
+ - row "upvote dmon on Feb 25, 2007 | | [–] sure" [ref=e124]:
140
+ - cell [ref=e125]:
141
+ - img [ref=e126]
142
+ - cell "upvote" [ref=e127]:
143
+ - link "upvote" [ref=e129] [cursor=pointer]:
144
+ - /url: vote?id=1079&how=up&goto=item%3Fid%3D1
145
+ - cell "dmon on Feb 25, 2007 | | [–] sure" [ref=e131]:
146
+ - generic [ref=e133]:
147
+ - link "dmon" [ref=e134] [cursor=pointer]:
148
+ - /url: user?id=dmon
149
+ - link "on Feb 25, 2007" [ref=e136] [cursor=pointer]:
150
+ - /url: item?id=1079
151
+ - generic [ref=e138]:
152
+ - text: "|"
153
+ - link [ref=e139] [cursor=pointer]:
154
+ - /url: "#15"
155
+ - text: root
156
+ - text: "|"
157
+ - link [ref=e140] [cursor=pointer]:
158
+ - /url: "#17"
159
+ - text: parent
160
+ - link "[–]" [ref=e141] [cursor=pointer]:
161
+ - /url: javascript:void(0)
162
+ - generic [ref=e144]:
163
+ - generic [ref=e145]: sure
164
+ - generic:
165
+ - paragraph
166
+ - row "Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4 Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact Search:" [ref=e151]:
167
+ - cell "Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4 Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact Search:" [ref=e152]:
168
+ - img
169
+ - table [ref=e154]:
170
+ - rowgroup [ref=e155]:
171
+ - row [ref=e156]:
172
+ - cell [ref=e157]
173
+ - link "Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4" [ref=e160] [cursor=pointer]:
174
+ - /url: https://www.ycombinator.com/apply/
175
+ - generic [ref=e162]:
176
+ - generic [ref=e163]:
177
+ - link "Guidelines" [ref=e164] [cursor=pointer]:
178
+ - /url: newsguidelines.html
179
+ - text: "|"
180
+ - link "FAQ" [ref=e165] [cursor=pointer]:
181
+ - /url: newsfaq.html
182
+ - text: "|"
183
+ - link "Lists" [ref=e166] [cursor=pointer]:
184
+ - /url: lists
185
+ - text: "|"
186
+ - link "API" [ref=e167] [cursor=pointer]:
187
+ - /url: https://github.com/HackerNews/API
188
+ - text: "|"
189
+ - link "Security" [ref=e168] [cursor=pointer]:
190
+ - /url: security.html
191
+ - text: "|"
192
+ - link "Legal" [ref=e169] [cursor=pointer]:
193
+ - /url: https://www.ycombinator.com/legal/
194
+ - text: "|"
195
+ - link "Apply to YC" [ref=e170] [cursor=pointer]:
196
+ - /url: https://www.ycombinator.com/apply/
197
+ - text: "|"
198
+ - link "Contact" [ref=e171] [cursor=pointer]:
199
+ - /url: mailto:hn@ycombinator.com
200
+ - generic [ref=e174]:
201
+ - text: "Search:"
202
+ - textbox [ref=e175]
@@ -0,0 +1,11 @@
1
+ MCP error -32602: Input validation error: Invalid arguments for tool execute: [
2
+ {
3
+ "code": "invalid_type",
4
+ "expected": "string",
5
+ "received": "undefined",
6
+ "path": [
7
+ "intend"
8
+ ],
9
+ "message": "Required"
10
+ }
11
+ ]