@ponythewhite/base-context 1.0.1 → 1.0.2

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.2] - 2026-09-17
4
+
5
+ - Fixed RPC requests waiting for a timeout after the agent process exits, and removed the shutdown delay for an already-exited process.
6
+
3
7
  ## [1.0.1] - 2026-09-16
4
8
 
5
9
  - Made the Synerise base-context installer the primary setup path, with automatic prerequisites, optional shell-profile updates, and clear launch instructions.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "base-context-runtime"
3
- version = "1.0.1"
3
+ version = "1.0.2"
4
4
  description = "Kernel-side runtime shim for Base Context recursion"
5
5
  license = "MIT"
6
6
  license-files = ["LICENSE", "NOTICE"]
@@ -367,7 +367,7 @@ wheels = [
367
367
 
368
368
  [[package]]
369
369
  name = "base-context-runtime"
370
- version = "1.0.1"
370
+ version = "1.0.2"
371
371
  source = { editable = "." }
372
372
  dependencies = [
373
373
  { name = "mcp" },
@@ -1,5 +1,5 @@
1
1
  {
2
- "sourceCommit": "9247ae92d4cc1a43fcb003316e6762be579a6a05",
2
+ "sourceCommit": "4192025d919683d61a402b666b4790e26118df53",
3
3
  "sourceDirty": false,
4
4
  "buildHost": {
5
5
  "platform": "linux",
@@ -51,7 +51,7 @@ import {
51
51
  oauth_exports,
52
52
  runPrintMode,
53
53
  runRpcMode
54
- } from "./chunk-S3INFPZZ.js";
54
+ } from "./chunk-44PEHPOG.js";
55
55
  import {
56
56
  AgentSession,
57
57
  CURRENT_SESSION_VERSION,
@@ -143,7 +143,7 @@ import {
143
143
  withFileMutationQueue,
144
144
  wrapRegisteredTool,
145
145
  wrapRegisteredTools
146
- } from "./chunk-V3L54UD6.js";
146
+ } from "./chunk-IADCPVEI.js";
147
147
  import "./chunk-CFNASUYO.js";
148
148
  import "./chunk-HKINIBP4.js";
149
149
  import {
@@ -347,7 +347,7 @@ import {
347
347
  watchWithErrorHandler,
348
348
  workerRosterEntryFromSummary,
349
349
  wrapTextWithAnsi
350
- } from "./chunk-V3L54UD6.js";
350
+ } from "./chunk-IADCPVEI.js";
351
351
  import {
352
352
  array,
353
353
  boolean,
@@ -72602,22 +72602,31 @@ var RpcClient = class {
72602
72602
  if (this.options.args) {
72603
72603
  args.push(...this.options.args);
72604
72604
  }
72605
- this.process = spawn11("node", [cliPath, ...args], {
72605
+ const child = spawn11("node", [cliPath, ...args], {
72606
72606
  cwd: this.options.cwd,
72607
72607
  env: { ...process.env, ...this.options.env },
72608
72608
  stdio: ["pipe", "pipe", "pipe"]
72609
72609
  });
72610
- this.process.stderr?.on("data", (data) => {
72610
+ this.process = child;
72611
+ this.stderr = "";
72612
+ child.stderr?.on("data", (data) => {
72613
+ if (this.process !== child)
72614
+ return;
72611
72615
  this.stderr += data.toString();
72612
72616
  process.stderr.write(data);
72613
72617
  });
72614
- this.stopReadingStdout = attachJsonlLineReader(this.process.stdout, (line) => {
72615
- this.handleLine(line);
72618
+ child.once("error", (error) => {
72619
+ if (this.process === child)
72620
+ this.rejectPendingRequests(error);
72621
+ });
72622
+ child.once("close", () => {
72623
+ if (this.process === child)
72624
+ this.rejectPendingRequests(this.processExitError(child));
72625
+ });
72626
+ this.stopReadingStdout = attachJsonlLineReader(child.stdout, (line) => {
72627
+ if (this.process === child)
72628
+ this.handleLine(line);
72616
72629
  });
72617
- await new Promise((resolve26) => setTimeout(resolve26, 100));
72618
- if (this.process.exitCode !== null) {
72619
- throw new Error(`Agent process exited immediately with code ${this.process.exitCode}. Stderr: ${this.stderr}`);
72620
- }
72621
72630
  try {
72622
72631
  const state = await this.getState();
72623
72632
  if (state.protocolVersion !== DAEMON_PROTOCOL_VERSION)
@@ -72626,10 +72635,12 @@ var RpcClient = class {
72626
72635
  if (!Number.isSafeInteger(state.schemaRevision) || (state.schemaRevision ?? 0) < minimumSchema)
72627
72636
  throw new Error(`Incompatible RPC schema: expected at least ${minimumSchema}, got ${state.schemaRevision ?? "unversioned"}`);
72628
72637
  } catch (error) {
72629
- try {
72630
- await this.stop();
72631
- } catch (cleanupError) {
72632
- throw new AggregateError([error, cleanupError], "RPC startup and cleanup failed", { cause: error });
72638
+ if (this.process === child) {
72639
+ try {
72640
+ await this.stop();
72641
+ } catch (cleanupError) {
72642
+ throw new AggregateError([error, cleanupError], "RPC startup and cleanup failed", { cause: error });
72643
+ }
72633
72644
  }
72634
72645
  throw error;
72635
72646
  }
@@ -72638,23 +72649,28 @@ var RpcClient = class {
72638
72649
  * Stop the RPC agent process.
72639
72650
  */
72640
72651
  async stop() {
72641
- if (!this.process)
72652
+ const child = this.process;
72653
+ if (!child)
72642
72654
  return;
72643
72655
  this.stopReadingStdout?.();
72644
72656
  this.stopReadingStdout = null;
72645
- this.process.kill("SIGTERM");
72646
- await new Promise((resolve26) => {
72647
- const timeout = setTimeout(() => {
72648
- this.process?.kill("SIGKILL");
72649
- resolve26();
72650
- }, 1e3);
72651
- this.process?.on("exit", () => {
72652
- clearTimeout(timeout);
72653
- resolve26();
72657
+ if (child.exitCode === null && child.signalCode === null) {
72658
+ await new Promise((resolve26) => {
72659
+ const timeout = setTimeout(() => {
72660
+ child.kill("SIGKILL");
72661
+ resolve26();
72662
+ }, 1e3);
72663
+ child.once("exit", () => {
72664
+ clearTimeout(timeout);
72665
+ resolve26();
72666
+ });
72667
+ child.kill("SIGTERM");
72654
72668
  });
72655
- });
72656
- this.process = null;
72657
- this.pendingRequests.clear();
72669
+ }
72670
+ if (this.process === child) {
72671
+ this.process = null;
72672
+ this.rejectPendingRequests(new Error("RPC client stopped"));
72673
+ }
72658
72674
  }
72659
72675
  /**
72660
72676
  * Subscribe to agent events.
@@ -73046,6 +73062,15 @@ var RpcClient = class {
73046
73062
  // =========================================================================
73047
73063
  // Internal
73048
73064
  // =========================================================================
73065
+ processExitError(child) {
73066
+ const reason = child.signalCode ? `signal ${child.signalCode}` : `code ${child.exitCode}`;
73067
+ return new Error(`Agent process exited with ${reason}. Stderr: ${this.stderr}`);
73068
+ }
73069
+ rejectPendingRequests(error) {
73070
+ for (const pending of this.pendingRequests.values())
73071
+ pending.reject(error);
73072
+ this.pendingRequests.clear();
73073
+ }
73049
73074
  handleLine(line) {
73050
73075
  try {
73051
73076
  const data = JSON.parse(line);
@@ -73074,13 +73099,16 @@ var RpcClient = class {
73074
73099
  }
73075
73100
  }
73076
73101
  async send(command, timeoutMs = 3e4) {
73077
- if (!this.process?.stdin) {
73102
+ const child = this.process;
73103
+ if (!child?.stdin) {
73078
73104
  throw new Error("Client not started");
73079
73105
  }
73106
+ if (child.exitCode !== null || child.signalCode !== null) {
73107
+ throw this.processExitError(child);
73108
+ }
73080
73109
  const id = `req_${++this.requestId}`;
73081
73110
  const fullCommand = { ...command, id };
73082
73111
  return new Promise((resolve26, reject) => {
73083
- this.pendingRequests.set(id, { resolve: resolve26, reject });
73084
73112
  const timeout = setTimeout(() => {
73085
73113
  this.pendingRequests.delete(id);
73086
73114
  reject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));
@@ -73095,7 +73123,7 @@ var RpcClient = class {
73095
73123
  reject(error);
73096
73124
  }
73097
73125
  });
73098
- this.process.stdin.write(serializeJsonLine(fullCommand));
73126
+ child.stdin.write(serializeJsonLine(fullCommand));
73099
73127
  });
73100
73128
  }
73101
73129
  getData(response) {
@@ -44713,7 +44713,7 @@ async function loadExtensionModule(extensionPath) {
44713
44713
  // (file-path aliases would load a second, divergent copy of each package).
44714
44714
  // Also disable tryNative so jiti handles ALL imports (not just the entry point)
44715
44715
  // Node/dev must also share the native AI registry and implementation identities.
44716
- ...isBunBinary || isBundledCli ? { virtualModules: (await import("./bundled-modules-TXUMJ2XQ.js")).VIRTUAL_MODULES, tryNative: false } : {
44716
+ ...isBunBinary || isBundledCli ? { virtualModules: (await import("./bundled-modules-PWOGKUQQ.js")).VIRTUAL_MODULES, tryNative: false } : {
44717
44717
  alias: getAliases(),
44718
44718
  virtualModules: {
44719
44719
  "@ponythewhite/base-context-ai": src_exports,
@@ -68982,7 +68982,7 @@ import { resolve as resolve15 } from "node:path";
68982
68982
  var BASE_CONTEXT_BUILD_ID_ENV = "BASE_CONTEXT_BUILD_ID";
68983
68983
  var BASE_CONTEXT_LAUNCHER_PATH_ENV = "BASE_CONTEXT_LAUNCHER_PATH";
68984
68984
  function bundledBuildId() {
68985
- return false ? void 0 : "v1.0.1";
68985
+ return false ? void 0 : "v1.0.2";
68986
68986
  }
68987
68987
  function getDaemonRuntimeIdentity(environment = process.env) {
68988
68988
  const entrypoint = process.argv[1];
@@ -5,7 +5,7 @@ import {
5
5
  isOwnedSessionWorkerProcess,
6
6
  maybeRunOwnedSessionWorkerFrontend,
7
7
  maybeStartDaemonEarly
8
- } from "./chunk-V3L54UD6.js";
8
+ } from "./chunk-IADCPVEI.js";
9
9
  import {
10
10
  APP_NAME
11
11
  } from "./chunk-27QCJ2AZ.js";
@@ -39,7 +39,7 @@ async function runCli() {
39
39
  }
40
40
  const [{ EnvHttpProxyAgent, setGlobalDispatcher }, { main }] = await Promise.all([
41
41
  import("undici"),
42
- import("./main-ODOYCEQC.js")
42
+ import("./main-SV7JLVEB.js")
43
43
  ]);
44
44
  setGlobalDispatcher(new EnvHttpProxyAgent({ bodyTimeout: 0, headersTimeout: 0 }));
45
45
  try {
@@ -52,6 +52,6 @@ var supported = assertNodeVersion({
52
52
  exit: (code) => process.exit(code)
53
53
  });
54
54
  if (supported) {
55
- const { runCli } = await import("./cli-main-BYMSRPH6.js");
55
+ const { runCli } = await import("./cli-main-4DS7Y3PI.js");
56
56
  await runCli();
57
57
  }
@@ -17,8 +17,8 @@ import {
17
17
  shouldUseDaemonClientRuntime,
18
18
  shouldUseDaemonInteractive,
19
19
  shouldUseEphemeralSessionManagerForDaemonInteractive
20
- } from "./chunk-S3INFPZZ.js";
21
- import "./chunk-V3L54UD6.js";
20
+ } from "./chunk-44PEHPOG.js";
21
+ import "./chunk-IADCPVEI.js";
22
22
  import "./chunk-CFNASUYO.js";
23
23
  import "./chunk-HKINIBP4.js";
24
24
  import "./chunk-27QCJ2AZ.js";
@@ -250,6 +250,8 @@ export declare class RpcClient {
250
250
  * Send prompt and wait for completion, returning all events.
251
251
  */
252
252
  promptAndWait(message: string, images?: ImageContent[], timeout?: number): Promise<AgentEvent[]>;
253
+ private processExitError;
254
+ private rejectPendingRequests;
253
255
  private handleLine;
254
256
  private send;
255
257
  private getData;
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACN,KAAK,UAAU,EACf,KAAK,YAAY,EAEjB,KAAK,aAAa,EAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,0BAA0B,EAAE,+BAA+B,EAAE,MAAM,8BAA8B,CAAC;AAChH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EACX,YAAY,EACZ,0BAA0B,EAC1B,8BAA8B,EAC9B,0BAA0B,EAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAG7E,OAAO,KAAK,EAEX,uBAAuB,EAGvB,eAAe,EACf,eAAe,EACf,MAAM,gBAAgB,CAAC;AAiBxB,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,QAAiB,CAAC;AAQxD,MAAM,WAAW,gBAAgB;IAChC,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;AAC3D,MAAM,MAAM,0BAA0B,GAAG,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,CAAC;AAMlF,qBAAa,SAAS;IAUT,OAAO,CAAC,OAAO;IAT3B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,wBAAwB,CAAoC;IACpE,OAAO,CAAC,eAAe,CACZ;IACX,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAAM;IAEpB,YAAoB,OAAO,GAAE,gBAAqB,EAAI;IAEtD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA4D3B;IAED;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAsB1B;IAED;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAQ9C;IAED,sBAAsB,CAAC,QAAQ,EAAE,0BAA0B,GAAG,MAAM,IAAI,CAQvE;IAED;;OAEG;IACH,SAAS,IAAI,MAAM,CAElB;IAMD;;;;OAIG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpE;IAED;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnE;IAED;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE;IAED;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED;;;;OAIG;IACG,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAGxE;IAED;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CAGzC;IAED;;OAEG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAG3F;IAED;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC;QAC3B,KAAK,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QACxC,aAAa,EAAE,aAAa,CAAC;QAC7B,QAAQ,EAAE,OAAO,CAAC;KAClB,GAAG,IAAI,CAAC,CAGR;IAED;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAG/C;IAED;;OAEG;IACG,gBAAgB,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;IAED;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,aAAa,CAAA;KAAE,GAAG,IAAI,CAAC,CAGnE;IAED;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAElE;IAED;;OAEG;IACG,eAAe,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAElE;IAED;;OAEG;IACG,OAAO,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGpE;IAED;;OAEG;IACG,MAAM,CACX,OAAO,GAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAO,GAC5E,OAAO,CAAC,gBAAgB,CAAC,CAc3B;IAED;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvD;IAED;;OAEG;IACG,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAElD;IAED;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAEhC;IAED;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAG/C;IAED;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/B;IAED;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAG7C;IAED;;OAEG;IACG,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAG/D;IAED;;;OAGG;IACG,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAGxE;IAED;;;OAGG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAGzE;IAED;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,CAG7C;IAED;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAGzE;IAED;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnD;IAED;;OAEG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhD;IAED;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAG3C;IAEK,gBAAgB,CAAC,qBAAqB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAO1G;IAEK,qBAAqB,IAAI,OAAO,CAAC,+BAA+B,CAAC,CAEtE;IAEK,kBAAkB,IAAI,OAAO,CAAC,+BAA+B,CAAC,CAEnE;IAEK,mBAAmB,IAAI,OAAO,CAAC,+BAA+B,CAAC,CAEpE;IAEK,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAG1C;IAEK,aAAa,CAAC,eAAe,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAGtE;IAEK,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAGzE;IAEK,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAGzD;IAEK,cAAc,IAAI,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAG1D;IAEK,YAAY,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAGjD;IAEK,YAAY,CACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,0BAA0B,GACvC,OAAO,CAAC,YAAY,CAAC,CAOvB;IAEK,eAAe,CAAC,MAAM,EAAE,0BAA0B,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAGtF;IAEK,eAAe,CACpB,eAAe,EAAE,MAAM,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,8BAA8B,GACpC,OAAO,CAAC,YAAY,CAAC,CAOvB;IAEK,OAAO,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAG9D;IAEK,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtD;IAED;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAG9C;IAMD;;;OAGG;IACH,WAAW,CAAC,OAAO,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB1C;IAED;;OAEG;IACH,aAAa,CAAC,OAAO,SAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAEpD;IAED,OAAO,CAAC,qBAAqB;IA+B7B;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,EAAE,OAAO,SAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAWpG;IAMD,OAAO,CAAC,UAAU;YAmCJ,IAAI;IA+BlB,OAAO,CAAC,OAAO;CAUf","sourcesContent":["/**\n * RPC Client for programmatic access to the coding agent.\n *\n * Spawns the agent in RPC mode and provides a typed API for all operations.\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport {\n\ttype AgentEvent,\n\ttype AgentMessage,\n\tAgentOutputLimitError,\n\ttype ThinkingLevel,\n} from \"@ponythewhite/base-context-agent\";\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionMessageReceipt, AgentSessionMessageSafetyStatus } from \"../../core/agent-messages.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\nimport type { CompactionResult } from \"../../core/compaction/index.js\";\nimport type {\n\tAgentCronJob,\n\tAgentHeartbeatDeliveryMode,\n\tAgentHeartbeatManagementAction,\n\tAgentHeartbeatUpdateAction,\n} from \"../../core/cron-jobs.js\";\nimport type { RefinementResult } from \"../../core/refinement/index.js\";\nimport type { SessionStats } from \"../../core/session-stats.js\";\nimport type { AgentConnectionHeartbeat } from \"../agent-connection/types.js\";\nimport { CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY, DAEMON_PROTOCOL_VERSION } from \"../daemon/daemon-protocol.js\";\nimport { attachJsonlLineReader, serializeJsonLine } from \"./jsonl.js\";\nimport type {\n\tRpcCommand,\n\tRpcObservedSessionEvent,\n\tRpcPromptCompletionError,\n\tRpcResponse,\n\tRpcSessionState,\n\tRpcSlashCommand,\n} from \"./rpc-types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nfunction promptCompletionError(event: AgentEvent): string | undefined {\n\tconst output = event as AgentEvent | RpcPromptCompletionError;\n\tif (\n\t\toutput.type === \"extension_error\" &&\n\t\toutput.extensionPath === \"<session-input>\" &&\n\t\toutput.event === \"prompt_completion\"\n\t)\n\t\treturn output.error;\n\treturn undefined;\n}\n\n/** Extended response timeout for refine requests, which run an LLM pass. */\nexport const REFINE_REQUEST_TIMEOUT_MS = 10 * 60 * 1000;\n\n/** Distributive Omit that works with union types */\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;\n\n/** RpcCommand without the id field (for internal send) */\ntype RpcCommandBody = DistributiveOmit<RpcCommand, \"id\">;\n\nexport interface RpcClientOptions {\n\t/** Path to the CLI entry point (default: searches for dist/cli.js) */\n\tcliPath?: string;\n\t/** Working directory for the agent */\n\tcwd?: string;\n\t/** Environment variables */\n\tenv?: Record<string, string>;\n\t/** Provider to use */\n\tprovider?: string;\n\t/** Model ID to use */\n\tmodel?: string;\n\t/** Additional CLI arguments */\n\targs?: string[];\n}\n\nexport interface ModelInfo {\n\tprovider: string;\n\tid: string;\n\tcontextWindow: number;\n\treasoning: boolean;\n}\n\nexport type RpcEventListener = (event: AgentEvent) => void;\nexport type RpcObservedSessionListener = (event: RpcObservedSessionEvent) => void;\n\n// ============================================================================\n// RPC Client\n// ============================================================================\n\nexport class RpcClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate stopReadingStdout: (() => void) | null = null;\n\tprivate eventListeners: RpcEventListener[] = [];\n\tprivate observedSessionListeners: RpcObservedSessionListener[] = [];\n\tprivate pendingRequests: Map<string, { resolve: (response: RpcResponse) => void; reject: (error: Error) => void }> =\n\t\tnew Map();\n\tprivate requestId = 0;\n\tprivate stderr = \"\";\n\n\tconstructor(private options: RpcClientOptions = {}) {}\n\n\t/**\n\t * Start the RPC agent process.\n\t */\n\tasync start(): Promise<void> {\n\t\tif (this.process) {\n\t\t\tthrow new Error(\"Client already started\");\n\t\t}\n\n\t\tconst cliPath = this.options.cliPath ?? \"dist/cli.js\";\n\t\tconst args = [\"--mode\", \"rpc\", \"--rpc-protocol-version\", String(DAEMON_PROTOCOL_VERSION)];\n\n\t\tif (this.options.provider) {\n\t\t\targs.push(\"--provider\", this.options.provider);\n\t\t}\n\t\tif (this.options.model) {\n\t\t\targs.push(\"--model\", this.options.model);\n\t\t}\n\t\tif (this.options.args) {\n\t\t\targs.push(...this.options.args);\n\t\t}\n\n\t\tthis.process = spawn(\"node\", [cliPath, ...args], {\n\t\t\tcwd: this.options.cwd,\n\t\t\tenv: { ...process.env, ...this.options.env },\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\t// Collect stderr for debugging\n\t\tthis.process.stderr?.on(\"data\", (data) => {\n\t\t\tthis.stderr += data.toString();\n\t\t\tprocess.stderr.write(data);\n\t\t});\n\n\t\t// Set up strict JSONL reader for stdout.\n\t\tthis.stopReadingStdout = attachJsonlLineReader(this.process.stdout!, (line) => {\n\t\t\tthis.handleLine(line);\n\t\t});\n\n\t\t// Wait a moment for process to initialize\n\t\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\n\t\tif (this.process.exitCode !== null) {\n\t\t\tthrow new Error(`Agent process exited immediately with code ${this.process.exitCode}. Stderr: ${this.stderr}`);\n\t\t}\n\t\ttry {\n\t\t\tconst state = await this.getState();\n\t\t\tif (state.protocolVersion !== DAEMON_PROTOCOL_VERSION)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC protocol: expected ${DAEMON_PROTOCOL_VERSION}, got ${state.protocolVersion ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t\tconst minimumSchema = CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY.minSchemaRevision;\n\t\t\tif (!Number.isSafeInteger(state.schemaRevision) || (state.schemaRevision ?? 0) < minimumSchema)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC schema: expected at least ${minimumSchema}, got ${state.schemaRevision ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait this.stop();\n\t\t\t} catch (cleanupError) {\n\t\t\t\tthrow new AggregateError([error, cleanupError], \"RPC startup and cleanup failed\", { cause: error });\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Stop the RPC agent process.\n\t */\n\tasync stop(): Promise<void> {\n\t\tif (!this.process) return;\n\n\t\tthis.stopReadingStdout?.();\n\t\tthis.stopReadingStdout = null;\n\t\tthis.process.kill(\"SIGTERM\");\n\n\t\t// Wait for process to exit\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\tthis.process?.kill(\"SIGKILL\");\n\t\t\t\tresolve();\n\t\t\t}, 1000);\n\n\t\t\tthis.process?.on(\"exit\", () => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\n\t\tthis.process = null;\n\t\tthis.pendingRequests.clear();\n\t}\n\n\t/**\n\t * Subscribe to agent events.\n\t */\n\tonEvent(listener: RpcEventListener): () => void {\n\t\tthis.eventListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.eventListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.eventListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\tonObservedSessionEvent(listener: RpcObservedSessionListener): () => void {\n\t\tthis.observedSessionListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.observedSessionListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.observedSessionListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Get collected stderr output (useful for debugging).\n\t */\n\tgetStderr(): string {\n\t\treturn this.stderr;\n\t}\n\n\t// =========================================================================\n\t// Command Methods\n\t// =========================================================================\n\n\t/**\n\t * Send a prompt to the agent.\n\t * Resolves after admission succeeds; use onEvent() to receive streaming events.\n\t * Use waitForIdle() to wait for completion.\n\t */\n\tasync prompt(message: string, images?: ImageContent[]): Promise<void> {\n\t\tthis.getData(await this.send({ type: \"prompt\", message, images }));\n\t}\n\n\t/**\n\t * Queue a steering message to interrupt the agent mid-run.\n\t */\n\tasync steer(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"steer\", message, images });\n\t}\n\n\t/**\n\t * Queue a follow-up message to be processed after the agent finishes.\n\t */\n\tasync followUp(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"follow_up\", message, images });\n\t}\n\n\t/**\n\t * Abort current operation.\n\t */\n\tasync abort(): Promise<void> {\n\t\tawait this.send({ type: \"abort\" });\n\t}\n\n\t/**\n\t * Start a new session, optionally with parent tracking.\n\t * @param parentSession - Optional parent session path for lineage tracking\n\t * @returns Object with `cancelled: true` if an extension cancelled the new session\n\t */\n\tasync newSession(parentSession?: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"new_session\", parentSession });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get current session state.\n\t */\n\tasync getState(): Promise<RpcSessionState> {\n\t\tconst response = await this.send({ type: \"get_state\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set model by provider and ID.\n\t */\n\tasync setModel(provider: string, modelId: string): Promise<{ provider: string; id: string }> {\n\t\tconst response = await this.send({ type: \"set_model\", provider, modelId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Cycle to next model.\n\t */\n\tasync cycleModel(): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: ThinkingLevel;\n\t\tisScoped: boolean;\n\t} | null> {\n\t\tconst response = await this.send({ type: \"cycle_model\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get list of available models.\n\t */\n\tasync getAvailableModels(): Promise<ModelInfo[]> {\n\t\tconst response = await this.send({ type: \"get_available_models\" });\n\t\treturn this.getData<{ models: ModelInfo[] }>(response).models;\n\t}\n\n\t/**\n\t * Set thinking level.\n\t */\n\tasync setThinkingLevel(level: ThinkingLevel): Promise<void> {\n\t\tawait this.send({ type: \"set_thinking_level\", level });\n\t}\n\n\t/**\n\t * Cycle thinking level.\n\t */\n\tasync cycleThinkingLevel(): Promise<{ level: ThinkingLevel } | null> {\n\t\tconst response = await this.send({ type: \"cycle_thinking_level\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set steering mode.\n\t */\n\tasync setSteeringMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_steering_mode\", mode });\n\t}\n\n\t/**\n\t * Set follow-up mode.\n\t */\n\tasync setFollowUpMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_follow_up_mode\", mode });\n\t}\n\n\t/**\n\t * Compact session context.\n\t */\n\tasync compact(customInstructions?: string): Promise<CompactionResult> {\n\t\tconst response = await this.send({ type: \"compact\", customInstructions });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Refine editable continual harness state.\n\t */\n\tasync refine(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean } = {},\n\t): Promise<RefinementResult> {\n\t\t// Refinement runs an LLM pass that routinely exceeds the default 30s response\n\t\t// timeout, so use the same extended window as the daemon refine path.\n\t\tconst command = { type: \"refine\", instructions: options.instructions, rollbackId: options.rollbackId } as {\n\t\t\ttype: \"refine\";\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t};\n\t\tif (options.global !== undefined) {\n\t\t\tcommand.global = options.global;\n\t\t}\n\t\tconst response = await this.send(command, REFINE_REQUEST_TIMEOUT_MS);\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set auto-compaction enabled/disabled.\n\t */\n\tasync setAutoCompaction(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_compaction\", enabled });\n\t}\n\n\t/**\n\t * Set auto-retry enabled/disabled.\n\t */\n\tasync setAutoRetry(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_retry\", enabled });\n\t}\n\n\t/**\n\t * Abort in-progress retry.\n\t */\n\tasync abortRetry(): Promise<void> {\n\t\tawait this.send({ type: \"abort_retry\" });\n\t}\n\n\t/**\n\t * Execute a bash command.\n\t */\n\tasync bash(command: string): Promise<BashResult> {\n\t\tconst response = await this.send({ type: \"bash\", command });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Abort running bash command.\n\t */\n\tasync abortBash(): Promise<void> {\n\t\tawait this.send({ type: \"abort_bash\" });\n\t}\n\n\t/**\n\t * Get session statistics.\n\t */\n\tasync getSessionStats(): Promise<SessionStats> {\n\t\tconst response = await this.send({ type: \"get_session_stats\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Export session to HTML.\n\t */\n\tasync exportHtml(outputPath?: string): Promise<{ path: string }> {\n\t\tconst response = await this.send({ type: \"export_html\", outputPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Switch to a different session file.\n\t * @returns Object with `cancelled: true` if an extension cancelled the switch\n\t */\n\tasync switchSession(sessionPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"switch_session\", sessionPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Fork from a specific message.\n\t * @returns Object with `text` (the message text) and `cancelled` (if extension cancelled)\n\t */\n\tasync fork(entryId: string): Promise<{ text: string; cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"fork\", entryId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Clone the current active branch into a new session.\n\t * @returns Object with `cancelled: true` if an extension cancelled the clone\n\t */\n\tasync clone(): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"clone\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get messages available for forking.\n\t */\n\tasync getForkMessages(): Promise<Array<{ entryId: string; text: string }>> {\n\t\tconst response = await this.send({ type: \"get_fork_messages\" });\n\t\treturn this.getData<{ messages: Array<{ entryId: string; text: string }> }>(response).messages;\n\t}\n\n\t/**\n\t * Get text of last assistant message.\n\t */\n\tasync getLastAssistantText(): Promise<string | null> {\n\t\tconst response = await this.send({ type: \"get_last_assistant_text\" });\n\t\treturn this.getData<{ text: string | null }>(response).text;\n\t}\n\n\t/**\n\t * Set the session display name.\n\t */\n\tasync setSessionName(name: string): Promise<void> {\n\t\tawait this.send({ type: \"set_session_name\", name });\n\t}\n\n\t/**\n\t * Get all messages in the session.\n\t */\n\tasync getMessages(): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"get_messages\" });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync sendAgentMessage(targetActiveSessionId: string, message: string): Promise<AgentSessionMessageReceipt> {\n\t\tconst response = await this.send({\n\t\t\ttype: \"send_message\",\n\t\t\ttargetActiveSessionId,\n\t\t\tmessage,\n\t\t});\n\t\treturn this.getData(response);\n\t}\n\n\tasync getAgentMessageStatus(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_status\" }));\n\t}\n\n\tasync pauseAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_pause\" }));\n\t}\n\n\tasync resumeAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_resume\" }));\n\t}\n\n\tasync clearAgentMessages(): Promise<number> {\n\t\tconst response = await this.send({ type: \"agent_messages_clear\" });\n\t\treturn this.getData<{ cleared: number }>(response).cleared;\n\t}\n\n\tasync listSchedules(includeInactive?: boolean): Promise<AgentCronJob[]> {\n\t\tconst response = await this.send({ type: \"list_schedules\", includeInactive });\n\t\treturn this.getData<{ jobs: AgentCronJob[] }>(response).jobs;\n\t}\n\n\tasync addSchedule(schedule: string, prompt: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"add_schedule\", schedule, prompt });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync cancelSchedule(jobId: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"cancel_schedule\", jobId });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync listHeartbeats(): Promise<AgentConnectionHeartbeat[]> {\n\t\tconst response = await this.send({ type: \"list_heartbeats\" });\n\t\treturn this.getData<{ heartbeats: AgentConnectionHeartbeat[] }>(response).heartbeats;\n\t}\n\n\tasync getHeartbeat(): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"get_heartbeat\" });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync setHeartbeat(\n\t\tschedule: string,\n\t\tprompt: string,\n\t\tdeliveryMode?: AgentHeartbeatDeliveryMode,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"set_heartbeat\", schedule, prompt, deliveryMode });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the created heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync updateHeartbeat(action: AgentHeartbeatUpdateAction): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"update_heartbeat\", action });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync manageHeartbeat(\n\t\tactiveSessionId: string,\n\t\tjobId: string,\n\t\taction: AgentHeartbeatManagementAction,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"manage_heartbeat\", activeSessionId, jobId, action });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the managed heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync observe(activeSessionId: string): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"observe\", activeSessionId });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync unobserve(activeSessionId: string): Promise<void> {\n\t\tawait this.send({ type: \"unobserve\", activeSessionId });\n\t}\n\n\t/**\n\t * Get available commands (extension commands, prompt templates, skills).\n\t */\n\tasync getCommands(): Promise<RpcSlashCommand[]> {\n\t\tconst response = await this.send({ type: \"get_commands\" });\n\t\treturn this.getData<{ commands: RpcSlashCommand[] }>(response).commands;\n\t}\n\n\t// =========================================================================\n\t// Helpers\n\t// =========================================================================\n\n\t/**\n\t * Wait for agent to become idle (no streaming).\n\t * Resolves when agent_end event is received.\n\t */\n\twaitForIdle(timeout = 60000): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tunsubscribe();\n\t\t\t\treject(new Error(`Timeout waiting for agent to become idle. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t} else if (event.type === \"agent_end\") {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Collect events until agent becomes idle.\n\t */\n\tcollectEvents(timeout = 60000): Promise<AgentEvent[]> {\n\t\treturn this.createEventCollection(timeout).result;\n\t}\n\n\tprivate createEventCollection(timeout: number): { result: Promise<AgentEvent[]>; cancel: () => void } {\n\t\tlet cancel = () => {};\n\t\tconst result = new Promise<AgentEvent[]>((resolve, reject) => {\n\t\t\tconst events: AgentEvent[] = [];\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tcancel();\n\t\t\t\treject(new Error(`Timeout collecting events. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tevents.push(event);\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tcancel();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.type === \"agent_end\") {\n\t\t\t\t\tcancel();\n\t\t\t\t\tresolve(events);\n\t\t\t\t}\n\t\t\t});\n\t\t\tcancel = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tunsubscribe();\n\t\t\t\tcancel = () => {};\n\t\t\t};\n\t\t});\n\t\treturn { result, cancel: () => cancel() };\n\t}\n\n\t/**\n\t * Send prompt and wait for completion, returning all events.\n\t */\n\tasync promptAndWait(message: string, images?: ImageContent[], timeout = 60000): Promise<AgentEvent[]> {\n\t\tconst collection = this.createEventCollection(timeout);\n\t\tlet events: AgentEvent[];\n\t\ttry {\n\t\t\t[, events] = await Promise.all([this.prompt(message, images), collection.result]);\n\t\t} finally {\n\t\t\tcollection.cancel();\n\t\t}\n\t\tconst terminal = events.find((event) => event.type === \"agent_end\");\n\t\tif (terminal?.type === \"agent_end\" && terminal.refusal) throw new AgentOutputLimitError(terminal.refusal);\n\t\treturn events;\n\t}\n\n\t// =========================================================================\n\t// Internal\n\t// =========================================================================\n\n\tprivate handleLine(line: string): void {\n\t\ttry {\n\t\t\tconst data = JSON.parse(line);\n\n\t\t\t// Check if it's a response to a pending request\n\t\t\tif (data.type === \"response\" && data.id && this.pendingRequests.has(data.id)) {\n\t\t\t\tconst pending = this.pendingRequests.get(data.id)!;\n\t\t\t\tthis.pendingRequests.delete(data.id);\n\t\t\t\tpending.resolve(data as RpcResponse);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (data.type === \"observed_session_event\" || data.type === \"observed_session_closed\") {\n\t\t\t\tfor (const listener of [...this.observedSessionListeners]) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener(data as RpcObservedSessionEvent);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise it's an event\n\t\t\tfor (const listener of [...this.eventListeners]) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(data as AgentEvent);\n\t\t\t\t} catch {\n\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore non-JSON lines\n\t\t}\n\t}\n\n\tprivate async send(command: RpcCommandBody, timeoutMs = 30000): Promise<RpcResponse> {\n\t\tif (!this.process?.stdin) {\n\t\t\tthrow new Error(\"Client not started\");\n\t\t}\n\n\t\tconst id = `req_${++this.requestId}`;\n\t\tconst fullCommand = { ...command, id } as RpcCommand;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.pendingRequests.set(id, { resolve, reject });\n\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\tthis.pendingRequests.delete(id);\n\t\t\t\treject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));\n\t\t\t}, timeoutMs);\n\n\t\t\tthis.pendingRequests.set(id, {\n\t\t\t\tresolve: (response) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tresolve(response);\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthis.process!.stdin!.write(serializeJsonLine(fullCommand));\n\t\t});\n\t}\n\n\tprivate getData<T>(response: RpcResponse): T {\n\t\tif (!response.success) {\n\t\t\tconst errorResponse = response as Extract<RpcResponse, { success: false }>;\n\t\t\tthrow new Error(errorResponse.error);\n\t\t}\n\t\t// Type assertion: we trust response.data matches T based on the command sent.\n\t\t// This is safe because each public method specifies the correct T for its command.\n\t\tconst successResponse = response as Extract<RpcResponse, { success: true; data: unknown }>;\n\t\treturn successResponse.data as T;\n\t}\n}\n"]}
1
+ {"version":3,"file":"rpc-client.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC Client for programmatic access to the coding agent.\n *\n * Spawns the agent in RPC mode and provides a typed API for all operations.\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport {\n\ttype AgentEvent,\n\ttype AgentMessage,\n\tAgentOutputLimitError,\n\ttype ThinkingLevel,\n} from \"@ponythewhite/base-context-agent\";\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionMessageReceipt, AgentSessionMessageSafetyStatus } from \"../../core/agent-messages.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\nimport type { CompactionResult } from \"../../core/compaction/index.js\";\nimport type {\n\tAgentCronJob,\n\tAgentHeartbeatDeliveryMode,\n\tAgentHeartbeatManagementAction,\n\tAgentHeartbeatUpdateAction,\n} from \"../../core/cron-jobs.js\";\nimport type { RefinementResult } from \"../../core/refinement/index.js\";\nimport type { SessionStats } from \"../../core/session-stats.js\";\nimport type { AgentConnectionHeartbeat } from \"../agent-connection/types.js\";\nimport { CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY, DAEMON_PROTOCOL_VERSION } from \"../daemon/daemon-protocol.js\";\nimport { attachJsonlLineReader, serializeJsonLine } from \"./jsonl.js\";\nimport type {\n\tRpcCommand,\n\tRpcObservedSessionEvent,\n\tRpcPromptCompletionError,\n\tRpcResponse,\n\tRpcSessionState,\n\tRpcSlashCommand,\n} from \"./rpc-types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nfunction promptCompletionError(event: AgentEvent): string | undefined {\n\tconst output = event as AgentEvent | RpcPromptCompletionError;\n\tif (\n\t\toutput.type === \"extension_error\" &&\n\t\toutput.extensionPath === \"<session-input>\" &&\n\t\toutput.event === \"prompt_completion\"\n\t)\n\t\treturn output.error;\n\treturn undefined;\n}\n\n/** Extended response timeout for refine requests, which run an LLM pass. */\nexport const REFINE_REQUEST_TIMEOUT_MS = 10 * 60 * 1000;\n\n/** Distributive Omit that works with union types */\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;\n\n/** RpcCommand without the id field (for internal send) */\ntype RpcCommandBody = DistributiveOmit<RpcCommand, \"id\">;\n\nexport interface RpcClientOptions {\n\t/** Path to the CLI entry point (default: searches for dist/cli.js) */\n\tcliPath?: string;\n\t/** Working directory for the agent */\n\tcwd?: string;\n\t/** Environment variables */\n\tenv?: Record<string, string>;\n\t/** Provider to use */\n\tprovider?: string;\n\t/** Model ID to use */\n\tmodel?: string;\n\t/** Additional CLI arguments */\n\targs?: string[];\n}\n\nexport interface ModelInfo {\n\tprovider: string;\n\tid: string;\n\tcontextWindow: number;\n\treasoning: boolean;\n}\n\nexport type RpcEventListener = (event: AgentEvent) => void;\nexport type RpcObservedSessionListener = (event: RpcObservedSessionEvent) => void;\n\n// ============================================================================\n// RPC Client\n// ============================================================================\n\nexport class RpcClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate stopReadingStdout: (() => void) | null = null;\n\tprivate eventListeners: RpcEventListener[] = [];\n\tprivate observedSessionListeners: RpcObservedSessionListener[] = [];\n\tprivate pendingRequests: Map<string, { resolve: (response: RpcResponse) => void; reject: (error: Error) => void }> =\n\t\tnew Map();\n\tprivate requestId = 0;\n\tprivate stderr = \"\";\n\n\tconstructor(private options: RpcClientOptions = {}) {}\n\n\t/**\n\t * Start the RPC agent process.\n\t */\n\tasync start(): Promise<void> {\n\t\tif (this.process) {\n\t\t\tthrow new Error(\"Client already started\");\n\t\t}\n\n\t\tconst cliPath = this.options.cliPath ?? \"dist/cli.js\";\n\t\tconst args = [\"--mode\", \"rpc\", \"--rpc-protocol-version\", String(DAEMON_PROTOCOL_VERSION)];\n\n\t\tif (this.options.provider) {\n\t\t\targs.push(\"--provider\", this.options.provider);\n\t\t}\n\t\tif (this.options.model) {\n\t\t\targs.push(\"--model\", this.options.model);\n\t\t}\n\t\tif (this.options.args) {\n\t\t\targs.push(...this.options.args);\n\t\t}\n\n\t\tconst child = spawn(\"node\", [cliPath, ...args], {\n\t\t\tcwd: this.options.cwd,\n\t\t\tenv: { ...process.env, ...this.options.env },\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t});\n\t\tthis.process = child;\n\t\tthis.stderr = \"\";\n\n\t\t// Collect stderr for debugging\n\t\tchild.stderr?.on(\"data\", (data) => {\n\t\t\tif (this.process !== child) return;\n\t\t\tthis.stderr += data.toString();\n\t\t\tprocess.stderr.write(data);\n\t\t});\n\t\tchild.once(\"error\", (error) => {\n\t\t\tif (this.process === child) this.rejectPendingRequests(error);\n\t\t});\n\t\t// Drain final stdout/stderr before rejecting requests that received no response.\n\t\tchild.once(\"close\", () => {\n\t\t\tif (this.process === child) this.rejectPendingRequests(this.processExitError(child));\n\t\t});\n\n\t\t// Set up strict JSONL reader for stdout.\n\t\tthis.stopReadingStdout = attachJsonlLineReader(child.stdout!, (line) => {\n\t\t\tif (this.process === child) this.handleLine(line);\n\t\t});\n\n\t\ttry {\n\t\t\tconst state = await this.getState();\n\t\t\tif (state.protocolVersion !== DAEMON_PROTOCOL_VERSION)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC protocol: expected ${DAEMON_PROTOCOL_VERSION}, got ${state.protocolVersion ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t\tconst minimumSchema = CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY.minSchemaRevision;\n\t\t\tif (!Number.isSafeInteger(state.schemaRevision) || (state.schemaRevision ?? 0) < minimumSchema)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC schema: expected at least ${minimumSchema}, got ${state.schemaRevision ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (this.process === child) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.stop();\n\t\t\t\t} catch (cleanupError) {\n\t\t\t\t\tthrow new AggregateError([error, cleanupError], \"RPC startup and cleanup failed\", { cause: error });\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Stop the RPC agent process.\n\t */\n\tasync stop(): Promise<void> {\n\t\tconst child = this.process;\n\t\tif (!child) return;\n\n\t\tthis.stopReadingStdout?.();\n\t\tthis.stopReadingStdout = null;\n\n\t\tif (child.exitCode === null && child.signalCode === null) {\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t\tresolve();\n\t\t\t\t}, 1000);\n\n\t\t\t\tchild.once(\"exit\", () => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t});\n\t\t}\n\n\t\tif (this.process === child) {\n\t\t\tthis.process = null;\n\t\t\tthis.rejectPendingRequests(new Error(\"RPC client stopped\"));\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to agent events.\n\t */\n\tonEvent(listener: RpcEventListener): () => void {\n\t\tthis.eventListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.eventListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.eventListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\tonObservedSessionEvent(listener: RpcObservedSessionListener): () => void {\n\t\tthis.observedSessionListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.observedSessionListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.observedSessionListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Get collected stderr output (useful for debugging).\n\t */\n\tgetStderr(): string {\n\t\treturn this.stderr;\n\t}\n\n\t// =========================================================================\n\t// Command Methods\n\t// =========================================================================\n\n\t/**\n\t * Send a prompt to the agent.\n\t * Resolves after admission succeeds; use onEvent() to receive streaming events.\n\t * Use waitForIdle() to wait for completion.\n\t */\n\tasync prompt(message: string, images?: ImageContent[]): Promise<void> {\n\t\tthis.getData(await this.send({ type: \"prompt\", message, images }));\n\t}\n\n\t/**\n\t * Queue a steering message to interrupt the agent mid-run.\n\t */\n\tasync steer(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"steer\", message, images });\n\t}\n\n\t/**\n\t * Queue a follow-up message to be processed after the agent finishes.\n\t */\n\tasync followUp(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"follow_up\", message, images });\n\t}\n\n\t/**\n\t * Abort current operation.\n\t */\n\tasync abort(): Promise<void> {\n\t\tawait this.send({ type: \"abort\" });\n\t}\n\n\t/**\n\t * Start a new session, optionally with parent tracking.\n\t * @param parentSession - Optional parent session path for lineage tracking\n\t * @returns Object with `cancelled: true` if an extension cancelled the new session\n\t */\n\tasync newSession(parentSession?: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"new_session\", parentSession });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get current session state.\n\t */\n\tasync getState(): Promise<RpcSessionState> {\n\t\tconst response = await this.send({ type: \"get_state\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set model by provider and ID.\n\t */\n\tasync setModel(provider: string, modelId: string): Promise<{ provider: string; id: string }> {\n\t\tconst response = await this.send({ type: \"set_model\", provider, modelId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Cycle to next model.\n\t */\n\tasync cycleModel(): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: ThinkingLevel;\n\t\tisScoped: boolean;\n\t} | null> {\n\t\tconst response = await this.send({ type: \"cycle_model\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get list of available models.\n\t */\n\tasync getAvailableModels(): Promise<ModelInfo[]> {\n\t\tconst response = await this.send({ type: \"get_available_models\" });\n\t\treturn this.getData<{ models: ModelInfo[] }>(response).models;\n\t}\n\n\t/**\n\t * Set thinking level.\n\t */\n\tasync setThinkingLevel(level: ThinkingLevel): Promise<void> {\n\t\tawait this.send({ type: \"set_thinking_level\", level });\n\t}\n\n\t/**\n\t * Cycle thinking level.\n\t */\n\tasync cycleThinkingLevel(): Promise<{ level: ThinkingLevel } | null> {\n\t\tconst response = await this.send({ type: \"cycle_thinking_level\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set steering mode.\n\t */\n\tasync setSteeringMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_steering_mode\", mode });\n\t}\n\n\t/**\n\t * Set follow-up mode.\n\t */\n\tasync setFollowUpMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_follow_up_mode\", mode });\n\t}\n\n\t/**\n\t * Compact session context.\n\t */\n\tasync compact(customInstructions?: string): Promise<CompactionResult> {\n\t\tconst response = await this.send({ type: \"compact\", customInstructions });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Refine editable continual harness state.\n\t */\n\tasync refine(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean } = {},\n\t): Promise<RefinementResult> {\n\t\t// Refinement runs an LLM pass that routinely exceeds the default 30s response\n\t\t// timeout, so use the same extended window as the daemon refine path.\n\t\tconst command = { type: \"refine\", instructions: options.instructions, rollbackId: options.rollbackId } as {\n\t\t\ttype: \"refine\";\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t};\n\t\tif (options.global !== undefined) {\n\t\t\tcommand.global = options.global;\n\t\t}\n\t\tconst response = await this.send(command, REFINE_REQUEST_TIMEOUT_MS);\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set auto-compaction enabled/disabled.\n\t */\n\tasync setAutoCompaction(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_compaction\", enabled });\n\t}\n\n\t/**\n\t * Set auto-retry enabled/disabled.\n\t */\n\tasync setAutoRetry(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_retry\", enabled });\n\t}\n\n\t/**\n\t * Abort in-progress retry.\n\t */\n\tasync abortRetry(): Promise<void> {\n\t\tawait this.send({ type: \"abort_retry\" });\n\t}\n\n\t/**\n\t * Execute a bash command.\n\t */\n\tasync bash(command: string): Promise<BashResult> {\n\t\tconst response = await this.send({ type: \"bash\", command });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Abort running bash command.\n\t */\n\tasync abortBash(): Promise<void> {\n\t\tawait this.send({ type: \"abort_bash\" });\n\t}\n\n\t/**\n\t * Get session statistics.\n\t */\n\tasync getSessionStats(): Promise<SessionStats> {\n\t\tconst response = await this.send({ type: \"get_session_stats\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Export session to HTML.\n\t */\n\tasync exportHtml(outputPath?: string): Promise<{ path: string }> {\n\t\tconst response = await this.send({ type: \"export_html\", outputPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Switch to a different session file.\n\t * @returns Object with `cancelled: true` if an extension cancelled the switch\n\t */\n\tasync switchSession(sessionPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"switch_session\", sessionPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Fork from a specific message.\n\t * @returns Object with `text` (the message text) and `cancelled` (if extension cancelled)\n\t */\n\tasync fork(entryId: string): Promise<{ text: string; cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"fork\", entryId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Clone the current active branch into a new session.\n\t * @returns Object with `cancelled: true` if an extension cancelled the clone\n\t */\n\tasync clone(): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"clone\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get messages available for forking.\n\t */\n\tasync getForkMessages(): Promise<Array<{ entryId: string; text: string }>> {\n\t\tconst response = await this.send({ type: \"get_fork_messages\" });\n\t\treturn this.getData<{ messages: Array<{ entryId: string; text: string }> }>(response).messages;\n\t}\n\n\t/**\n\t * Get text of last assistant message.\n\t */\n\tasync getLastAssistantText(): Promise<string | null> {\n\t\tconst response = await this.send({ type: \"get_last_assistant_text\" });\n\t\treturn this.getData<{ text: string | null }>(response).text;\n\t}\n\n\t/**\n\t * Set the session display name.\n\t */\n\tasync setSessionName(name: string): Promise<void> {\n\t\tawait this.send({ type: \"set_session_name\", name });\n\t}\n\n\t/**\n\t * Get all messages in the session.\n\t */\n\tasync getMessages(): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"get_messages\" });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync sendAgentMessage(targetActiveSessionId: string, message: string): Promise<AgentSessionMessageReceipt> {\n\t\tconst response = await this.send({\n\t\t\ttype: \"send_message\",\n\t\t\ttargetActiveSessionId,\n\t\t\tmessage,\n\t\t});\n\t\treturn this.getData(response);\n\t}\n\n\tasync getAgentMessageStatus(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_status\" }));\n\t}\n\n\tasync pauseAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_pause\" }));\n\t}\n\n\tasync resumeAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_resume\" }));\n\t}\n\n\tasync clearAgentMessages(): Promise<number> {\n\t\tconst response = await this.send({ type: \"agent_messages_clear\" });\n\t\treturn this.getData<{ cleared: number }>(response).cleared;\n\t}\n\n\tasync listSchedules(includeInactive?: boolean): Promise<AgentCronJob[]> {\n\t\tconst response = await this.send({ type: \"list_schedules\", includeInactive });\n\t\treturn this.getData<{ jobs: AgentCronJob[] }>(response).jobs;\n\t}\n\n\tasync addSchedule(schedule: string, prompt: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"add_schedule\", schedule, prompt });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync cancelSchedule(jobId: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"cancel_schedule\", jobId });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync listHeartbeats(): Promise<AgentConnectionHeartbeat[]> {\n\t\tconst response = await this.send({ type: \"list_heartbeats\" });\n\t\treturn this.getData<{ heartbeats: AgentConnectionHeartbeat[] }>(response).heartbeats;\n\t}\n\n\tasync getHeartbeat(): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"get_heartbeat\" });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync setHeartbeat(\n\t\tschedule: string,\n\t\tprompt: string,\n\t\tdeliveryMode?: AgentHeartbeatDeliveryMode,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"set_heartbeat\", schedule, prompt, deliveryMode });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the created heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync updateHeartbeat(action: AgentHeartbeatUpdateAction): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"update_heartbeat\", action });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync manageHeartbeat(\n\t\tactiveSessionId: string,\n\t\tjobId: string,\n\t\taction: AgentHeartbeatManagementAction,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"manage_heartbeat\", activeSessionId, jobId, action });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the managed heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync observe(activeSessionId: string): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"observe\", activeSessionId });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync unobserve(activeSessionId: string): Promise<void> {\n\t\tawait this.send({ type: \"unobserve\", activeSessionId });\n\t}\n\n\t/**\n\t * Get available commands (extension commands, prompt templates, skills).\n\t */\n\tasync getCommands(): Promise<RpcSlashCommand[]> {\n\t\tconst response = await this.send({ type: \"get_commands\" });\n\t\treturn this.getData<{ commands: RpcSlashCommand[] }>(response).commands;\n\t}\n\n\t// =========================================================================\n\t// Helpers\n\t// =========================================================================\n\n\t/**\n\t * Wait for agent to become idle (no streaming).\n\t * Resolves when agent_end event is received.\n\t */\n\twaitForIdle(timeout = 60000): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tunsubscribe();\n\t\t\t\treject(new Error(`Timeout waiting for agent to become idle. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t} else if (event.type === \"agent_end\") {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Collect events until agent becomes idle.\n\t */\n\tcollectEvents(timeout = 60000): Promise<AgentEvent[]> {\n\t\treturn this.createEventCollection(timeout).result;\n\t}\n\n\tprivate createEventCollection(timeout: number): { result: Promise<AgentEvent[]>; cancel: () => void } {\n\t\tlet cancel = () => {};\n\t\tconst result = new Promise<AgentEvent[]>((resolve, reject) => {\n\t\t\tconst events: AgentEvent[] = [];\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tcancel();\n\t\t\t\treject(new Error(`Timeout collecting events. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tevents.push(event);\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tcancel();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.type === \"agent_end\") {\n\t\t\t\t\tcancel();\n\t\t\t\t\tresolve(events);\n\t\t\t\t}\n\t\t\t});\n\t\t\tcancel = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tunsubscribe();\n\t\t\t\tcancel = () => {};\n\t\t\t};\n\t\t});\n\t\treturn { result, cancel: () => cancel() };\n\t}\n\n\t/**\n\t * Send prompt and wait for completion, returning all events.\n\t */\n\tasync promptAndWait(message: string, images?: ImageContent[], timeout = 60000): Promise<AgentEvent[]> {\n\t\tconst collection = this.createEventCollection(timeout);\n\t\tlet events: AgentEvent[];\n\t\ttry {\n\t\t\t[, events] = await Promise.all([this.prompt(message, images), collection.result]);\n\t\t} finally {\n\t\t\tcollection.cancel();\n\t\t}\n\t\tconst terminal = events.find((event) => event.type === \"agent_end\");\n\t\tif (terminal?.type === \"agent_end\" && terminal.refusal) throw new AgentOutputLimitError(terminal.refusal);\n\t\treturn events;\n\t}\n\n\t// =========================================================================\n\t// Internal\n\t// =========================================================================\n\n\tprivate processExitError(child: ChildProcess): Error {\n\t\tconst reason = child.signalCode ? `signal ${child.signalCode}` : `code ${child.exitCode}`;\n\t\treturn new Error(`Agent process exited with ${reason}. Stderr: ${this.stderr}`);\n\t}\n\n\tprivate rejectPendingRequests(error: Error): void {\n\t\tfor (const pending of this.pendingRequests.values()) pending.reject(error);\n\t\tthis.pendingRequests.clear();\n\t}\n\n\tprivate handleLine(line: string): void {\n\t\ttry {\n\t\t\tconst data = JSON.parse(line);\n\n\t\t\t// Check if it's a response to a pending request\n\t\t\tif (data.type === \"response\" && data.id && this.pendingRequests.has(data.id)) {\n\t\t\t\tconst pending = this.pendingRequests.get(data.id)!;\n\t\t\t\tthis.pendingRequests.delete(data.id);\n\t\t\t\tpending.resolve(data as RpcResponse);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (data.type === \"observed_session_event\" || data.type === \"observed_session_closed\") {\n\t\t\t\tfor (const listener of [...this.observedSessionListeners]) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener(data as RpcObservedSessionEvent);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise it's an event\n\t\t\tfor (const listener of [...this.eventListeners]) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(data as AgentEvent);\n\t\t\t\t} catch {\n\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore non-JSON lines\n\t\t}\n\t}\n\n\tprivate async send(command: RpcCommandBody, timeoutMs = 30000): Promise<RpcResponse> {\n\t\tconst child = this.process;\n\t\tif (!child?.stdin) {\n\t\t\tthrow new Error(\"Client not started\");\n\t\t}\n\t\tif (child.exitCode !== null || child.signalCode !== null) {\n\t\t\tthrow this.processExitError(child);\n\t\t}\n\n\t\tconst id = `req_${++this.requestId}`;\n\t\tconst fullCommand = { ...command, id } as RpcCommand;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\tthis.pendingRequests.delete(id);\n\t\t\t\treject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));\n\t\t\t}, timeoutMs);\n\n\t\t\tthis.pendingRequests.set(id, {\n\t\t\t\tresolve: (response) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tresolve(response);\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tchild.stdin!.write(serializeJsonLine(fullCommand));\n\t\t});\n\t}\n\n\tprivate getData<T>(response: RpcResponse): T {\n\t\tif (!response.success) {\n\t\t\tconst errorResponse = response as Extract<RpcResponse, { success: false }>;\n\t\t\tthrow new Error(errorResponse.error);\n\t\t}\n\t\t// Type assertion: we trust response.data matches T based on the command sent.\n\t\t// This is safe because each public method specifies the correct T for its command.\n\t\tconst successResponse = response as Extract<RpcResponse, { success: true; data: unknown }>;\n\t\treturn successResponse.data as T;\n\t}\n}\n"]}
@@ -53,25 +53,34 @@ export class RpcClient {
53
53
  if (this.options.args) {
54
54
  args.push(...this.options.args);
55
55
  }
56
- this.process = spawn("node", [cliPath, ...args], {
56
+ const child = spawn("node", [cliPath, ...args], {
57
57
  cwd: this.options.cwd,
58
58
  env: { ...process.env, ...this.options.env },
59
59
  stdio: ["pipe", "pipe", "pipe"],
60
60
  });
61
+ this.process = child;
62
+ this.stderr = "";
61
63
  // Collect stderr for debugging
62
- this.process.stderr?.on("data", (data) => {
64
+ child.stderr?.on("data", (data) => {
65
+ if (this.process !== child)
66
+ return;
63
67
  this.stderr += data.toString();
64
68
  process.stderr.write(data);
65
69
  });
70
+ child.once("error", (error) => {
71
+ if (this.process === child)
72
+ this.rejectPendingRequests(error);
73
+ });
74
+ // Drain final stdout/stderr before rejecting requests that received no response.
75
+ child.once("close", () => {
76
+ if (this.process === child)
77
+ this.rejectPendingRequests(this.processExitError(child));
78
+ });
66
79
  // Set up strict JSONL reader for stdout.
67
- this.stopReadingStdout = attachJsonlLineReader(this.process.stdout, (line) => {
68
- this.handleLine(line);
80
+ this.stopReadingStdout = attachJsonlLineReader(child.stdout, (line) => {
81
+ if (this.process === child)
82
+ this.handleLine(line);
69
83
  });
70
- // Wait a moment for process to initialize
71
- await new Promise((resolve) => setTimeout(resolve, 100));
72
- if (this.process.exitCode !== null) {
73
- throw new Error(`Agent process exited immediately with code ${this.process.exitCode}. Stderr: ${this.stderr}`);
74
- }
75
84
  try {
76
85
  const state = await this.getState();
77
86
  if (state.protocolVersion !== DAEMON_PROTOCOL_VERSION)
@@ -81,11 +90,13 @@ export class RpcClient {
81
90
  throw new Error(`Incompatible RPC schema: expected at least ${minimumSchema}, got ${state.schemaRevision ?? "unversioned"}`);
82
91
  }
83
92
  catch (error) {
84
- try {
85
- await this.stop();
86
- }
87
- catch (cleanupError) {
88
- throw new AggregateError([error, cleanupError], "RPC startup and cleanup failed", { cause: error });
93
+ if (this.process === child) {
94
+ try {
95
+ await this.stop();
96
+ }
97
+ catch (cleanupError) {
98
+ throw new AggregateError([error, cleanupError], "RPC startup and cleanup failed", { cause: error });
99
+ }
89
100
  }
90
101
  throw error;
91
102
  }
@@ -94,24 +105,28 @@ export class RpcClient {
94
105
  * Stop the RPC agent process.
95
106
  */
96
107
  async stop() {
97
- if (!this.process)
108
+ const child = this.process;
109
+ if (!child)
98
110
  return;
99
111
  this.stopReadingStdout?.();
100
112
  this.stopReadingStdout = null;
101
- this.process.kill("SIGTERM");
102
- // Wait for process to exit
103
- await new Promise((resolve) => {
104
- const timeout = setTimeout(() => {
105
- this.process?.kill("SIGKILL");
106
- resolve();
107
- }, 1000);
108
- this.process?.on("exit", () => {
109
- clearTimeout(timeout);
110
- resolve();
113
+ if (child.exitCode === null && child.signalCode === null) {
114
+ await new Promise((resolve) => {
115
+ const timeout = setTimeout(() => {
116
+ child.kill("SIGKILL");
117
+ resolve();
118
+ }, 1000);
119
+ child.once("exit", () => {
120
+ clearTimeout(timeout);
121
+ resolve();
122
+ });
123
+ child.kill("SIGTERM");
111
124
  });
112
- });
113
- this.process = null;
114
- this.pendingRequests.clear();
125
+ }
126
+ if (this.process === child) {
127
+ this.process = null;
128
+ this.rejectPendingRequests(new Error("RPC client stopped"));
129
+ }
115
130
  }
116
131
  /**
117
132
  * Subscribe to agent events.
@@ -505,6 +520,15 @@ export class RpcClient {
505
520
  // =========================================================================
506
521
  // Internal
507
522
  // =========================================================================
523
+ processExitError(child) {
524
+ const reason = child.signalCode ? `signal ${child.signalCode}` : `code ${child.exitCode}`;
525
+ return new Error(`Agent process exited with ${reason}. Stderr: ${this.stderr}`);
526
+ }
527
+ rejectPendingRequests(error) {
528
+ for (const pending of this.pendingRequests.values())
529
+ pending.reject(error);
530
+ this.pendingRequests.clear();
531
+ }
508
532
  handleLine(line) {
509
533
  try {
510
534
  const data = JSON.parse(line);
@@ -541,13 +565,16 @@ export class RpcClient {
541
565
  }
542
566
  }
543
567
  async send(command, timeoutMs = 30000) {
544
- if (!this.process?.stdin) {
568
+ const child = this.process;
569
+ if (!child?.stdin) {
545
570
  throw new Error("Client not started");
546
571
  }
572
+ if (child.exitCode !== null || child.signalCode !== null) {
573
+ throw this.processExitError(child);
574
+ }
547
575
  const id = `req_${++this.requestId}`;
548
576
  const fullCommand = { ...command, id };
549
577
  return new Promise((resolve, reject) => {
550
- this.pendingRequests.set(id, { resolve, reject });
551
578
  const timeout = setTimeout(() => {
552
579
  this.pendingRequests.delete(id);
553
580
  reject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));
@@ -562,7 +589,7 @@ export class RpcClient {
562
589
  reject(error);
563
590
  },
564
591
  });
565
- this.process.stdin.write(serializeJsonLine(fullCommand));
592
+ child.stdin.write(serializeJsonLine(fullCommand));
566
593
  });
567
594
  }
568
595
  getData(response) {
@@ -1 +1 @@
1
- {"version":3,"file":"rpc-client.js","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC Client for programmatic access to the coding agent.\n *\n * Spawns the agent in RPC mode and provides a typed API for all operations.\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport {\n\ttype AgentEvent,\n\ttype AgentMessage,\n\tAgentOutputLimitError,\n\ttype ThinkingLevel,\n} from \"@ponythewhite/base-context-agent\";\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionMessageReceipt, AgentSessionMessageSafetyStatus } from \"../../core/agent-messages.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\nimport type { CompactionResult } from \"../../core/compaction/index.js\";\nimport type {\n\tAgentCronJob,\n\tAgentHeartbeatDeliveryMode,\n\tAgentHeartbeatManagementAction,\n\tAgentHeartbeatUpdateAction,\n} from \"../../core/cron-jobs.js\";\nimport type { RefinementResult } from \"../../core/refinement/index.js\";\nimport type { SessionStats } from \"../../core/session-stats.js\";\nimport type { AgentConnectionHeartbeat } from \"../agent-connection/types.js\";\nimport { CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY, DAEMON_PROTOCOL_VERSION } from \"../daemon/daemon-protocol.js\";\nimport { attachJsonlLineReader, serializeJsonLine } from \"./jsonl.js\";\nimport type {\n\tRpcCommand,\n\tRpcObservedSessionEvent,\n\tRpcPromptCompletionError,\n\tRpcResponse,\n\tRpcSessionState,\n\tRpcSlashCommand,\n} from \"./rpc-types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nfunction promptCompletionError(event: AgentEvent): string | undefined {\n\tconst output = event as AgentEvent | RpcPromptCompletionError;\n\tif (\n\t\toutput.type === \"extension_error\" &&\n\t\toutput.extensionPath === \"<session-input>\" &&\n\t\toutput.event === \"prompt_completion\"\n\t)\n\t\treturn output.error;\n\treturn undefined;\n}\n\n/** Extended response timeout for refine requests, which run an LLM pass. */\nexport const REFINE_REQUEST_TIMEOUT_MS = 10 * 60 * 1000;\n\n/** Distributive Omit that works with union types */\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;\n\n/** RpcCommand without the id field (for internal send) */\ntype RpcCommandBody = DistributiveOmit<RpcCommand, \"id\">;\n\nexport interface RpcClientOptions {\n\t/** Path to the CLI entry point (default: searches for dist/cli.js) */\n\tcliPath?: string;\n\t/** Working directory for the agent */\n\tcwd?: string;\n\t/** Environment variables */\n\tenv?: Record<string, string>;\n\t/** Provider to use */\n\tprovider?: string;\n\t/** Model ID to use */\n\tmodel?: string;\n\t/** Additional CLI arguments */\n\targs?: string[];\n}\n\nexport interface ModelInfo {\n\tprovider: string;\n\tid: string;\n\tcontextWindow: number;\n\treasoning: boolean;\n}\n\nexport type RpcEventListener = (event: AgentEvent) => void;\nexport type RpcObservedSessionListener = (event: RpcObservedSessionEvent) => void;\n\n// ============================================================================\n// RPC Client\n// ============================================================================\n\nexport class RpcClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate stopReadingStdout: (() => void) | null = null;\n\tprivate eventListeners: RpcEventListener[] = [];\n\tprivate observedSessionListeners: RpcObservedSessionListener[] = [];\n\tprivate pendingRequests: Map<string, { resolve: (response: RpcResponse) => void; reject: (error: Error) => void }> =\n\t\tnew Map();\n\tprivate requestId = 0;\n\tprivate stderr = \"\";\n\n\tconstructor(private options: RpcClientOptions = {}) {}\n\n\t/**\n\t * Start the RPC agent process.\n\t */\n\tasync start(): Promise<void> {\n\t\tif (this.process) {\n\t\t\tthrow new Error(\"Client already started\");\n\t\t}\n\n\t\tconst cliPath = this.options.cliPath ?? \"dist/cli.js\";\n\t\tconst args = [\"--mode\", \"rpc\", \"--rpc-protocol-version\", String(DAEMON_PROTOCOL_VERSION)];\n\n\t\tif (this.options.provider) {\n\t\t\targs.push(\"--provider\", this.options.provider);\n\t\t}\n\t\tif (this.options.model) {\n\t\t\targs.push(\"--model\", this.options.model);\n\t\t}\n\t\tif (this.options.args) {\n\t\t\targs.push(...this.options.args);\n\t\t}\n\n\t\tthis.process = spawn(\"node\", [cliPath, ...args], {\n\t\t\tcwd: this.options.cwd,\n\t\t\tenv: { ...process.env, ...this.options.env },\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\t// Collect stderr for debugging\n\t\tthis.process.stderr?.on(\"data\", (data) => {\n\t\t\tthis.stderr += data.toString();\n\t\t\tprocess.stderr.write(data);\n\t\t});\n\n\t\t// Set up strict JSONL reader for stdout.\n\t\tthis.stopReadingStdout = attachJsonlLineReader(this.process.stdout!, (line) => {\n\t\t\tthis.handleLine(line);\n\t\t});\n\n\t\t// Wait a moment for process to initialize\n\t\tawait new Promise((resolve) => setTimeout(resolve, 100));\n\n\t\tif (this.process.exitCode !== null) {\n\t\t\tthrow new Error(`Agent process exited immediately with code ${this.process.exitCode}. Stderr: ${this.stderr}`);\n\t\t}\n\t\ttry {\n\t\t\tconst state = await this.getState();\n\t\t\tif (state.protocolVersion !== DAEMON_PROTOCOL_VERSION)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC protocol: expected ${DAEMON_PROTOCOL_VERSION}, got ${state.protocolVersion ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t\tconst minimumSchema = CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY.minSchemaRevision;\n\t\t\tif (!Number.isSafeInteger(state.schemaRevision) || (state.schemaRevision ?? 0) < minimumSchema)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC schema: expected at least ${minimumSchema}, got ${state.schemaRevision ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait this.stop();\n\t\t\t} catch (cleanupError) {\n\t\t\t\tthrow new AggregateError([error, cleanupError], \"RPC startup and cleanup failed\", { cause: error });\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Stop the RPC agent process.\n\t */\n\tasync stop(): Promise<void> {\n\t\tif (!this.process) return;\n\n\t\tthis.stopReadingStdout?.();\n\t\tthis.stopReadingStdout = null;\n\t\tthis.process.kill(\"SIGTERM\");\n\n\t\t// Wait for process to exit\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\tthis.process?.kill(\"SIGKILL\");\n\t\t\t\tresolve();\n\t\t\t}, 1000);\n\n\t\t\tthis.process?.on(\"exit\", () => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\n\t\tthis.process = null;\n\t\tthis.pendingRequests.clear();\n\t}\n\n\t/**\n\t * Subscribe to agent events.\n\t */\n\tonEvent(listener: RpcEventListener): () => void {\n\t\tthis.eventListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.eventListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.eventListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\tonObservedSessionEvent(listener: RpcObservedSessionListener): () => void {\n\t\tthis.observedSessionListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.observedSessionListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.observedSessionListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Get collected stderr output (useful for debugging).\n\t */\n\tgetStderr(): string {\n\t\treturn this.stderr;\n\t}\n\n\t// =========================================================================\n\t// Command Methods\n\t// =========================================================================\n\n\t/**\n\t * Send a prompt to the agent.\n\t * Resolves after admission succeeds; use onEvent() to receive streaming events.\n\t * Use waitForIdle() to wait for completion.\n\t */\n\tasync prompt(message: string, images?: ImageContent[]): Promise<void> {\n\t\tthis.getData(await this.send({ type: \"prompt\", message, images }));\n\t}\n\n\t/**\n\t * Queue a steering message to interrupt the agent mid-run.\n\t */\n\tasync steer(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"steer\", message, images });\n\t}\n\n\t/**\n\t * Queue a follow-up message to be processed after the agent finishes.\n\t */\n\tasync followUp(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"follow_up\", message, images });\n\t}\n\n\t/**\n\t * Abort current operation.\n\t */\n\tasync abort(): Promise<void> {\n\t\tawait this.send({ type: \"abort\" });\n\t}\n\n\t/**\n\t * Start a new session, optionally with parent tracking.\n\t * @param parentSession - Optional parent session path for lineage tracking\n\t * @returns Object with `cancelled: true` if an extension cancelled the new session\n\t */\n\tasync newSession(parentSession?: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"new_session\", parentSession });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get current session state.\n\t */\n\tasync getState(): Promise<RpcSessionState> {\n\t\tconst response = await this.send({ type: \"get_state\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set model by provider and ID.\n\t */\n\tasync setModel(provider: string, modelId: string): Promise<{ provider: string; id: string }> {\n\t\tconst response = await this.send({ type: \"set_model\", provider, modelId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Cycle to next model.\n\t */\n\tasync cycleModel(): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: ThinkingLevel;\n\t\tisScoped: boolean;\n\t} | null> {\n\t\tconst response = await this.send({ type: \"cycle_model\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get list of available models.\n\t */\n\tasync getAvailableModels(): Promise<ModelInfo[]> {\n\t\tconst response = await this.send({ type: \"get_available_models\" });\n\t\treturn this.getData<{ models: ModelInfo[] }>(response).models;\n\t}\n\n\t/**\n\t * Set thinking level.\n\t */\n\tasync setThinkingLevel(level: ThinkingLevel): Promise<void> {\n\t\tawait this.send({ type: \"set_thinking_level\", level });\n\t}\n\n\t/**\n\t * Cycle thinking level.\n\t */\n\tasync cycleThinkingLevel(): Promise<{ level: ThinkingLevel } | null> {\n\t\tconst response = await this.send({ type: \"cycle_thinking_level\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set steering mode.\n\t */\n\tasync setSteeringMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_steering_mode\", mode });\n\t}\n\n\t/**\n\t * Set follow-up mode.\n\t */\n\tasync setFollowUpMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_follow_up_mode\", mode });\n\t}\n\n\t/**\n\t * Compact session context.\n\t */\n\tasync compact(customInstructions?: string): Promise<CompactionResult> {\n\t\tconst response = await this.send({ type: \"compact\", customInstructions });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Refine editable continual harness state.\n\t */\n\tasync refine(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean } = {},\n\t): Promise<RefinementResult> {\n\t\t// Refinement runs an LLM pass that routinely exceeds the default 30s response\n\t\t// timeout, so use the same extended window as the daemon refine path.\n\t\tconst command = { type: \"refine\", instructions: options.instructions, rollbackId: options.rollbackId } as {\n\t\t\ttype: \"refine\";\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t};\n\t\tif (options.global !== undefined) {\n\t\t\tcommand.global = options.global;\n\t\t}\n\t\tconst response = await this.send(command, REFINE_REQUEST_TIMEOUT_MS);\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set auto-compaction enabled/disabled.\n\t */\n\tasync setAutoCompaction(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_compaction\", enabled });\n\t}\n\n\t/**\n\t * Set auto-retry enabled/disabled.\n\t */\n\tasync setAutoRetry(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_retry\", enabled });\n\t}\n\n\t/**\n\t * Abort in-progress retry.\n\t */\n\tasync abortRetry(): Promise<void> {\n\t\tawait this.send({ type: \"abort_retry\" });\n\t}\n\n\t/**\n\t * Execute a bash command.\n\t */\n\tasync bash(command: string): Promise<BashResult> {\n\t\tconst response = await this.send({ type: \"bash\", command });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Abort running bash command.\n\t */\n\tasync abortBash(): Promise<void> {\n\t\tawait this.send({ type: \"abort_bash\" });\n\t}\n\n\t/**\n\t * Get session statistics.\n\t */\n\tasync getSessionStats(): Promise<SessionStats> {\n\t\tconst response = await this.send({ type: \"get_session_stats\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Export session to HTML.\n\t */\n\tasync exportHtml(outputPath?: string): Promise<{ path: string }> {\n\t\tconst response = await this.send({ type: \"export_html\", outputPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Switch to a different session file.\n\t * @returns Object with `cancelled: true` if an extension cancelled the switch\n\t */\n\tasync switchSession(sessionPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"switch_session\", sessionPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Fork from a specific message.\n\t * @returns Object with `text` (the message text) and `cancelled` (if extension cancelled)\n\t */\n\tasync fork(entryId: string): Promise<{ text: string; cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"fork\", entryId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Clone the current active branch into a new session.\n\t * @returns Object with `cancelled: true` if an extension cancelled the clone\n\t */\n\tasync clone(): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"clone\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get messages available for forking.\n\t */\n\tasync getForkMessages(): Promise<Array<{ entryId: string; text: string }>> {\n\t\tconst response = await this.send({ type: \"get_fork_messages\" });\n\t\treturn this.getData<{ messages: Array<{ entryId: string; text: string }> }>(response).messages;\n\t}\n\n\t/**\n\t * Get text of last assistant message.\n\t */\n\tasync getLastAssistantText(): Promise<string | null> {\n\t\tconst response = await this.send({ type: \"get_last_assistant_text\" });\n\t\treturn this.getData<{ text: string | null }>(response).text;\n\t}\n\n\t/**\n\t * Set the session display name.\n\t */\n\tasync setSessionName(name: string): Promise<void> {\n\t\tawait this.send({ type: \"set_session_name\", name });\n\t}\n\n\t/**\n\t * Get all messages in the session.\n\t */\n\tasync getMessages(): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"get_messages\" });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync sendAgentMessage(targetActiveSessionId: string, message: string): Promise<AgentSessionMessageReceipt> {\n\t\tconst response = await this.send({\n\t\t\ttype: \"send_message\",\n\t\t\ttargetActiveSessionId,\n\t\t\tmessage,\n\t\t});\n\t\treturn this.getData(response);\n\t}\n\n\tasync getAgentMessageStatus(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_status\" }));\n\t}\n\n\tasync pauseAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_pause\" }));\n\t}\n\n\tasync resumeAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_resume\" }));\n\t}\n\n\tasync clearAgentMessages(): Promise<number> {\n\t\tconst response = await this.send({ type: \"agent_messages_clear\" });\n\t\treturn this.getData<{ cleared: number }>(response).cleared;\n\t}\n\n\tasync listSchedules(includeInactive?: boolean): Promise<AgentCronJob[]> {\n\t\tconst response = await this.send({ type: \"list_schedules\", includeInactive });\n\t\treturn this.getData<{ jobs: AgentCronJob[] }>(response).jobs;\n\t}\n\n\tasync addSchedule(schedule: string, prompt: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"add_schedule\", schedule, prompt });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync cancelSchedule(jobId: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"cancel_schedule\", jobId });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync listHeartbeats(): Promise<AgentConnectionHeartbeat[]> {\n\t\tconst response = await this.send({ type: \"list_heartbeats\" });\n\t\treturn this.getData<{ heartbeats: AgentConnectionHeartbeat[] }>(response).heartbeats;\n\t}\n\n\tasync getHeartbeat(): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"get_heartbeat\" });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync setHeartbeat(\n\t\tschedule: string,\n\t\tprompt: string,\n\t\tdeliveryMode?: AgentHeartbeatDeliveryMode,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"set_heartbeat\", schedule, prompt, deliveryMode });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the created heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync updateHeartbeat(action: AgentHeartbeatUpdateAction): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"update_heartbeat\", action });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync manageHeartbeat(\n\t\tactiveSessionId: string,\n\t\tjobId: string,\n\t\taction: AgentHeartbeatManagementAction,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"manage_heartbeat\", activeSessionId, jobId, action });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the managed heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync observe(activeSessionId: string): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"observe\", activeSessionId });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync unobserve(activeSessionId: string): Promise<void> {\n\t\tawait this.send({ type: \"unobserve\", activeSessionId });\n\t}\n\n\t/**\n\t * Get available commands (extension commands, prompt templates, skills).\n\t */\n\tasync getCommands(): Promise<RpcSlashCommand[]> {\n\t\tconst response = await this.send({ type: \"get_commands\" });\n\t\treturn this.getData<{ commands: RpcSlashCommand[] }>(response).commands;\n\t}\n\n\t// =========================================================================\n\t// Helpers\n\t// =========================================================================\n\n\t/**\n\t * Wait for agent to become idle (no streaming).\n\t * Resolves when agent_end event is received.\n\t */\n\twaitForIdle(timeout = 60000): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tunsubscribe();\n\t\t\t\treject(new Error(`Timeout waiting for agent to become idle. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t} else if (event.type === \"agent_end\") {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Collect events until agent becomes idle.\n\t */\n\tcollectEvents(timeout = 60000): Promise<AgentEvent[]> {\n\t\treturn this.createEventCollection(timeout).result;\n\t}\n\n\tprivate createEventCollection(timeout: number): { result: Promise<AgentEvent[]>; cancel: () => void } {\n\t\tlet cancel = () => {};\n\t\tconst result = new Promise<AgentEvent[]>((resolve, reject) => {\n\t\t\tconst events: AgentEvent[] = [];\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tcancel();\n\t\t\t\treject(new Error(`Timeout collecting events. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tevents.push(event);\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tcancel();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.type === \"agent_end\") {\n\t\t\t\t\tcancel();\n\t\t\t\t\tresolve(events);\n\t\t\t\t}\n\t\t\t});\n\t\t\tcancel = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tunsubscribe();\n\t\t\t\tcancel = () => {};\n\t\t\t};\n\t\t});\n\t\treturn { result, cancel: () => cancel() };\n\t}\n\n\t/**\n\t * Send prompt and wait for completion, returning all events.\n\t */\n\tasync promptAndWait(message: string, images?: ImageContent[], timeout = 60000): Promise<AgentEvent[]> {\n\t\tconst collection = this.createEventCollection(timeout);\n\t\tlet events: AgentEvent[];\n\t\ttry {\n\t\t\t[, events] = await Promise.all([this.prompt(message, images), collection.result]);\n\t\t} finally {\n\t\t\tcollection.cancel();\n\t\t}\n\t\tconst terminal = events.find((event) => event.type === \"agent_end\");\n\t\tif (terminal?.type === \"agent_end\" && terminal.refusal) throw new AgentOutputLimitError(terminal.refusal);\n\t\treturn events;\n\t}\n\n\t// =========================================================================\n\t// Internal\n\t// =========================================================================\n\n\tprivate handleLine(line: string): void {\n\t\ttry {\n\t\t\tconst data = JSON.parse(line);\n\n\t\t\t// Check if it's a response to a pending request\n\t\t\tif (data.type === \"response\" && data.id && this.pendingRequests.has(data.id)) {\n\t\t\t\tconst pending = this.pendingRequests.get(data.id)!;\n\t\t\t\tthis.pendingRequests.delete(data.id);\n\t\t\t\tpending.resolve(data as RpcResponse);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (data.type === \"observed_session_event\" || data.type === \"observed_session_closed\") {\n\t\t\t\tfor (const listener of [...this.observedSessionListeners]) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener(data as RpcObservedSessionEvent);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise it's an event\n\t\t\tfor (const listener of [...this.eventListeners]) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(data as AgentEvent);\n\t\t\t\t} catch {\n\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore non-JSON lines\n\t\t}\n\t}\n\n\tprivate async send(command: RpcCommandBody, timeoutMs = 30000): Promise<RpcResponse> {\n\t\tif (!this.process?.stdin) {\n\t\t\tthrow new Error(\"Client not started\");\n\t\t}\n\n\t\tconst id = `req_${++this.requestId}`;\n\t\tconst fullCommand = { ...command, id } as RpcCommand;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.pendingRequests.set(id, { resolve, reject });\n\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\tthis.pendingRequests.delete(id);\n\t\t\t\treject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));\n\t\t\t}, timeoutMs);\n\n\t\t\tthis.pendingRequests.set(id, {\n\t\t\t\tresolve: (response) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tresolve(response);\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthis.process!.stdin!.write(serializeJsonLine(fullCommand));\n\t\t});\n\t}\n\n\tprivate getData<T>(response: RpcResponse): T {\n\t\tif (!response.success) {\n\t\t\tconst errorResponse = response as Extract<RpcResponse, { success: false }>;\n\t\t\tthrow new Error(errorResponse.error);\n\t\t}\n\t\t// Type assertion: we trust response.data matches T based on the command sent.\n\t\t// This is safe because each public method specifies the correct T for its command.\n\t\tconst successResponse = response as Extract<RpcResponse, { success: true; data: unknown }>;\n\t\treturn successResponse.data as T;\n\t}\n}\n"]}
1
+ {"version":3,"file":"rpc-client.js","sourceRoot":"","sources":["../../../src/modes/rpc/rpc-client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC Client for programmatic access to the coding agent.\n *\n * Spawns the agent in RPC mode and provides a typed API for all operations.\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport {\n\ttype AgentEvent,\n\ttype AgentMessage,\n\tAgentOutputLimitError,\n\ttype ThinkingLevel,\n} from \"@ponythewhite/base-context-agent\";\nimport type { ImageContent } from \"@ponythewhite/base-context-ai\";\nimport type { AgentSessionMessageReceipt, AgentSessionMessageSafetyStatus } from \"../../core/agent-messages.js\";\nimport type { BashResult } from \"../../core/bash-executor.js\";\nimport type { CompactionResult } from \"../../core/compaction/index.js\";\nimport type {\n\tAgentCronJob,\n\tAgentHeartbeatDeliveryMode,\n\tAgentHeartbeatManagementAction,\n\tAgentHeartbeatUpdateAction,\n} from \"../../core/cron-jobs.js\";\nimport type { RefinementResult } from \"../../core/refinement/index.js\";\nimport type { SessionStats } from \"../../core/session-stats.js\";\nimport type { AgentConnectionHeartbeat } from \"../agent-connection/types.js\";\nimport { CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY, DAEMON_PROTOCOL_VERSION } from \"../daemon/daemon-protocol.js\";\nimport { attachJsonlLineReader, serializeJsonLine } from \"./jsonl.js\";\nimport type {\n\tRpcCommand,\n\tRpcObservedSessionEvent,\n\tRpcPromptCompletionError,\n\tRpcResponse,\n\tRpcSessionState,\n\tRpcSlashCommand,\n} from \"./rpc-types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\nfunction promptCompletionError(event: AgentEvent): string | undefined {\n\tconst output = event as AgentEvent | RpcPromptCompletionError;\n\tif (\n\t\toutput.type === \"extension_error\" &&\n\t\toutput.extensionPath === \"<session-input>\" &&\n\t\toutput.event === \"prompt_completion\"\n\t)\n\t\treturn output.error;\n\treturn undefined;\n}\n\n/** Extended response timeout for refine requests, which run an LLM pass. */\nexport const REFINE_REQUEST_TIMEOUT_MS = 10 * 60 * 1000;\n\n/** Distributive Omit that works with union types */\ntype DistributiveOmit<T, K extends keyof T> = T extends unknown ? Omit<T, K> : never;\n\n/** RpcCommand without the id field (for internal send) */\ntype RpcCommandBody = DistributiveOmit<RpcCommand, \"id\">;\n\nexport interface RpcClientOptions {\n\t/** Path to the CLI entry point (default: searches for dist/cli.js) */\n\tcliPath?: string;\n\t/** Working directory for the agent */\n\tcwd?: string;\n\t/** Environment variables */\n\tenv?: Record<string, string>;\n\t/** Provider to use */\n\tprovider?: string;\n\t/** Model ID to use */\n\tmodel?: string;\n\t/** Additional CLI arguments */\n\targs?: string[];\n}\n\nexport interface ModelInfo {\n\tprovider: string;\n\tid: string;\n\tcontextWindow: number;\n\treasoning: boolean;\n}\n\nexport type RpcEventListener = (event: AgentEvent) => void;\nexport type RpcObservedSessionListener = (event: RpcObservedSessionEvent) => void;\n\n// ============================================================================\n// RPC Client\n// ============================================================================\n\nexport class RpcClient {\n\tprivate process: ChildProcess | null = null;\n\tprivate stopReadingStdout: (() => void) | null = null;\n\tprivate eventListeners: RpcEventListener[] = [];\n\tprivate observedSessionListeners: RpcObservedSessionListener[] = [];\n\tprivate pendingRequests: Map<string, { resolve: (response: RpcResponse) => void; reject: (error: Error) => void }> =\n\t\tnew Map();\n\tprivate requestId = 0;\n\tprivate stderr = \"\";\n\n\tconstructor(private options: RpcClientOptions = {}) {}\n\n\t/**\n\t * Start the RPC agent process.\n\t */\n\tasync start(): Promise<void> {\n\t\tif (this.process) {\n\t\t\tthrow new Error(\"Client already started\");\n\t\t}\n\n\t\tconst cliPath = this.options.cliPath ?? \"dist/cli.js\";\n\t\tconst args = [\"--mode\", \"rpc\", \"--rpc-protocol-version\", String(DAEMON_PROTOCOL_VERSION)];\n\n\t\tif (this.options.provider) {\n\t\t\targs.push(\"--provider\", this.options.provider);\n\t\t}\n\t\tif (this.options.model) {\n\t\t\targs.push(\"--model\", this.options.model);\n\t\t}\n\t\tif (this.options.args) {\n\t\t\targs.push(...this.options.args);\n\t\t}\n\n\t\tconst child = spawn(\"node\", [cliPath, ...args], {\n\t\t\tcwd: this.options.cwd,\n\t\t\tenv: { ...process.env, ...this.options.env },\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t});\n\t\tthis.process = child;\n\t\tthis.stderr = \"\";\n\n\t\t// Collect stderr for debugging\n\t\tchild.stderr?.on(\"data\", (data) => {\n\t\t\tif (this.process !== child) return;\n\t\t\tthis.stderr += data.toString();\n\t\t\tprocess.stderr.write(data);\n\t\t});\n\t\tchild.once(\"error\", (error) => {\n\t\t\tif (this.process === child) this.rejectPendingRequests(error);\n\t\t});\n\t\t// Drain final stdout/stderr before rejecting requests that received no response.\n\t\tchild.once(\"close\", () => {\n\t\t\tif (this.process === child) this.rejectPendingRequests(this.processExitError(child));\n\t\t});\n\n\t\t// Set up strict JSONL reader for stdout.\n\t\tthis.stopReadingStdout = attachJsonlLineReader(child.stdout!, (line) => {\n\t\t\tif (this.process === child) this.handleLine(line);\n\t\t});\n\n\t\ttry {\n\t\t\tconst state = await this.getState();\n\t\t\tif (state.protocolVersion !== DAEMON_PROTOCOL_VERSION)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC protocol: expected ${DAEMON_PROTOCOL_VERSION}, got ${state.protocolVersion ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t\tconst minimumSchema = CANONICAL_SESSION_OWNERSHIP_COMPATIBILITY.minSchemaRevision;\n\t\t\tif (!Number.isSafeInteger(state.schemaRevision) || (state.schemaRevision ?? 0) < minimumSchema)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Incompatible RPC schema: expected at least ${minimumSchema}, got ${state.schemaRevision ?? \"unversioned\"}`,\n\t\t\t\t);\n\t\t} catch (error) {\n\t\t\tif (this.process === child) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.stop();\n\t\t\t\t} catch (cleanupError) {\n\t\t\t\t\tthrow new AggregateError([error, cleanupError], \"RPC startup and cleanup failed\", { cause: error });\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Stop the RPC agent process.\n\t */\n\tasync stop(): Promise<void> {\n\t\tconst child = this.process;\n\t\tif (!child) return;\n\n\t\tthis.stopReadingStdout?.();\n\t\tthis.stopReadingStdout = null;\n\n\t\tif (child.exitCode === null && child.signalCode === null) {\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t\tresolve();\n\t\t\t\t}, 1000);\n\n\t\t\t\tchild.once(\"exit\", () => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t});\n\t\t}\n\n\t\tif (this.process === child) {\n\t\t\tthis.process = null;\n\t\t\tthis.rejectPendingRequests(new Error(\"RPC client stopped\"));\n\t\t}\n\t}\n\n\t/**\n\t * Subscribe to agent events.\n\t */\n\tonEvent(listener: RpcEventListener): () => void {\n\t\tthis.eventListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.eventListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.eventListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\tonObservedSessionEvent(listener: RpcObservedSessionListener): () => void {\n\t\tthis.observedSessionListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst index = this.observedSessionListeners.indexOf(listener);\n\t\t\tif (index !== -1) {\n\t\t\t\tthis.observedSessionListeners.splice(index, 1);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Get collected stderr output (useful for debugging).\n\t */\n\tgetStderr(): string {\n\t\treturn this.stderr;\n\t}\n\n\t// =========================================================================\n\t// Command Methods\n\t// =========================================================================\n\n\t/**\n\t * Send a prompt to the agent.\n\t * Resolves after admission succeeds; use onEvent() to receive streaming events.\n\t * Use waitForIdle() to wait for completion.\n\t */\n\tasync prompt(message: string, images?: ImageContent[]): Promise<void> {\n\t\tthis.getData(await this.send({ type: \"prompt\", message, images }));\n\t}\n\n\t/**\n\t * Queue a steering message to interrupt the agent mid-run.\n\t */\n\tasync steer(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"steer\", message, images });\n\t}\n\n\t/**\n\t * Queue a follow-up message to be processed after the agent finishes.\n\t */\n\tasync followUp(message: string, images?: ImageContent[]): Promise<void> {\n\t\tawait this.send({ type: \"follow_up\", message, images });\n\t}\n\n\t/**\n\t * Abort current operation.\n\t */\n\tasync abort(): Promise<void> {\n\t\tawait this.send({ type: \"abort\" });\n\t}\n\n\t/**\n\t * Start a new session, optionally with parent tracking.\n\t * @param parentSession - Optional parent session path for lineage tracking\n\t * @returns Object with `cancelled: true` if an extension cancelled the new session\n\t */\n\tasync newSession(parentSession?: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"new_session\", parentSession });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get current session state.\n\t */\n\tasync getState(): Promise<RpcSessionState> {\n\t\tconst response = await this.send({ type: \"get_state\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set model by provider and ID.\n\t */\n\tasync setModel(provider: string, modelId: string): Promise<{ provider: string; id: string }> {\n\t\tconst response = await this.send({ type: \"set_model\", provider, modelId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Cycle to next model.\n\t */\n\tasync cycleModel(): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: ThinkingLevel;\n\t\tisScoped: boolean;\n\t} | null> {\n\t\tconst response = await this.send({ type: \"cycle_model\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get list of available models.\n\t */\n\tasync getAvailableModels(): Promise<ModelInfo[]> {\n\t\tconst response = await this.send({ type: \"get_available_models\" });\n\t\treturn this.getData<{ models: ModelInfo[] }>(response).models;\n\t}\n\n\t/**\n\t * Set thinking level.\n\t */\n\tasync setThinkingLevel(level: ThinkingLevel): Promise<void> {\n\t\tawait this.send({ type: \"set_thinking_level\", level });\n\t}\n\n\t/**\n\t * Cycle thinking level.\n\t */\n\tasync cycleThinkingLevel(): Promise<{ level: ThinkingLevel } | null> {\n\t\tconst response = await this.send({ type: \"cycle_thinking_level\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set steering mode.\n\t */\n\tasync setSteeringMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_steering_mode\", mode });\n\t}\n\n\t/**\n\t * Set follow-up mode.\n\t */\n\tasync setFollowUpMode(mode: \"all\" | \"one-at-a-time\"): Promise<void> {\n\t\tawait this.send({ type: \"set_follow_up_mode\", mode });\n\t}\n\n\t/**\n\t * Compact session context.\n\t */\n\tasync compact(customInstructions?: string): Promise<CompactionResult> {\n\t\tconst response = await this.send({ type: \"compact\", customInstructions });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Refine editable continual harness state.\n\t */\n\tasync refine(\n\t\toptions: { instructions?: string; rollbackId?: string; global?: boolean } = {},\n\t): Promise<RefinementResult> {\n\t\t// Refinement runs an LLM pass that routinely exceeds the default 30s response\n\t\t// timeout, so use the same extended window as the daemon refine path.\n\t\tconst command = { type: \"refine\", instructions: options.instructions, rollbackId: options.rollbackId } as {\n\t\t\ttype: \"refine\";\n\t\t\tinstructions?: string;\n\t\t\trollbackId?: string;\n\t\t\tglobal?: boolean;\n\t\t};\n\t\tif (options.global !== undefined) {\n\t\t\tcommand.global = options.global;\n\t\t}\n\t\tconst response = await this.send(command, REFINE_REQUEST_TIMEOUT_MS);\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Set auto-compaction enabled/disabled.\n\t */\n\tasync setAutoCompaction(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_compaction\", enabled });\n\t}\n\n\t/**\n\t * Set auto-retry enabled/disabled.\n\t */\n\tasync setAutoRetry(enabled: boolean): Promise<void> {\n\t\tawait this.send({ type: \"set_auto_retry\", enabled });\n\t}\n\n\t/**\n\t * Abort in-progress retry.\n\t */\n\tasync abortRetry(): Promise<void> {\n\t\tawait this.send({ type: \"abort_retry\" });\n\t}\n\n\t/**\n\t * Execute a bash command.\n\t */\n\tasync bash(command: string): Promise<BashResult> {\n\t\tconst response = await this.send({ type: \"bash\", command });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Abort running bash command.\n\t */\n\tasync abortBash(): Promise<void> {\n\t\tawait this.send({ type: \"abort_bash\" });\n\t}\n\n\t/**\n\t * Get session statistics.\n\t */\n\tasync getSessionStats(): Promise<SessionStats> {\n\t\tconst response = await this.send({ type: \"get_session_stats\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Export session to HTML.\n\t */\n\tasync exportHtml(outputPath?: string): Promise<{ path: string }> {\n\t\tconst response = await this.send({ type: \"export_html\", outputPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Switch to a different session file.\n\t * @returns Object with `cancelled: true` if an extension cancelled the switch\n\t */\n\tasync switchSession(sessionPath: string): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"switch_session\", sessionPath });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Fork from a specific message.\n\t * @returns Object with `text` (the message text) and `cancelled` (if extension cancelled)\n\t */\n\tasync fork(entryId: string): Promise<{ text: string; cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"fork\", entryId });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Clone the current active branch into a new session.\n\t * @returns Object with `cancelled: true` if an extension cancelled the clone\n\t */\n\tasync clone(): Promise<{ cancelled: boolean }> {\n\t\tconst response = await this.send({ type: \"clone\" });\n\t\treturn this.getData(response);\n\t}\n\n\t/**\n\t * Get messages available for forking.\n\t */\n\tasync getForkMessages(): Promise<Array<{ entryId: string; text: string }>> {\n\t\tconst response = await this.send({ type: \"get_fork_messages\" });\n\t\treturn this.getData<{ messages: Array<{ entryId: string; text: string }> }>(response).messages;\n\t}\n\n\t/**\n\t * Get text of last assistant message.\n\t */\n\tasync getLastAssistantText(): Promise<string | null> {\n\t\tconst response = await this.send({ type: \"get_last_assistant_text\" });\n\t\treturn this.getData<{ text: string | null }>(response).text;\n\t}\n\n\t/**\n\t * Set the session display name.\n\t */\n\tasync setSessionName(name: string): Promise<void> {\n\t\tawait this.send({ type: \"set_session_name\", name });\n\t}\n\n\t/**\n\t * Get all messages in the session.\n\t */\n\tasync getMessages(): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"get_messages\" });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync sendAgentMessage(targetActiveSessionId: string, message: string): Promise<AgentSessionMessageReceipt> {\n\t\tconst response = await this.send({\n\t\t\ttype: \"send_message\",\n\t\t\ttargetActiveSessionId,\n\t\t\tmessage,\n\t\t});\n\t\treturn this.getData(response);\n\t}\n\n\tasync getAgentMessageStatus(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_status\" }));\n\t}\n\n\tasync pauseAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_pause\" }));\n\t}\n\n\tasync resumeAgentMessages(): Promise<AgentSessionMessageSafetyStatus> {\n\t\treturn this.getData(await this.send({ type: \"agent_messages_resume\" }));\n\t}\n\n\tasync clearAgentMessages(): Promise<number> {\n\t\tconst response = await this.send({ type: \"agent_messages_clear\" });\n\t\treturn this.getData<{ cleared: number }>(response).cleared;\n\t}\n\n\tasync listSchedules(includeInactive?: boolean): Promise<AgentCronJob[]> {\n\t\tconst response = await this.send({ type: \"list_schedules\", includeInactive });\n\t\treturn this.getData<{ jobs: AgentCronJob[] }>(response).jobs;\n\t}\n\n\tasync addSchedule(schedule: string, prompt: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"add_schedule\", schedule, prompt });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync cancelSchedule(jobId: string): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"cancel_schedule\", jobId });\n\t\treturn this.getData<{ job: AgentCronJob }>(response).job;\n\t}\n\n\tasync listHeartbeats(): Promise<AgentConnectionHeartbeat[]> {\n\t\tconst response = await this.send({ type: \"list_heartbeats\" });\n\t\treturn this.getData<{ heartbeats: AgentConnectionHeartbeat[] }>(response).heartbeats;\n\t}\n\n\tasync getHeartbeat(): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"get_heartbeat\" });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync setHeartbeat(\n\t\tschedule: string,\n\t\tprompt: string,\n\t\tdeliveryMode?: AgentHeartbeatDeliveryMode,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"set_heartbeat\", schedule, prompt, deliveryMode });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the created heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync updateHeartbeat(action: AgentHeartbeatUpdateAction): Promise<AgentCronJob | null> {\n\t\tconst response = await this.send({ type: \"update_heartbeat\", action });\n\t\treturn this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t}\n\n\tasync manageHeartbeat(\n\t\tactiveSessionId: string,\n\t\tjobId: string,\n\t\taction: AgentHeartbeatManagementAction,\n\t): Promise<AgentCronJob> {\n\t\tconst response = await this.send({ type: \"manage_heartbeat\", activeSessionId, jobId, action });\n\t\tconst heartbeat = this.getData<{ heartbeat: AgentCronJob | null }>(response).heartbeat;\n\t\tif (!heartbeat) {\n\t\t\tthrow new Error(\"Daemon did not return the managed heartbeat\");\n\t\t}\n\t\treturn heartbeat;\n\t}\n\n\tasync observe(activeSessionId: string): Promise<AgentMessage[]> {\n\t\tconst response = await this.send({ type: \"observe\", activeSessionId });\n\t\treturn this.getData<{ messages: AgentMessage[] }>(response).messages;\n\t}\n\n\tasync unobserve(activeSessionId: string): Promise<void> {\n\t\tawait this.send({ type: \"unobserve\", activeSessionId });\n\t}\n\n\t/**\n\t * Get available commands (extension commands, prompt templates, skills).\n\t */\n\tasync getCommands(): Promise<RpcSlashCommand[]> {\n\t\tconst response = await this.send({ type: \"get_commands\" });\n\t\treturn this.getData<{ commands: RpcSlashCommand[] }>(response).commands;\n\t}\n\n\t// =========================================================================\n\t// Helpers\n\t// =========================================================================\n\n\t/**\n\t * Wait for agent to become idle (no streaming).\n\t * Resolves when agent_end event is received.\n\t */\n\twaitForIdle(timeout = 60000): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tunsubscribe();\n\t\t\t\treject(new Error(`Timeout waiting for agent to become idle. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t} else if (event.type === \"agent_end\") {\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tunsubscribe();\n\t\t\t\t\tresolve();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t/**\n\t * Collect events until agent becomes idle.\n\t */\n\tcollectEvents(timeout = 60000): Promise<AgentEvent[]> {\n\t\treturn this.createEventCollection(timeout).result;\n\t}\n\n\tprivate createEventCollection(timeout: number): { result: Promise<AgentEvent[]>; cancel: () => void } {\n\t\tlet cancel = () => {};\n\t\tconst result = new Promise<AgentEvent[]>((resolve, reject) => {\n\t\t\tconst events: AgentEvent[] = [];\n\t\t\tconst timer = setTimeout(() => {\n\t\t\t\tcancel();\n\t\t\t\treject(new Error(`Timeout collecting events. Stderr: ${this.stderr}`));\n\t\t\t}, timeout);\n\n\t\t\tconst unsubscribe = this.onEvent((event) => {\n\t\t\t\tevents.push(event);\n\t\t\t\tconst error = promptCompletionError(event);\n\t\t\t\tif (error !== undefined) {\n\t\t\t\t\tcancel();\n\t\t\t\t\treject(new Error(error));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (event.type === \"agent_end\") {\n\t\t\t\t\tcancel();\n\t\t\t\t\tresolve(events);\n\t\t\t\t}\n\t\t\t});\n\t\t\tcancel = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tunsubscribe();\n\t\t\t\tcancel = () => {};\n\t\t\t};\n\t\t});\n\t\treturn { result, cancel: () => cancel() };\n\t}\n\n\t/**\n\t * Send prompt and wait for completion, returning all events.\n\t */\n\tasync promptAndWait(message: string, images?: ImageContent[], timeout = 60000): Promise<AgentEvent[]> {\n\t\tconst collection = this.createEventCollection(timeout);\n\t\tlet events: AgentEvent[];\n\t\ttry {\n\t\t\t[, events] = await Promise.all([this.prompt(message, images), collection.result]);\n\t\t} finally {\n\t\t\tcollection.cancel();\n\t\t}\n\t\tconst terminal = events.find((event) => event.type === \"agent_end\");\n\t\tif (terminal?.type === \"agent_end\" && terminal.refusal) throw new AgentOutputLimitError(terminal.refusal);\n\t\treturn events;\n\t}\n\n\t// =========================================================================\n\t// Internal\n\t// =========================================================================\n\n\tprivate processExitError(child: ChildProcess): Error {\n\t\tconst reason = child.signalCode ? `signal ${child.signalCode}` : `code ${child.exitCode}`;\n\t\treturn new Error(`Agent process exited with ${reason}. Stderr: ${this.stderr}`);\n\t}\n\n\tprivate rejectPendingRequests(error: Error): void {\n\t\tfor (const pending of this.pendingRequests.values()) pending.reject(error);\n\t\tthis.pendingRequests.clear();\n\t}\n\n\tprivate handleLine(line: string): void {\n\t\ttry {\n\t\t\tconst data = JSON.parse(line);\n\n\t\t\t// Check if it's a response to a pending request\n\t\t\tif (data.type === \"response\" && data.id && this.pendingRequests.has(data.id)) {\n\t\t\t\tconst pending = this.pendingRequests.get(data.id)!;\n\t\t\t\tthis.pendingRequests.delete(data.id);\n\t\t\t\tpending.resolve(data as RpcResponse);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (data.type === \"observed_session_event\" || data.type === \"observed_session_closed\") {\n\t\t\t\tfor (const listener of [...this.observedSessionListeners]) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tlistener(data as RpcObservedSessionEvent);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Otherwise it's an event\n\t\t\tfor (const listener of [...this.eventListeners]) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(data as AgentEvent);\n\t\t\t\t} catch {\n\t\t\t\t\t// Listener failures must not block other RPC subscribers.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore non-JSON lines\n\t\t}\n\t}\n\n\tprivate async send(command: RpcCommandBody, timeoutMs = 30000): Promise<RpcResponse> {\n\t\tconst child = this.process;\n\t\tif (!child?.stdin) {\n\t\t\tthrow new Error(\"Client not started\");\n\t\t}\n\t\tif (child.exitCode !== null || child.signalCode !== null) {\n\t\t\tthrow this.processExitError(child);\n\t\t}\n\n\t\tconst id = `req_${++this.requestId}`;\n\t\tconst fullCommand = { ...command, id } as RpcCommand;\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\tthis.pendingRequests.delete(id);\n\t\t\t\treject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));\n\t\t\t}, timeoutMs);\n\n\t\t\tthis.pendingRequests.set(id, {\n\t\t\t\tresolve: (response) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tresolve(response);\n\t\t\t\t},\n\t\t\t\treject: (error) => {\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\treject(error);\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tchild.stdin!.write(serializeJsonLine(fullCommand));\n\t\t});\n\t}\n\n\tprivate getData<T>(response: RpcResponse): T {\n\t\tif (!response.success) {\n\t\t\tconst errorResponse = response as Extract<RpcResponse, { success: false }>;\n\t\t\tthrow new Error(errorResponse.error);\n\t\t}\n\t\t// Type assertion: we trust response.data matches T based on the command sent.\n\t\t// This is safe because each public method specifies the correct T for its command.\n\t\tconst successResponse = response as Extract<RpcResponse, { success: true; data: unknown }>;\n\t\treturn successResponse.data as T;\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponythewhite/base-context",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Synerise base-context: a coding and research agent with durable context and a persistent Python REPL",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,9 +42,9 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@agentclientprotocol/sdk": "^1.3.0",
45
- "@ponythewhite/base-context-agent": "1.0.1",
46
- "@ponythewhite/base-context-ai": "1.0.1",
47
- "@ponythewhite/base-context-tui": "1.0.1",
45
+ "@ponythewhite/base-context-agent": "1.0.2",
46
+ "@ponythewhite/base-context-ai": "1.0.2",
47
+ "@ponythewhite/base-context-tui": "1.0.2",
48
48
  "@silvia-odwyer/photon-node": "^0.3.4",
49
49
  "chalk": "^5.5.0",
50
50
  "cli-highlight": "^2.1.11",