()
| 221 | } |
| 222 | |
| 223 | async start(): Promise<void> { |
| 224 | if (this.process) throw new Error("Pi RPC client already started"); |
| 225 | writeConfigs(this.env, this.options); |
| 226 | |
| 227 | this.process = spawn( |
| 228 | "bun", |
| 229 | [ |
| 230 | PI_CLI, |
| 231 | "--mode", |
| 232 | "rpc", |
| 233 | "--no-extensions", |
| 234 | "--extension", |
| 235 | this.env.pluginDir, |
| 236 | "--no-skills", |
| 237 | "--no-prompt-templates", |
| 238 | "--no-themes", |
| 239 | "--model", |
| 240 | "anthropic/claude-haiku-4-5", |
| 241 | "--api-key", |
| 242 | "test-key-not-real", |
| 243 | ], |
| 244 | { cwd: this.env.workdir, env: childEnv(this.env), stdio: ["pipe", "pipe", "pipe"] }, |
| 245 | ); |
| 246 | |
| 247 | this.process.stderr?.on("data", (chunk: Buffer) => { |
| 248 | this.stderr += chunk.toString(); |
| 249 | }); |
| 250 | this.stopReadingStdout = attachStrictJsonlReader(this.process.stdout!, (line) => { |
| 251 | this.protocol.dispatchLine(line); |
| 252 | }); |
| 253 | this.process.once("exit", (code, signal) => { |
| 254 | this.protocol.rejectPending( |
| 255 | new Error(`Pi RPC process exited with code ${code ?? "null"} signal ${signal ?? "null"}\n${this.stderr}`), |
| 256 | ); |
| 257 | }); |
| 258 | |
| 259 | await Bun.sleep(100); |
| 260 | if (this.process.exitCode !== null) { |
| 261 | throw new Error(`Pi RPC process exited during startup with code ${this.process.exitCode}\n${this.stderr}`); |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | onEvent(listener: (event: PiRpcEvent) => void): () => void { |
| 266 | return this.protocol.onEvent(listener); |
no test coverage detected