patchrelay 0.8.7 → 0.8.9

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "service": "patchrelay",
3
- "version": "0.8.7",
4
- "commit": "d054181e45d3",
5
- "builtAt": "2026-03-19T11:51:02.960Z"
3
+ "version": "0.8.9",
4
+ "commit": "a82762db78db",
5
+ "builtAt": "2026-03-19T12:29:25.534Z"
6
6
  }
@@ -22,6 +22,7 @@ export class CodexAppServerClient extends EventEmitter {
22
22
  config;
23
23
  logger;
24
24
  spawnProcess;
25
+ static DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
25
26
  child;
26
27
  nextRequestId = 1;
27
28
  pending = new Map();
@@ -210,8 +211,25 @@ export class CodexAppServerClient extends EventEmitter {
210
211
  throw new Error("Codex app-server is not running");
211
212
  }
212
213
  const id = this.nextRequestId++;
214
+ const requestTimeoutMs = this.config.requestTimeoutMs ?? CodexAppServerClient.DEFAULT_REQUEST_TIMEOUT_MS;
213
215
  const promise = new Promise((resolve, reject) => {
214
- this.pending.set(id, { resolve, reject });
216
+ const timeout = setTimeout(() => {
217
+ if (!this.pending.delete(id)) {
218
+ return;
219
+ }
220
+ reject(new Error(`Codex app-server request timed out after ${requestTimeoutMs}ms`));
221
+ }, requestTimeoutMs);
222
+ timeout.unref?.();
223
+ this.pending.set(id, {
224
+ resolve: (value) => {
225
+ clearTimeout(timeout);
226
+ resolve(value);
227
+ },
228
+ reject: (error) => {
229
+ clearTimeout(timeout);
230
+ reject(error);
231
+ },
232
+ });
215
233
  });
216
234
  this.writeMessage({
217
235
  jsonrpc: "2.0",
package/dist/config.js CHANGED
@@ -114,6 +114,7 @@ const configSchema = z.object({
114
114
  args: z.array(z.string()).default(["app-server"]),
115
115
  shell_bin: z.string().optional(),
116
116
  source_bashrc: z.boolean().default(true),
117
+ request_timeout_ms: z.number().int().positive().default(30000),
117
118
  model: z.string().optional(),
118
119
  model_provider: z.string().optional(),
119
120
  service_name: z.string().default("patchrelay"),
@@ -461,6 +462,7 @@ export function loadConfig(configPath = process.env.PATCHRELAY_CONFIG ?? getDefa
461
462
  args: parsed.runner.codex.args,
462
463
  ...(parsed.runner.codex.shell_bin ? { shellBin: parsed.runner.codex.shell_bin } : {}),
463
464
  sourceBashrc: parsed.runner.codex.source_bashrc,
465
+ requestTimeoutMs: parsed.runner.codex.request_timeout_ms,
464
466
  ...(parsed.runner.codex.model ? { model: parsed.runner.codex.model } : {}),
465
467
  ...(parsed.runner.codex.model_provider ? { modelProvider: parsed.runner.codex.model_provider } : {}),
466
468
  ...(parsed.runner.codex.service_name ? { serviceName: parsed.runner.codex.service_name } : {}),
@@ -1,6 +1,7 @@
1
1
  import { SerialWorkQueue } from "./service-queue.js";
2
2
  const ISSUE_KEY_DELIMITER = "::";
3
3
  const DEFAULT_RECONCILE_INTERVAL_MS = 5_000;
4
+ const DEFAULT_RECONCILE_TIMEOUT_MS = 60_000;
4
5
  function toReconciler(value) {
5
6
  if (typeof value === "function") {
6
7
  return {
@@ -124,7 +125,7 @@ export class ServiceRuntime {
124
125
  }
125
126
  this.reconcileInProgress = true;
126
127
  try {
127
- await this.stageRunReconciler.reconcileActiveStageRuns();
128
+ await promiseWithTimeout(this.stageRunReconciler.reconcileActiveStageRuns(), this.options.reconcileTimeoutMs ?? DEFAULT_RECONCILE_TIMEOUT_MS, "Background active-stage reconciliation");
128
129
  }
129
130
  catch (error) {
130
131
  this.logger.warn({
@@ -139,3 +140,18 @@ export class ServiceRuntime {
139
140
  }
140
141
  }
141
142
  }
143
+ function promiseWithTimeout(promise, timeoutMs, label) {
144
+ return new Promise((resolve, reject) => {
145
+ const timeout = setTimeout(() => {
146
+ reject(new Error(`${label} timed out after ${timeoutMs}ms`));
147
+ }, timeoutMs);
148
+ timeout.unref?.();
149
+ promise.then((value) => {
150
+ clearTimeout(timeout);
151
+ resolve(value);
152
+ }, (error) => {
153
+ clearTimeout(timeout);
154
+ reject(error);
155
+ });
156
+ });
157
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchrelay",
3
- "version": "0.8.7",
3
+ "version": "0.8.9",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {