dsh-edge 0.1.0 → 0.1.3

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 (64) hide show
  1. package/LICENSE +1 -1
  2. package/README.i18n.yaml +2 -2
  3. package/README.md +6 -4
  4. package/README.zh.md +6 -4
  5. package/THIRD_PARTY_NOTICES.md +42 -14
  6. package/dist/index.html +1 -1
  7. package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +7 -7
  8. package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +61 -61
  9. package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +14 -14
  10. package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +287 -287
  11. package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +10 -10
  12. package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +11 -11
  13. package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +15 -15
  14. package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +8 -8
  15. package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +27 -27
  16. package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +8 -8
  17. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +31 -31
  18. package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +23 -23
  19. package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +19 -19
  20. package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +29 -29
  21. package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +7 -7
  22. package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +64 -64
  23. package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +183 -183
  24. package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +44 -44
  25. package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +24 -24
  26. package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +79 -79
  27. package/dist/plugins/{@deepseek-ai/dsh-client-ui-edge → dsh-edge-client-ui}/client.js +12 -12
  28. package/package.json +26 -23
  29. package/scripts/assemble-web.mjs +1 -1
  30. package/scripts/bundle.mjs +41 -8
  31. package/scripts/cli.d.mts +1 -0
  32. package/scripts/cli.mjs +37 -6
  33. package/scripts/install.d.mts +6 -6
  34. package/scripts/install.mjs +36 -19
  35. package/scripts/legal-files.mjs +65 -7
  36. package/scripts/smoke-installed.mjs +47 -0
  37. package/scripts/verify-packed.d.mts +24 -0
  38. package/scripts/verify-packed.mjs +85 -23
  39. package/scripts/wrangler-config.d.mts +19 -2
  40. package/scripts/wrangler-config.mjs +68 -27
  41. package/worker/direct/index.js +2347 -0
  42. package/worker/isolated/index.js +44491 -0
  43. package/src/agent.ts +0 -119
  44. package/src/auth.ts +0 -352
  45. package/src/deepseek.ts +0 -231
  46. package/src/deployment.ts +0 -147
  47. package/src/direct-shell-core-empty.ts +0 -10
  48. package/src/direct-shell-protocol.ts +0 -5
  49. package/src/direct-shell.ts +0 -341
  50. package/src/do-session-persistence.ts +0 -1064
  51. package/src/edge-api.ts +0 -796
  52. package/src/edge-credentials.ts +0 -56
  53. package/src/edge-remotes.ts +0 -41
  54. package/src/edge-workspace-store.ts +0 -339
  55. package/src/http.ts +0 -212
  56. package/src/index.ts +0 -196
  57. package/src/instance.ts +0 -1007
  58. package/src/isolated-direct-shell-unavailable.ts +0 -11
  59. package/src/protocol.ts +0 -39
  60. package/src/release.ts +0 -9
  61. package/src/session-store.ts +0 -1110
  62. package/src/sse.ts +0 -86
  63. package/src/web-search.ts +0 -38
  64. package/src/workspace.ts +0 -270
