refactor(runtime): compose consumers over fs and subprocess

This commit is contained in:
Tianyi Cui
2026-07-28 23:00:00 +08:00
parent 987d477cfc
commit 8917ff8ef4
116 changed files with 2828 additions and 1122 deletions

View File

@@ -1,7 +1,14 @@
import { describe, expect, it } from 'vitest'
import { PassThrough } from 'node:stream'
import { Context } from 'cordis'
import { scrubbedParentEnv, SubprocessService } from '@deepseek-ai/dsh-subprocess'
import type { SubprocessHandle, SubprocessOutputRead, SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess'
import type {
SubprocessHandle,
SubprocessOutputRead,
SubprocessSpawnSpec,
SubprocessTerminalHandle,
SubprocessTerminalSpawnSpec,
} from '@deepseek-ai/dsh-subprocess'
/**
* Minimal concrete service: a hand-built handle. The seam is spawn-only —
@@ -9,6 +16,13 @@ import type { SubprocessHandle, SubprocessOutputRead, SubprocessSpawnSpec } from
* is all an implementation owes the abstract class.
*/
class StubSubprocessService extends SubprocessService {
readonly cwd = '/stub'
readonly runtimeRoot = '/stub/.runtime'
async resolveExecutable(command: string): Promise<string> {
return `/bin/${command}`
}
spawn(spec: SubprocessSpawnSpec): SubprocessHandle {
const read: SubprocessOutputRead = { text: '', nextOffset: 0, lossy: false }
const collected = spec.stdio.stdout !== 'pipe' && spec.stdio.stdout !== 'inherit'
@@ -25,6 +39,19 @@ class StubSubprocessService extends SubprocessService {
waitForExit: () => Promise.resolve(true),
}
}
async spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle> {
return {
pid: spec.argv.length,
output: new PassThrough(),
done: Promise.resolve({ exitCode: 0, signal: null }),
write: async () => {},
inspectForeground: async () => ({ processGroupId: 1, inputWaiting: true }),
signalForeground: async () => 1,
terminate: () => {},
waitForExit: async () => true,
}
}
}
describe('SubprocessService seam', () => {