fix(e2b): address review round on cadence config, disposal, and SDK edge cases
- subprocess-e2b: the 20 ms remote poll cadence becomes a validated pollMs Config field (each tick is one control-plane request); the README documents the latency-versus-request-count trade. - subprocess-e2b: extract src/remote.ts owning asError, signalOpts, commandOpts, delay, waitTick, and one tolerant signalRemoteGroups shared by the pgid-keyed process ladder and sid-keyed terminal ladder, so the two teardown paths keep identical error tolerance. - subprocess-e2b: service disposal aggregates sibling cleanup failures into one AggregateError instead of discarding all but the first. - subprocess-e2b: waitForProcessGroupId refuses published group ids <= 1, so a same-UID rewrite of the pid file cannot aim termination at kill -- -1; README documents the same-UID control-state limitation. - subprocess-e2b: drain-grace expiry now releases an inherited-output E2B callback blocked on host backpressure before disconnecting, so the SDK settlement cannot stay pinned behind an unread host stream. - subprocess-e2b: spawn/spawnTerminal stop validating typed spec fields (trust-TypeScript rule; pty-local validates its config before specs exist); resolveExecutable rejects separator-containing relative paths per the seam contract; terminal setups tracked as a Set of records. - subprocess-e2b: PTY output push-without-backpressure is a documented contract (flowing consumer folds bytes; paused consumer buffers). - fs-e2b: streamText normalizes the pinned SDK's empty-file '' return into an empty stream instead of throwing on getReader(). - e2b overlays: comment the one-world cwd invariant across e2b.cwd, workspaceRoot, and bash-local's implicit default workdir.
This commit is contained in:
@@ -793,6 +793,8 @@ describe('E2B subprocess terminal service', () => {
|
||||
it('rejects invalid executable lookup inputs and results', async () => {
|
||||
const { ctx, fake } = await service()
|
||||
await expect(ctx.subprocess.resolveExecutable('')).rejects.toThrow('non-empty')
|
||||
await expect(ctx.subprocess.resolveExecutable('./bin/server')).rejects.toThrow('is a relative path')
|
||||
await expect(ctx.subprocess.resolveExecutable('node_modules/.bin/server')).rejects.toThrow('is a relative path')
|
||||
await expect(ctx.subprocess.resolveExecutable('node', undefined, AbortSignal.abort(new Error('stop'))))
|
||||
.rejects.toThrow('stop')
|
||||
fake.resolvedExecutable = 'node\n'
|
||||
@@ -801,6 +803,15 @@ describe('E2B subprocess terminal service', () => {
|
||||
await expect(ctx.subprocess.resolveExecutable('node')).rejects.toThrow('did not resolve')
|
||||
})
|
||||
|
||||
it('rejects a non-positive poll cadence at load', async () => {
|
||||
const ctx = new Context()
|
||||
ctx.provide('e2b', runtime(new FakeTerminalSandbox()))
|
||||
await expect(ctx.plugin(E2BSubprocessService, { pollMs: 0 }))
|
||||
.rejects.toThrow('pollMs must be a positive safe integer')
|
||||
const explicit = await ctx.plugin(E2BSubprocessService, { pollMs: 5 })
|
||||
await explicit.dispose()
|
||||
})
|
||||
|
||||
it('owns live terminals through service disposal', async () => {
|
||||
const { ctx, fiber, fake } = await service()
|
||||
const terminal = await ctx.subprocess.spawnTerminal(spec({ signal: new AbortController().signal }))
|
||||
@@ -873,9 +884,6 @@ describe('E2B subprocess terminal service', () => {
|
||||
const { ctx, fiber, fake } = await service()
|
||||
for (const request of [
|
||||
spec({ argv: [] }),
|
||||
spec({ rows: 0 }),
|
||||
spec({ cols: 1.5 }),
|
||||
spec({ graceMs: 0 }),
|
||||
spec({ signal: AbortSignal.abort(new Error('cancelled')) }),
|
||||
]) {
|
||||
await expect(ctx.subprocess.spawnTerminal(request)).rejects.toThrow()
|
||||
|
||||
Reference in New Issue
Block a user