package/src/deployment.ts DELETED
@@ -1,147 +0,0 @@
1
- /** Deployment configuration shared by Edge health and turn admission. */
2
-
3
- import type { EdgeReasoningEffort } from './deepseek.ts'
4
- import {
5
- resolveEdgeBaseURL,
6
- resolveEdgeMaxOutputTokens,
7
- resolveEdgeModel,
8
- resolveEdgeReasoningEffort,
9
- resolveEdgeStreamIdleTimeoutMs,
10
- } from './deepseek.ts'
11
- import { resolveDeepSeekApiKey } from './http.ts'
12
- import { resolveEdgeSearchBaseURL } from './web-search.ts'
13
- import {
14
- resolveEdgeCommandTimeoutPolicy,
15
- type EdgeCommandTimeoutPolicy,
16
- } from './workspace.ts'
17
- import { DSH_EDGE_UPSTREAM_VERSION, DSH_EDGE_VERSION } from './release.ts'
18
-
19
- declare const __DSH_EDGE_DEPLOYMENT_ID__: string | undefined
20
-
21
- const LOCAL_DEPLOYMENT_ID = 'local-development'
22
-
23
- /** Worker variables that control one Edge model and shell turn. */
24
- export interface EdgeDeploymentConfigSource {
25
- LOADER?: unknown
26
- DEEPSEEK_API_KEY?: string
27
- DEEPSEEK_BASE_URL?: string
28
- DEEPSEEK_MAX_OUTPUT_TOKENS?: string
29
- DEEPSEEK_MODEL?: string
30
- DEEPSEEK_REASONING_EFFORT?: string
31
- DEEPSEEK_SEARCH_BASE_URL?: string
32
- DEEPSEEK_STREAM_IDLE_TIMEOUT_MS?: string
33
- DSH_EDGE_DEFAULT_COMMAND_TIMEOUT_MS?: string
34
- DSH_EDGE_MAX_COMMAND_TIMEOUT_MS?: string
35
- }
36
-
37
- /** Validated deployment choices consumed by one Edge turn. */
38
- export interface EdgeDeploymentConfig {
39
- baseURL: string
40
- maxTokens: number
41
- model: string
42
- reasoningEffort: EdgeReasoningEffort
43
- searchBaseURL: string
44
- streamIdleTimeoutMs: number
45
- commandTimeoutPolicy: EdgeCommandTimeoutPolicy
46
- }
47
-
48
- /** Secret-free deployment facts safe to project to the authenticated owner. */
49
- export interface EdgeDeploymentProfile {
50
- shell: 'just-bash-direct' | 'just-bash-isolated'
51
- storage: 'durable-object-sqlite-vfs'
52
- deploymentId: string
53
- apiKeyConfigured: boolean
54
- baseURL: string
55
- maxTokens: number
56
- model: string
57
- reasoningEffort: EdgeReasoningEffort
58
- searchBaseURL: string
59
- streamIdleTimeoutMs: number
60
- commandTimeoutPolicy: EdgeCommandTimeoutPolicy
61
- }
62
-
63
- /** Identify the exact Worker artifact that answered a readiness request. */
64
- export function resolveEdgeDeploymentId(): string {
65
- return typeof __DSH_EDGE_DEPLOYMENT_ID__ === 'string'
66
- ? __DSH_EDGE_DEPLOYMENT_ID__
67
- : LOCAL_DEPLOYMENT_ID
68
- }
69
-
70
- /** Resolve every deployment choice before health succeeds or a turn is claimed. */
71
- export function resolveEdgeDeploymentConfig(
72
- source: EdgeDeploymentConfigSource,
73
- ): EdgeDeploymentConfig {
74
- resolveDeepSeekApiKey(source.DEEPSEEK_API_KEY)
75
- return {
76
- baseURL: resolveEdgeBaseURL(source.DEEPSEEK_BASE_URL),
77
- maxTokens: resolveEdgeMaxOutputTokens(source.DEEPSEEK_MAX_OUTPUT_TOKENS),
78
- model: resolveEdgeModel(source.DEEPSEEK_MODEL),
79
- reasoningEffort: resolveEdgeReasoningEffort(source.DEEPSEEK_REASONING_EFFORT),
80
- searchBaseURL: resolveEdgeSearchBaseURL(source.DEEPSEEK_SEARCH_BASE_URL),
81
- streamIdleTimeoutMs: resolveEdgeStreamIdleTimeoutMs(
82
- source.DEEPSEEK_STREAM_IDLE_TIMEOUT_MS,
83
- ),
84
- commandTimeoutPolicy: resolveEdgeCommandTimeoutPolicy(
85
- source.DSH_EDGE_DEFAULT_COMMAND_TIMEOUT_MS,
86
- source.DSH_EDGE_MAX_COMMAND_TIMEOUT_MS,
87
- ),
88
- }
89
- }
90
-
91
- /** Whether the deployment supplies a non-blank DeepSeek Worker binding. */
92
- export function edgeDeploymentApiKeyConfigured(source: EdgeDeploymentConfigSource): boolean {
93
- return typeof source.DEEPSEEK_API_KEY === 'string'
94
- && source.DEEPSEEK_API_KEY.trim().length > 0
95
- }
96
-
97
- /** Omit URL components that commonly carry credentials from the browser projection. */
98
- function projectedEdgeBaseURL(raw?: string): string {
99
- const value = resolveEdgeBaseURL(raw)
100
- const parsed = new URL(value)
101
- if (parsed.search.length === 0 && parsed.hash.length === 0) return value
102
- parsed.search = ''
103
- parsed.hash = ''
104
- return parsed.href
105
- }
106
-
107
- /** Resolve the effective runtime profile without retaining or returning a credential value. */
108
- export function resolveEdgeDeploymentProfile(
109
- source: EdgeDeploymentConfigSource,
110
- ): EdgeDeploymentProfile {
111
- return {
112
- shell: source.LOADER === undefined ? 'just-bash-direct' : 'just-bash-isolated',
113
- storage: 'durable-object-sqlite-vfs',
114
- deploymentId: resolveEdgeDeploymentId(),
115
- apiKeyConfigured: edgeDeploymentApiKeyConfigured(source),
116
- baseURL: projectedEdgeBaseURL(source.DEEPSEEK_BASE_URL),
117
- maxTokens: resolveEdgeMaxOutputTokens(source.DEEPSEEK_MAX_OUTPUT_TOKENS),
118
- model: resolveEdgeModel(source.DEEPSEEK_MODEL),
119
- reasoningEffort: resolveEdgeReasoningEffort(source.DEEPSEEK_REASONING_EFFORT),
120
- searchBaseURL: resolveEdgeSearchBaseURL(source.DEEPSEEK_SEARCH_BASE_URL),
121
- streamIdleTimeoutMs: resolveEdgeStreamIdleTimeoutMs(
122
- source.DEEPSEEK_STREAM_IDLE_TIMEOUT_MS,
123
- ),
124
- commandTimeoutPolicy: resolveEdgeCommandTimeoutPolicy(
125
- source.DSH_EDGE_DEFAULT_COMMAND_TIMEOUT_MS,
126
- source.DSH_EDGE_MAX_COMMAND_TIMEOUT_MS,
127
- ),
128
- }
129
- }
130
-
131
- /** Validate the default turn configuration and return the public runtime identity. */
132
- export function resolveEdgeDeploymentHealth(source: EdgeDeploymentConfigSource) {
133
- resolveEdgeDeploymentConfig(source)
134
- const profile = resolveEdgeDeploymentProfile(source)
135
- return {
136
- ok: true,
137
- service: 'dsh-edge',
138
- storage: profile.storage,
139
- shell: profile.shell,
140
- agent: 'upstream-react-loop-agent',
141
- access: 'single-owner-cookie',
142
- deploymentId: profile.deploymentId,
143
- version: DSH_EDGE_VERSION,
144
- upstreamVersion: DSH_EDGE_UPSTREAM_VERSION,
145
- status: 'ready',
146
- } as const
147
- }
@@ -1,10 +0,0 @@
1
- /**
2
- * Direct-build replacement for Computer's embedded Dynamic Worker modules.
3
- *
4
- * Direct deployments have no Loader binding, so they cannot select
5
- * `WorkerShellBackend`. The alias keeps Computer's filesystem and command
6
- * adapters available without uploading an unreachable shell runtime.
7
- */
8
- const directShellCore = Object.freeze({})
9
-
10
- export default directShellCore
@@ -1,5 +0,0 @@
1
- /** Byte ceiling shared by shell execution, retention, and truncation rendering. */
2
- export const EDGE_SHELL_OUTPUT_LIMIT_BYTES = 65_536
3
-
4
- /** Standard shell-event result used when direct just-bash stops at its output budget. */
5
- export const DIRECT_SHELL_OUTPUT_TRUNCATED = 'dsh-edge:direct-output-truncated'
@@ -1,341 +0,0 @@
1
- /** In-process just-bash backend for the Cloudflare Computer workspace runtime. */
2
-
3
- import type { BackendHandle, WorkspaceBackend } from '@cloudflare/computer'
4
- import {
5
- WorkspaceFsAdapter,
6
- defineArtifactsCommand,
7
- defineAssetsCommand,
8
- defineGitCommand,
9
- type WorkspaceFs,
10
- } from '@cloudflare/computer/backends/worker-shell'
11
- import {
12
- Bash,
13
- type BashExecResult,
14
- type IFileSystem,
15
- } from 'just-bash/browser'
16
- import {
17
- DIRECT_SHELL_OUTPUT_TRUNCATED,
18
- EDGE_SHELL_OUTPUT_LIMIT_BYTES,
19
- } from './direct-shell-protocol.ts'
20
-
21
- const DEFAULT_BACKEND_ID = 'worker-shell'
22
- const DEFAULT_CWD = '/workspace'
23
- type DirectBackendHost = Parameters<WorkspaceBackend['connect']>[0]
24
- type WorkspaceSyncRpc = BackendHandle['rpc']['sync']
25
- type ShellExec = BackendHandle['rpc']['shell']['exec']
26
- type ShellExecInput = Parameters<ShellExec>[0]
27
- type ShellExecEnvelope = Awaited<ReturnType<ShellExec>>
28
- type ShellExecEvent = ShellExecEnvelope['events'] extends ReadableStream<infer Event>
29
- ? Event
30
- : never
31
-
32
- interface DirectBashExecOptions {
33
- cwd?: string
34
- env?: Record<string, string>
35
- stdin?: string
36
- stdinKind?: 'bytes'
37
- signal?: AbortSignal
38
- }
39
-
40
- interface DirectExecution {
41
- controller: AbortController
42
- done: Promise<void>
43
- }
44
-
45
- interface DirectBashOutcome {
46
- result: BashExecResult
47
- terminalResult?: typeof DIRECT_SHELL_OUTPUT_TRUNCATED
48
- }
49
-
50
- /** Options for the free in-process shell backend. */
51
- export interface DirectShellBackendOptions {
52
- id?: string
53
- }
54
-
55
- /** Run just-bash in the owning Durable Object against Computer's local VFS. */
56
- export class DirectShellBackend implements WorkspaceBackend {
57
- readonly type = 'direct-shell'
58
- readonly id: string
59
-
60
- constructor(options: DirectShellBackendOptions = {}) {
61
- this.id = options.id ?? DEFAULT_BACKEND_ID
62
- }
63
-
64
- /** Connect one workspace-local shell runtime. */
65
- connect(host: DirectBackendHost): Promise<BackendHandle> {
66
- const runtime = new DirectShellRuntime(host)
67
- return Promise.resolve({
68
- rpc: {
69
- sync: disabledSyncRpc(),
70
- shell: {
71
- exec: input => runtime.exec(input),
72
- getExec: input => runtime.getExec(input.id),
73
- killExec: input => runtime.killExec(input.id, input.signal),
74
- disposeExec: input => runtime.disposeExec(input.id),
75
- },
76
- },
77
- sync: 'none',
78
- close: () => runtime.close(),
79
- })
80
- }
81
- }
82
-
83
- class DirectShellRuntime {
84
- private readonly fs: WorkspaceFsAdapter
85
- private readonly executions = new Map<string, DirectExecution>()
86
- private closed = false
87
-
88
- constructor(private readonly host: DirectBackendHost) {
89
- this.fs = new WorkspaceFsAdapter(workspaceFs(host))
90
- }
91
-
92
- exec(input: ShellExecInput): Promise<ShellExecEnvelope> {
93
- if (this.closed) throw directShellError('ECLOSED', 'direct shell backend is closed')
94
- const id = input.id ?? crypto.randomUUID()
95
- if (this.executions.has(id)) {
96
- throw directShellError('EEXEC_BUSY', `execution ${id} is running`)
97
- }
98
-
99
- const controller = new AbortController()
100
- const result = Promise.resolve().then(() => this.run(input, controller.signal))
101
- const done = result.then(() => undefined, () => undefined)
102
- this.executions.set(id, { controller, done })
103
- return Promise.resolve({
104
- id,
105
- events: executionEvents(
106
- id,
107
- result,
108
- () => { this.deleteExecution(id, controller) },
109
- () => this.disposeExec(id),
110
- ),
111
- })
112
- }
113
-
114
- getExec(id: string): Promise<ShellExecEnvelope> {
115
- throw directShellError('ENOENT', `no such exec: ${id}`)
116
- }
117
-
118
- killExec(id: string, signal = 'SIGTERM'): Promise<void> {
119
- this.executions.get(id)?.controller.abort(
120
- directShellError('EEXEC_CANCELLED', `execution cancelled with ${signal}`),
121
- )
122
- return Promise.resolve()
123
- }
124
-
125
- async disposeExec(id: string): Promise<void> {
126
- const execution = this.executions.get(id)
127
- if (execution === undefined) return
128
- execution.controller.abort(
129
- directShellError('EEXEC_DISPOSED', `execution disposed: ${id}`),
130
- )
131
- await execution.done
132
- this.deleteExecution(id, execution.controller)
133
- }
134
-
135
- async close(): Promise<void> {
136
- if (this.closed) return
137
- this.closed = true
138
- const active = [...this.executions.values()]
139
- for (const execution of active) {
140
- execution.controller.abort(directShellError('ECLOSED', 'direct shell backend is closing'))
141
- }
142
- await Promise.allSettled(active.map(execution => execution.done))
143
- this.executions.clear()
144
- }
145
-
146
- private async run(input: ShellExecInput, signal: AbortSignal): Promise<DirectBashOutcome> {
147
- const timeoutLimit = input.timeoutMs !== undefined && input.timeoutMs > 0
148
- ? { maxExecutionTimeMs: input.timeoutMs }
149
- : {}
150
- const bash = new Bash({
151
- // Computer and just-bash accept the same runtime encodings, but their
152
- // interfaces spell the optional UTF-8 alias set differently.
153
- fs: this.fs as unknown as IFileSystem,
154
- cwd: input.cwd ?? DEFAULT_CWD,
155
- ...(input.env === undefined ? {} : { env: input.env }),
156
- customCommands: [
157
- defineGitCommand(this.host),
158
- defineAssetsCommand({}),
159
- defineArtifactsCommand(this.host),
160
- ],
161
- defenseInDepth: { enabled: 'auto' },
162
- executionLimitProfile: 'hardened',
163
- executionLimits: {
164
- maxOutputSize: EDGE_SHELL_OUTPUT_LIMIT_BYTES,
165
- ...timeoutLimit,
166
- },
167
- })
168
- const directBash = bash as unknown as {
169
- exec(command: string, options: DirectBashExecOptions): Promise<BashExecResult>
170
- }
171
- try {
172
- const result = await directBash.exec(input.source, {
173
- cwd: input.cwd ?? DEFAULT_CWD,
174
- ...(input.env === undefined ? {} : { env: input.env }),
175
- ...(input.stdin === undefined
176
- ? {}
177
- : { stdin: latin1FromBytes(input.stdin), stdinKind: 'bytes' as const }),
178
- signal,
179
- })
180
- return {
181
- result,
182
- ...(hitDirectOutputLimit(result)
183
- ? { terminalResult: DIRECT_SHELL_OUTPUT_TRUNCATED }
184
- : {}),
185
- }
186
- } catch (error) {
187
- const message = error instanceof Error ? error.message : String(error)
188
- return {
189
- result: {
190
- stdout: '',
191
- stderr: `${message}\n`,
192
- exitCode: signal.aborted ? 130 : 1,
193
- env: input.env ?? {},
194
- },
195
- }
196
- }
197
- }
198
-
199
- private deleteExecution(id: string, controller: AbortController): void {
200
- if (this.executions.get(id)?.controller === controller) this.executions.delete(id)
201
- }
202
- }
203
-
204
- function workspaceFs(host: DirectBackendHost): WorkspaceFs {
205
- const fs = host.fs
206
- return {
207
- readFile: fs.readFile.bind(fs),
208
- exists: async path => await statOrNull(() => fs.stat(path)) !== null,
209
- stat: path => fs.stat(path),
210
- statOrNull: path => statOrNull(() => fs.stat(path)),
211
- lstat: path => fs.lstat(path),
212
- lstatOrNull: path => statOrNull(() => fs.lstat(path)),
213
- readdir: path => fs.readdir(path),
214
- find: (directory, pattern) => fs.find(directory, pattern),
215
- ls: prefix => fs.ls(prefix),
216
- grep: (pattern, path, options) => fs.grep(pattern, path, options),
217
- readlink: path => fs.readlink(path),
218
- writeFile: (path, content, options) => fs.writeFile(path, content, options),
219
- mkdir: (path, options) => fs.mkdir(path, options),
220
- rm: (path, options) => fs.rm(path, options),
221
- chmod: (path, mode) => fs.chmod(path, mode),
222
- symlink: (target, path) => fs.symlink(target, path),
223
- }
224
- }
225
-
226
- async function statOrNull<T>(read: () => Promise<T>): Promise<T | null> {
227
- try {
228
- return await read()
229
- } catch (error) {
230
- if (hasErrorCode(error, 'ENOENT')) return null
231
- throw error
232
- }
233
- }
234
-
235
- function hasErrorCode(error: unknown, code: string): boolean {
236
- return typeof error === 'object'
237
- && error !== null
238
- && 'code' in error
239
- && error.code === code
240
- }
241
-
242
- function executionEvents(
243
- id: string,
244
- result: Promise<DirectBashOutcome>,
245
- onTerminal: () => void,
246
- onCancel: () => Promise<void>,
247
- ): ReadableStream<ShellExecEvent> {
248
- const encoder = new TextEncoder()
249
- let events: ShellExecEvent[] | undefined
250
- return new ReadableStream({
251
- async pull(controller) {
252
- try {
253
- events ??= shellExecEvents(id, encoder, await result)
254
- const event = events.shift()
255
- if (event === undefined) return
256
- controller.enqueue(event)
257
- if (event.name === 'exit') {
258
- controller.close()
259
- onTerminal()
260
- }
261
- } catch (error) {
262
- controller.error(error)
263
- onTerminal()
264
- }
265
- },
266
- cancel: onCancel,
267
- }, { highWaterMark: 0 })
268
- }
269
-
270
- function shellExecEvents(
271
- id: string,
272
- encoder: TextEncoder,
273
- outcome: DirectBashOutcome,
274
- ): ShellExecEvent[] {
275
- const { result } = outcome
276
- const events: ShellExecEvent[] = []
277
- let seq = 0
278
- if (result.stdout.length > 0) {
279
- events.push({ id, seq: ++seq, name: 'stdout', value: encoder.encode(result.stdout) })
280
- }
281
- if (result.stderr.length > 0) {
282
- events.push({ id, seq: ++seq, name: 'stderr', value: encoder.encode(result.stderr) })
283
- }
284
- events.push({
285
- id,
286
- seq: ++seq,
287
- name: 'exit',
288
- code: result.exitCode,
289
- ...(outcome.terminalResult === undefined ? {} : { result: outcome.terminalResult }),
290
- })
291
- return events
292
- }
293
-
294
- function hitDirectOutputLimit(result: BashExecResult): boolean {
295
- if (result.exitCode !== 126) return false
296
- const accountedBytes = result.internalOutputAccounting?.stderr
297
- if (accountedBytes === undefined) return false
298
- const stderr = new TextEncoder().encode(result.stderr)
299
- if (accountedBytes < 0 || accountedBytes > stderr.byteLength) return false
300
- const interpreterDiagnostic = new TextDecoder().decode(stderr.subarray(accountedBytes))
301
- return [
302
- `limit exceeded (${EDGE_SHELL_OUTPUT_LIMIT_BYTES} bytes)`,
303
- `total output size exceeded (>${EDGE_SHELL_OUTPUT_LIMIT_BYTES} bytes), `
304
- + 'increase executionLimits.maxOutputSize',
305
- ].some(diagnostic => interpreterDiagnostic.includes(diagnostic))
306
- }
307
-
308
- function latin1FromBytes(bytes: Uint8Array): string {
309
- let result = ''
310
- for (const byte of bytes) result += String.fromCharCode(byte)
311
- return result
312
- }
313
-
314
- function directShellError(code: string, message: string): Error & { code: string } {
315
- const error = new Error(message) as Error & { code: string }
316
- error.name = 'DirectShellError'
317
- error.code = code
318
- return error
319
- }
320
-
321
- function disabledSyncRpc(): WorkspaceSyncRpc {
322
- const refuse = (name: string): never => {
323
- throw directShellError(
324
- 'ENOSYS',
325
- `DirectShellBackend: sync.${name} must not be called because sync is disabled`,
326
- )
327
- }
328
- return {
329
- push: () => refuse('push'),
330
- fetchChanges: () => refuse('fetchChanges'),
331
- watermarks: () => refuse('watermarks'),
332
- readEntry: () => refuse('readEntry'),
333
- hasObjects: () => refuse('hasObjects'),
334
- fetchObjects: () => new ReadableStream({
335
- start(controller) {
336
- controller.error(directShellError('ENOSYS', 'DirectShellBackend: sync is disabled'))
337
- },
338
- }),
339
- pushObjects: () => refuse('pushObjects'),
340
- }
341
- }