@namzu/sdk 35.0.0 → 36.0.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.
- package/CHANGELOG.md +38 -0
- package/dist/provider/token-budget.d.ts.map +1 -1
- package/dist/provider/token-budget.js +56 -8
- package/dist/provider/token-budget.js.map +1 -1
- package/dist/public-runtime.d.ts +2 -2
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +1 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +1 -0
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +50 -10
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +7 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +1 -0
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +3 -3
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +31 -6
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +2 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +10 -5
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js +14 -4
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/sandbox/file-walk-program.d.ts +3 -0
- package/dist/sandbox/file-walk-program.d.ts.map +1 -0
- package/dist/sandbox/file-walk-program.js +94 -0
- package/dist/sandbox/file-walk-program.js.map +1 -0
- package/dist/sandbox/file-walk.d.ts +12 -0
- package/dist/sandbox/file-walk.d.ts.map +1 -0
- package/dist/sandbox/file-walk.js +429 -0
- package/dist/sandbox/file-walk.js.map +1 -0
- package/dist/sandbox/index.d.ts +2 -0
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +1 -0
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +9 -0
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts +3 -2
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +29 -15
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +215 -59
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/glob.d.ts +2 -1
- package/dist/tools/builtins/glob.d.ts.map +1 -1
- package/dist/tools/builtins/glob.js +95 -103
- package/dist/tools/builtins/glob.js.map +1 -1
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +155 -111
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/ls.js +2 -2
- package/dist/tools/builtins/ls.js.map +1 -1
- package/dist/types/sandbox/index.d.ts +20 -0
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/package.json +6 -1
- package/src/provider/token-budget.ts +52 -8
- package/src/public-runtime.ts +2 -1
- package/src/runtime/query/executor.ts +54 -14
- package/src/runtime/query/index.ts +8 -0
- package/src/runtime/query/iteration/index.ts +29 -9
- package/src/runtime/query/iteration/phases/context.ts +2 -0
- package/src/runtime/query/iteration/stream-turn.ts +9 -5
- package/src/runtime/query/prompt.ts +21 -4
- package/src/sandbox/file-walk-program.ts +93 -0
- package/src/sandbox/file-walk.ts +463 -0
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/provider/local.ts +13 -0
- package/src/scheduler/completion-inbox.ts +29 -19
- package/src/tools/builtins/bash.ts +230 -58
- package/src/tools/builtins/glob.ts +104 -122
- package/src/tools/builtins/grep.ts +166 -132
- package/src/tools/builtins/ls.ts +2 -2
- package/src/types/sandbox/index.ts +21 -0
|
@@ -1,60 +1,54 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import { isAbsolute, join, relative, sep } from 'node:path'
|
|
3
3
|
import { z } from 'zod'
|
|
4
|
-
import
|
|
4
|
+
import { walkFilesLocally } from '../../sandbox/file-walk.js'
|
|
5
|
+
import type { SandboxWalkFilesOptions } from '../../types/sandbox/index.js'
|
|
6
|
+
import { subscribeToAbort } from '../../utils/abort.js'
|
|
5
7
|
import { defineTool } from '../defineTool.js'
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* and read — so that is all this abstracts. Matching, context lines and
|
|
15
|
-
* the caps stay in one implementation; duplicating them per source is how
|
|
16
|
-
* the two would drift apart, and the sandbox path is the one nobody runs
|
|
17
|
-
* by accident.
|
|
18
|
-
*/
|
|
19
|
-
interface FileSource {
|
|
20
|
-
/** The root every reported path is relative to. */
|
|
21
|
-
readonly root: string
|
|
22
|
-
/** True when paths are the sandbox's, not the host's. */
|
|
23
|
-
readonly posix?: boolean
|
|
24
|
-
list(searchRoot: string, pattern: string): AsyncIterable<string>
|
|
25
|
-
read(path: string): Promise<Buffer>
|
|
26
|
-
}
|
|
8
|
+
import {
|
|
9
|
+
resolveWithin,
|
|
10
|
+
resolveWithinAny,
|
|
11
|
+
resolveWithinAnyReal,
|
|
12
|
+
resolveWithinReal,
|
|
13
|
+
toolRoots,
|
|
14
|
+
} from '../paths.js'
|
|
15
|
+
import { relativePosix, resolveWithinPosix } from '../posix-path.js'
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
17
|
+
/** A remote read has no signal parameter; stop consuming it when the turn ends. */
|
|
18
|
+
async function readWithSignal(read: () => Promise<Buffer>, signal?: AbortSignal): Promise<Buffer> {
|
|
19
|
+
signal?.throwIfAborted()
|
|
20
|
+
if (!signal) return await read()
|
|
21
|
+
let dispose: (() => void) | undefined
|
|
22
|
+
try {
|
|
23
|
+
const cancelled = new Promise<never>((_, reject) => {
|
|
24
|
+
dispose = subscribeToAbort(signal, () => reject(signal.reason))
|
|
25
|
+
})
|
|
26
|
+
// Promise.race observes any late rejection. A late buffer is never searched.
|
|
27
|
+
return await Promise.race([
|
|
28
|
+
Promise.resolve().then(() => {
|
|
29
|
+
signal.throwIfAborted()
|
|
30
|
+
return read()
|
|
31
|
+
}),
|
|
32
|
+
cancelled,
|
|
33
|
+
])
|
|
34
|
+
} finally {
|
|
35
|
+
dispose?.()
|
|
37
36
|
}
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// two disagree, and then hand the model a path its own
|
|
50
|
-
// sandbox cannot open.
|
|
51
|
-
const absolute = joinPosix(searchRoot, entry.path)
|
|
52
|
-
const relPath = relativePosix(sandbox.rootDir, absolute)
|
|
53
|
-
if (matchesGlob(relPath, pattern)) yield absolute
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
read: (path) => sandbox.readFile(path),
|
|
39
|
+
function relativeInclude(include: string, root: string, sandboxed: boolean): string {
|
|
40
|
+
let pattern = sandboxed ? include : include.split(sep).join('/')
|
|
41
|
+
if (pattern.split('/').includes('..'))
|
|
42
|
+
throw new Error('Include pattern escapes the search directory')
|
|
43
|
+
if (sandboxed ? pattern.startsWith('/') : isAbsolute(include)) {
|
|
44
|
+
const absolute = sandboxed ? resolveWithinPosix(root, pattern) : resolveWithin(root, include)
|
|
45
|
+
pattern = sandboxed
|
|
46
|
+
? relativePosix(root, absolute)
|
|
47
|
+
: relative(root, absolute).split(sep).join('/')
|
|
57
48
|
}
|
|
49
|
+
while (pattern.startsWith('./')) pattern = pattern.slice(2)
|
|
50
|
+
// Grep's existing unqualified include is recursive: *.ts means **/*.ts.
|
|
51
|
+
return pattern.includes('/') ? pattern : `**/${pattern}`
|
|
58
52
|
}
|
|
59
53
|
|
|
60
54
|
const inputSchema = z.object({
|
|
@@ -84,6 +78,7 @@ const inputSchema = z.object({
|
|
|
84
78
|
|
|
85
79
|
const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5 MB — skip binaries/large files
|
|
86
80
|
const BINARY_CHECK_BYTES = 512
|
|
81
|
+
const MAX_VISITED_ENTRIES = 20_000
|
|
87
82
|
|
|
88
83
|
function isBinaryContent(buffer: Buffer): boolean {
|
|
89
84
|
const check = buffer.subarray(0, BINARY_CHECK_BYTES)
|
|
@@ -96,15 +91,17 @@ function isBinaryContent(buffer: Buffer): boolean {
|
|
|
96
91
|
export const GrepTool = defineTool({
|
|
97
92
|
name: 'grep',
|
|
98
93
|
description:
|
|
99
|
-
'Searches file contents using a regular expression. Returns matching lines with file paths, line numbers, and optional context lines. Skips binary files.',
|
|
94
|
+
'Searches file contents using a regular expression. Returns matching lines with file paths, line numbers, and optional context lines. Searches incrementally with a bounded traversal; identifies incomplete searches. Skips binary files, files over 5 MB, and symlinks. Choose the narrowest relevant directory.',
|
|
100
95
|
inputSchema,
|
|
101
96
|
category: 'analysis',
|
|
102
97
|
permissions: ['file_read'],
|
|
103
98
|
readOnly: true,
|
|
104
99
|
destructive: false,
|
|
105
100
|
concurrencySafe: true,
|
|
101
|
+
timeoutMs: 15_000,
|
|
106
102
|
|
|
107
103
|
async execute(input, context) {
|
|
104
|
+
context.abortSignal?.throwIfAborted()
|
|
108
105
|
const flags = input.case_sensitive ? 'g' : 'gi'
|
|
109
106
|
let regex: RegExp
|
|
110
107
|
try {
|
|
@@ -117,108 +114,145 @@ export const GrepTool = defineTool({
|
|
|
117
114
|
}
|
|
118
115
|
}
|
|
119
116
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
filePattern = `**/${filePattern}`
|
|
117
|
+
const sandbox = context.sandbox
|
|
118
|
+
const lexicalRoot = sandbox
|
|
119
|
+
? resolveWithinPosix(sandbox.rootDir, input.path)
|
|
120
|
+
: resolveWithinAny(toolRoots(context), input.path)
|
|
121
|
+
const root = sandbox ? lexicalRoot : await resolveWithinAnyReal(toolRoots(context), input.path)
|
|
122
|
+
const filePattern = relativeInclude(input.include ?? '**/*', lexicalRoot, sandbox !== undefined)
|
|
123
|
+
const walkSandbox = sandbox?.walkFiles?.bind(sandbox)
|
|
124
|
+
if (sandbox && !walkSandbox) {
|
|
125
|
+
return {
|
|
126
|
+
success: false,
|
|
127
|
+
output: '',
|
|
128
|
+
error:
|
|
129
|
+
'This sandbox does not support bounded file discovery (Sandbox.walkFiles). Update its adapter before searching file contents.',
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const options: SandboxWalkFilesOptions = {
|
|
133
|
+
pattern: filePattern,
|
|
134
|
+
signal: context.abortSignal,
|
|
135
|
+
maxEntries: MAX_VISITED_ENTRIES + 1,
|
|
136
|
+
maxVisitedEntries: MAX_VISITED_ENTRIES,
|
|
137
|
+
// Preserve existing source behavior: sandbox grep included dotfiles;
|
|
138
|
+
// node's host glob excluded wildcard dotfiles.
|
|
139
|
+
includeHidden: sandbox !== undefined,
|
|
144
140
|
}
|
|
141
|
+
const entries = walkSandbox ? walkSandbox(root, options) : walkFilesLocally(root, options)
|
|
145
142
|
|
|
146
143
|
const results: string[] = []
|
|
147
144
|
let totalMatches = 0
|
|
148
145
|
let filesSearched = 0
|
|
149
146
|
let filesMatched = 0
|
|
150
147
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
for (let i = 0; i < lines.length; i++) {
|
|
168
|
-
const line = lines[i] ?? ''
|
|
169
|
-
regex.lastIndex = 0
|
|
170
|
-
if (!regex.test(line)) continue
|
|
148
|
+
let truncated = false
|
|
149
|
+
let failure: string | undefined
|
|
150
|
+
let unreadableFiles = 0
|
|
151
|
+
try {
|
|
152
|
+
for await (const entry of entries) {
|
|
153
|
+
context.abortSignal?.throwIfAborted()
|
|
154
|
+
const filePath = sandbox
|
|
155
|
+
? resolveWithinPosix(root, entry.path)
|
|
156
|
+
: resolveWithin(root, entry.path)
|
|
157
|
+
if (filesSearched >= MAX_VISITED_ENTRIES) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`File search stopped after examining ${MAX_VISITED_ENTRIES} files; narrow its root or include pattern.`,
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
filesSearched++
|
|
163
|
+
if (entry.size > MAX_FILE_SIZE) continue
|
|
171
164
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
165
|
+
let content: string
|
|
166
|
+
try {
|
|
167
|
+
const buffer = await readWithSignal(
|
|
168
|
+
() =>
|
|
169
|
+
sandbox
|
|
170
|
+
? sandbox.readFile(filePath)
|
|
171
|
+
: resolveWithinReal(root, filePath).then((contained) =>
|
|
172
|
+
readFile(contained, { signal: context.abortSignal }),
|
|
173
|
+
),
|
|
174
|
+
context.abortSignal,
|
|
175
|
+
)
|
|
176
|
+
context.abortSignal?.throwIfAborted()
|
|
177
|
+
if (buffer.length > MAX_FILE_SIZE || isBinaryContent(buffer)) continue
|
|
178
|
+
content = buffer.toString('utf-8')
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (context.abortSignal?.aborted) throw error
|
|
181
|
+
unreadableFiles++
|
|
182
|
+
continue
|
|
175
183
|
}
|
|
176
184
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// hand the model a string `read` then resolves somewhere else.
|
|
180
|
-
const relPath = source.posix
|
|
181
|
-
? `./${relativePosix(source.root, filePath)}`
|
|
182
|
-
: `./${relative(source.root, filePath).split(sep).join('/')}`
|
|
185
|
+
const lines = content.split('\n')
|
|
186
|
+
let fileHasMatch = false
|
|
183
187
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const
|
|
188
|
+
for (let i = 0; i < lines.length; i++) {
|
|
189
|
+
context.abortSignal?.throwIfAborted()
|
|
190
|
+
const line = lines[i] ?? ''
|
|
191
|
+
regex.lastIndex = 0
|
|
192
|
+
if (!regex.test(line)) continue
|
|
187
193
|
|
|
188
|
-
if (
|
|
189
|
-
|
|
194
|
+
if (!fileHasMatch) {
|
|
195
|
+
fileHasMatch = true
|
|
196
|
+
filesMatched++
|
|
190
197
|
}
|
|
191
198
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
199
|
+
const relPath = sandbox
|
|
200
|
+
? `./${relativePosix(sandbox.rootDir, filePath)}`
|
|
201
|
+
: `./${relative(context.workingDirectory, join(lexicalRoot, relative(root, filePath)))
|
|
202
|
+
.split(sep)
|
|
203
|
+
.join('/')}`
|
|
204
|
+
|
|
205
|
+
if (input.context_lines > 0) {
|
|
206
|
+
const start = Math.max(0, i - input.context_lines)
|
|
207
|
+
const end = Math.min(lines.length - 1, i + input.context_lines)
|
|
208
|
+
|
|
209
|
+
if (results.length > 0) {
|
|
210
|
+
results.push('--')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (let j = start; j <= end; j++) {
|
|
214
|
+
const prefix = j === i ? ':' : '-'
|
|
215
|
+
results.push(`${relPath}${prefix}${j + 1}${prefix}${lines[j]}`)
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
results.push(`${relPath}:${i + 1}:${line}`)
|
|
195
219
|
}
|
|
196
|
-
|
|
197
|
-
|
|
220
|
+
|
|
221
|
+
totalMatches++
|
|
222
|
+
if (totalMatches >= input.max_results) break
|
|
198
223
|
}
|
|
199
224
|
|
|
200
|
-
totalMatches
|
|
201
|
-
|
|
225
|
+
if (totalMatches >= input.max_results) {
|
|
226
|
+
// Do not read another file just to prove there are more hits. Reaching
|
|
227
|
+
// the requested cap means completeness was not established.
|
|
228
|
+
truncated = true
|
|
229
|
+
break
|
|
230
|
+
}
|
|
202
231
|
}
|
|
203
|
-
|
|
204
|
-
|
|
232
|
+
} catch (error) {
|
|
233
|
+
truncated = true
|
|
234
|
+
failure = (error instanceof Error ? error.message : String(error)) || 'File search failed.'
|
|
205
235
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
success: true,
|
|
210
|
-
output: `No matches found for pattern "${input.pattern}"`,
|
|
211
|
-
data: { totalMatches: 0, filesSearched, filesMatched: 0 },
|
|
212
|
-
}
|
|
236
|
+
if (unreadableFiles > 0) {
|
|
237
|
+
truncated = true
|
|
238
|
+
failure ??= `${unreadableFiles} file(s) could not be read.`
|
|
213
239
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
240
|
+
const summary =
|
|
241
|
+
totalMatches > 0
|
|
242
|
+
? `Found ${totalMatches} match(es) in ${filesMatched} file(s) (${filesSearched} files searched)`
|
|
243
|
+
: truncated
|
|
244
|
+
? `No matches found in the files searched for pattern "${input.pattern}"`
|
|
245
|
+
: `No matches found for pattern "${input.pattern}"`
|
|
246
|
+
const notice = failure
|
|
247
|
+
? `[Search incomplete: ${failure}]`
|
|
248
|
+
: truncated
|
|
249
|
+
? `[Search incomplete: reached max_results (${input.max_results}). Narrow the directory or include pattern for a complete search.]`
|
|
250
|
+
: undefined
|
|
218
251
|
return {
|
|
219
|
-
success:
|
|
220
|
-
output,
|
|
221
|
-
data: { totalMatches, filesSearched, filesMatched },
|
|
252
|
+
success: failure === undefined,
|
|
253
|
+
output: [results.join('\n'), summary, notice].filter(Boolean).join('\n\n'),
|
|
254
|
+
data: { totalMatches, filesSearched, filesMatched, truncated },
|
|
255
|
+
...(failure ? { error: failure } : {}),
|
|
222
256
|
}
|
|
223
257
|
},
|
|
224
258
|
})
|
package/src/tools/builtins/ls.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { Sandbox } from '../../types/sandbox/index.js'
|
|
|
5
5
|
import type { ToolResult } from '../../types/tool/index.js'
|
|
6
6
|
import { defineTool } from '../defineTool.js'
|
|
7
7
|
import { resolveWithinAny, toolRoots } from '../paths.js'
|
|
8
|
-
import {
|
|
8
|
+
import { relativePosix, resolveWithinPosix } from '../posix-path.js'
|
|
9
9
|
|
|
10
10
|
const inputSchema = z.object({
|
|
11
11
|
path: z.string().default('.').describe('Directory path to list. Defaults to working directory.'),
|
|
@@ -140,7 +140,7 @@ async function listInSandbox(
|
|
|
140
140
|
// Relative to the LISTED directory, in the sandbox's own coordinates.
|
|
141
141
|
const relativePaths: { segments: string[]; size: number }[] = []
|
|
142
142
|
for (const entry of entries) {
|
|
143
|
-
const rel = relativePosix(root,
|
|
143
|
+
const rel = relativePosix(root, resolveWithinPosix(root, entry.path))
|
|
144
144
|
if (!rel || rel.startsWith('..')) continue
|
|
145
145
|
const segments = rel.split('/').filter(Boolean)
|
|
146
146
|
if (segments.length === 0) continue
|
|
@@ -181,6 +181,20 @@ export interface SandboxFileEntry {
|
|
|
181
181
|
readonly size: number
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
/** A bounded search; patterns and depth are relative to the requested root. */
|
|
185
|
+
export interface SandboxWalkFilesOptions {
|
|
186
|
+
readonly pattern?: string
|
|
187
|
+
readonly signal?: AbortSignal
|
|
188
|
+
/** Direct children have depth 1. Omitted means no additional depth bound. */
|
|
189
|
+
readonly maxDepth?: number
|
|
190
|
+
/** Positive safe integer bounding emitted matching files. */
|
|
191
|
+
readonly maxEntries: number
|
|
192
|
+
/** Positive safe integer bounding examined directory entries; defaults to 20,000. */
|
|
193
|
+
readonly maxVisitedEntries?: number
|
|
194
|
+
/** Match hidden names through wildcards; explicit dotfile patterns always work. Defaults to false. */
|
|
195
|
+
readonly includeHidden?: boolean
|
|
196
|
+
}
|
|
197
|
+
|
|
184
198
|
// ---------------------------------------------------------------------------
|
|
185
199
|
// Sandbox interface — the core abstraction
|
|
186
200
|
// ---------------------------------------------------------------------------
|
|
@@ -294,6 +308,13 @@ export interface Sandbox {
|
|
|
294
308
|
* MAY throw for other I/O failures.
|
|
295
309
|
*/
|
|
296
310
|
listFiles(rootPath: string): Promise<readonly SandboxFileEntry[]>
|
|
311
|
+
/**
|
|
312
|
+
* Lazily enumerate regular files as absolute paths, without following symlinks.
|
|
313
|
+
* Cancellation and iterator return stop traversal. Exceeding the examined-entry
|
|
314
|
+
* budget throws an error with code `ERR_FILE_WALK_LIMIT`; it is not an empty or
|
|
315
|
+
* complete listing. Hosts requiring bounded search must refuse an absent method.
|
|
316
|
+
*/
|
|
317
|
+
walkFiles?(rootPath: string, options: SandboxWalkFilesOptions): AsyncIterable<SandboxFileEntry>
|
|
297
318
|
/**
|
|
298
319
|
* Release every resource owned by this sandbox.
|
|
299
320
|
*
|