@parall/daemon 1.28.1 → 1.29.1

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.
@@ -112,6 +112,9 @@ function buildEventBody(event) {
112
112
  }
113
113
  return lines.join("\n") + buildSendMessageHint(event);
114
114
  }
115
+ function buildEventBodyForForkResult(event) {
116
+ return buildEventBody(event).replace(/\n<system-reminder>[\s\S]*<\/system-reminder>$/, "");
117
+ }
115
118
  function buildSendMessageHint(event) {
116
119
  if (event.noReply)
117
120
  return "";
@@ -143,14 +146,16 @@ function buildForkResultPrefix(results) {
143
146
  if (!results.length)
144
147
  return "";
145
148
  const blocks = results.map((result) => {
146
- const lines = [`[Fork result]`];
147
- lines.push(`[Handled: ${result.sourceEvent.type} \u2014 ${result.sourceEvent.summary}]`);
149
+ const lines = [];
150
+ for (const body of result.eventBodies) {
151
+ lines.push(body);
152
+ }
153
+ lines.push(`[This event was handled by a parallel fork session. Do NOT re-handle, re-reply, or duplicate work for it.]`);
154
+ lines.push(`[Fork summary: ${result.agentSummary ? sanitizeMeta(result.agentSummary) : "No fork summary available \u2014 the fork completed without producing a text summary. Check the target chat/task for any actions the fork already took before acting."}]`);
148
155
  if (result.actions.length)
149
- lines.push(`[Actions: ${result.actions.join("; ")}]`);
150
- if (result.agentSummary)
151
- lines.push(`[Summary: ${sanitizeMeta(result.agentSummary)}]`);
156
+ lines.push(`[Fork actions: ${result.actions.join("; ")}]`);
152
157
  if (result.historyPath)
153
- lines.push(`[History: ${result.historyPath}]`);
158
+ lines.push(`[Fork history: ${result.historyPath}]`);
154
159
  return lines.join("\n");
155
160
  });
156
161
  return blocks.join("\n\n") + "\n\n---\n\n";
@@ -418,11 +423,19 @@ Messages may arrive with a \`[Thread: prll://msg_xxx]\` line in the event block,
418
423
  - Keep thread replies focused on the original topic
419
424
  `;
420
425
 
426
+ // ts/agent-core/dist/logger.js
427
+ function createLogger(prefix) {
428
+ return {
429
+ info: (msg) => console.log(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
430
+ warn: (msg) => console.warn(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
431
+ error: (msg) => console.error(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`)
432
+ };
433
+ }
434
+
421
435
  // ts/agent-core/dist/gateway-base.js
422
436
  import * as os from "node:os";
423
437
  import * as fs from "node:fs";
424
438
  import * as path from "node:path";
425
- import { randomUUID } from "node:crypto";
426
439
 
427
440
  // ts/sdk/dist/types.js
428
441
  var MENTION_ALL_USER_ID = "all";
@@ -440,6 +453,8 @@ var ENDPOINTS = {
440
453
  AUTH_CHECK_EMAIL: `${API_BASE}/auth/check-email`,
441
454
  AUTH_VERIFY_EMAIL: `${API_BASE}/auth/verify-email`,
442
455
  AUTH_RESEND_CODE: `${API_BASE}/auth/resend-code`,
456
+ AUTH_FORGOT_PASSWORD: `${API_BASE}/auth/forgot-password`,
457
+ AUTH_RESET_PASSWORD: `${API_BASE}/auth/reset-password`,
443
458
  // Users
444
459
  USERS_ME: `${API_BASE}/users/me`,
445
460
  USER_AVATAR: `${API_BASE}/users/me/avatar`,
@@ -473,8 +488,10 @@ var ENDPOINTS = {
473
488
  CHAT_MESSAGES: (orgId, chatId) => `${API_BASE}/orgs/${orgId}/chats/${chatId}/messages`,
474
489
  // Messages (global, by message ID)
475
490
  MESSAGE: (id) => `${API_BASE}/messages/${id}`,
476
- MESSAGE_PATCHES: (id) => `${API_BASE}/messages/${id}/patches`,
477
491
  MESSAGE_REPLIES: (id) => `${API_BASE}/messages/${id}/replies`,
492
+ MESSAGE_WATCH: (id) => `${API_BASE}/messages/${id}/watch`,
493
+ MESSAGE_WATCHERS: (id) => `${API_BASE}/messages/${id}/watchers`,
494
+ MESSAGE_WATCHING: (id) => `${API_BASE}/messages/${id}/watching`,
478
495
  // Upload (org-scoped)
479
496
  UPLOAD_PRESIGN: (orgId) => `${API_BASE}/orgs/${orgId}/upload/presign`,
480
497
  UPLOAD_COMPLETE: (orgId) => `${API_BASE}/orgs/${orgId}/upload/complete`,
@@ -500,6 +517,7 @@ var ENDPOINTS = {
500
517
  AGENT_SESSION: (orgId, agentId, sessionId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}`,
501
518
  AGENT_SESSION_STEPS: (orgId, agentId, sessionId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}/steps`,
502
519
  AGENT_SESSION_STEP: (orgId, agentId, sessionId, stepId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}/steps/${stepId}`,
520
+ AGENT_STEP_BY_ID: (orgId, stepId) => `${API_BASE}/orgs/${orgId}/agent-steps/${stepId}`,
503
521
  AGENT_TASKS: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/tasks`,
504
522
  AGENT_RUNTIME_AUTH: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/runtime-auth`,
505
523
  AGENT_RUNTIME_AUTH_SESSIONS: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/runtime-auth-sessions`,
@@ -524,9 +542,15 @@ var ENDPOINTS = {
524
542
  // Attach/Detach bind an agent to/from a daemon Machine.
525
543
  MACHINE_ATTACH_AGENT: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}`,
526
544
  MACHINE_DETACH_AGENT: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}`,
545
+ MACHINE_WORKSPACE_STATES: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/workspace-states`,
546
+ MACHINE_AGENT_DAEMON_CONFIG: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/daemon-config`,
547
+ MACHINE_AGENT_WORKSPACE_SETUP: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/workspace/setup`,
548
+ MACHINE_LLM_SOURCE: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/llm-source`,
527
549
  MACHINE_RUNTIME_AUTH: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth`,
528
550
  MACHINE_KEYS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys`,
529
551
  MACHINE_KEY: (orgId, machineId, keyId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys/${keyId}`,
552
+ MACHINE_RUNTIME_AUTH_SESSIONS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth-sessions`,
553
+ MACHINE_RUNTIME_AUTH_SESSION_COMPLETE: (orgId, machineId, sessionId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth-sessions/${sessionId}/complete`,
530
554
  // Machine self-control-plane (mck_-scoped). The bearer token implicitly
531
555
  // identifies the Machine, so there is no `:mid` URL parameter — these are
532
556
  // "self" routes called by the daemon for its own host.
@@ -534,6 +558,7 @@ var ENDPOINTS = {
534
558
  MACHINES_ME_AGENTS: `${API_BASE}/machines/me/agents`,
535
559
  MACHINES_ME_HEALTH: `${API_BASE}/machines/me/health`,
536
560
  MACHINES_ME_AGENT_LAUNCH_CREDENTIAL: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/launch-credential`,
561
+ MACHINES_ME_AGENT_WORKSPACE_STATE: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/workspace-state`,
537
562
  MACHINES_ME_WS_TICKET: `${API_BASE}/machines/me/ws/ticket`,
538
563
  // Tasks (org-scoped)
539
564
  TASKS: (orgId) => `${API_BASE}/orgs/${orgId}/tasks`,
@@ -713,7 +738,8 @@ var WS_EVENTS = {
713
738
  MACHINE_HELLO: "machine.hello",
714
739
  MACHINE_AGENT_ATTACHED: "machine.agent.attached",
715
740
  MACHINE_AGENT_DETACHED: "machine.agent.detached",
716
- MACHINE_STOP: "machine.stop"
741
+ MACHINE_STOP: "machine.stop",
742
+ MACHINE_WORKSPACE_SETUP_REQUESTED: "machine.workspace.setup.requested"
717
743
  };
718
744
 
719
745
  // ts/sdk/dist/client.js
@@ -733,7 +759,9 @@ var ParallClient = class _ParallClient {
733
759
  "/auth/logout",
734
760
  "/auth/verify-email",
735
761
  "/auth/resend-code",
736
- "/auth/check-email"
762
+ "/auth/check-email",
763
+ "/auth/forgot-password",
764
+ "/auth/reset-password"
737
765
  ]);
738
766
  /** Proactive refresh when token expires within this window (seconds). */
739
767
  static REFRESH_THRESHOLD_S = 5 * 60;
@@ -971,6 +999,12 @@ var ParallClient = class _ParallClient {
971
999
  async resendCode(email) {
972
1000
  return this.request("POST", ENDPOINTS.AUTH_RESEND_CODE, { email });
973
1001
  }
1002
+ async forgotPassword(email) {
1003
+ return this.request("POST", ENDPOINTS.AUTH_FORGOT_PASSWORD, { email });
1004
+ }
1005
+ async resetPassword(token, newPassword) {
1006
+ return this.request("POST", ENDPOINTS.AUTH_RESET_PASSWORD, { token, new_password: newPassword });
1007
+ }
974
1008
  // ---- WebSocket ----
975
1009
  async getWsTicket() {
976
1010
  return this.request("POST", ENDPOINTS.WS_TICKET);
@@ -1167,9 +1201,6 @@ var ParallClient = class _ParallClient {
1167
1201
  async deleteMessage(id) {
1168
1202
  return this.request("DELETE", ENDPOINTS.MESSAGE(id));
1169
1203
  }
1170
- async patchMessage(id, req) {
1171
- return this.request("POST", ENDPOINTS.MESSAGE_PATCHES(id), req);
1172
- }
1173
1204
  async getMessageReplies(id, params) {
1174
1205
  return this.request("GET", ENDPOINTS.MESSAGE_REPLIES(id), void 0, params);
1175
1206
  }
@@ -1180,8 +1211,8 @@ var ParallClient = class _ParallClient {
1180
1211
  async completeUpload(orgId, attachmentId) {
1181
1212
  return this.request("POST", ENDPOINTS.UPLOAD_COMPLETE(orgId), { attachment_id: attachmentId });
1182
1213
  }
1183
- async getFileUrl(id) {
1184
- return this.request("GET", ENDPOINTS.FILE(id));
1214
+ async getFileUrl(id, opts) {
1215
+ return this.request("GET", ENDPOINTS.FILE(id), void 0, opts?.download ? { download: true } : void 0);
1185
1216
  }
1186
1217
  // ---- Approvals ----
1187
1218
  async getApproval(id) {
@@ -1262,8 +1293,7 @@ var ParallClient = class _ParallClient {
1262
1293
  * @param params.status - Comma-separated status filter (e.g., `'open'`).
1263
1294
  */
1264
1295
  async getAgentSessions(orgId, agentId, params) {
1265
- const res = await this.request("GET", ENDPOINTS.AGENT_SESSIONS(orgId, agentId), void 0, params);
1266
- return res.data;
1296
+ return this.request("GET", ENDPOINTS.AGENT_SESSIONS(orgId, agentId), void 0, params);
1267
1297
  }
1268
1298
  async getAgentSession(orgId, agentId, sessionId) {
1269
1299
  return this.request("GET", ENDPOINTS.AGENT_SESSION(orgId, agentId, sessionId));
@@ -1275,12 +1305,14 @@ var ParallClient = class _ParallClient {
1275
1305
  return this.request("POST", ENDPOINTS.AGENT_SESSION_STEPS(orgId, agentId, sessionId), req);
1276
1306
  }
1277
1307
  async getAgentSessionSteps(orgId, agentId, sessionId, params) {
1278
- const res = await this.request("GET", ENDPOINTS.AGENT_SESSION_STEPS(orgId, agentId, sessionId), void 0, params);
1279
- return res.data;
1308
+ return this.request("GET", ENDPOINTS.AGENT_SESSION_STEPS(orgId, agentId, sessionId), void 0, params);
1280
1309
  }
1281
1310
  async getAgentSessionStep(orgId, agentId, sessionId, stepId) {
1282
1311
  return this.request("GET", ENDPOINTS.AGENT_SESSION_STEP(orgId, agentId, sessionId, stepId));
1283
1312
  }
1313
+ async getAgentStepById(orgId, stepId) {
1314
+ return this.request("GET", ENDPOINTS.AGENT_STEP_BY_ID(orgId, stepId));
1315
+ }
1284
1316
  // ---- Agent runtime auth (hosted Claude OAuth) ----
1285
1317
  async getAgentRuntimeAuth(orgId, agentId) {
1286
1318
  return this.request("GET", ENDPOINTS.AGENT_RUNTIME_AUTH(orgId, agentId));
@@ -1377,10 +1409,32 @@ var ParallClient = class _ParallClient {
1377
1409
  async detachAgent(orgId, machineId, agentId) {
1378
1410
  return this.request("DELETE", ENDPOINTS.MACHINE_DETACH_AGENT(orgId, machineId, agentId));
1379
1411
  }
1412
+ async listAgentWorkspaceStates(orgId, machineId) {
1413
+ const res = await this.request("GET", ENDPOINTS.MACHINE_WORKSPACE_STATES(orgId, machineId));
1414
+ return res.data;
1415
+ }
1416
+ async patchAgentDaemonConfig(orgId, machineId, agentId, daemonConfig) {
1417
+ return this.request("PATCH", ENDPOINTS.MACHINE_AGENT_DAEMON_CONFIG(orgId, machineId, agentId), { daemon_config: daemonConfig });
1418
+ }
1419
+ async retryAgentWorkspaceSetup(orgId, machineId, agentId) {
1420
+ return this.request("POST", ENDPOINTS.MACHINE_AGENT_WORKSPACE_SETUP(orgId, machineId, agentId));
1421
+ }
1422
+ async patchMachineLLMSource(orgId, machineId, llmSource) {
1423
+ return this.request("PATCH", ENDPOINTS.MACHINE_LLM_SOURCE(orgId, machineId), { llm_source: llmSource });
1424
+ }
1380
1425
  /** Get machine-level runtime auth state. */
1381
1426
  async getMachineRuntimeAuth(orgId, machineId) {
1382
1427
  return this.request("GET", ENDPOINTS.MACHINE_RUNTIME_AUTH(orgId, machineId));
1383
1428
  }
1429
+ async startMachineRuntimeAuthSession(orgId, machineId, req = {}) {
1430
+ return this.request("POST", ENDPOINTS.MACHINE_RUNTIME_AUTH_SESSIONS(orgId, machineId), req);
1431
+ }
1432
+ async completeMachineRuntimeAuthSession(orgId, machineId, sessionId, req) {
1433
+ return this.request("POST", ENDPOINTS.MACHINE_RUNTIME_AUTH_SESSION_COMPLETE(orgId, machineId, sessionId), req);
1434
+ }
1435
+ async disconnectMachineRuntimeAuth(orgId, machineId) {
1436
+ return this.request("DELETE", ENDPOINTS.MACHINE_RUNTIME_AUTH(orgId, machineId));
1437
+ }
1384
1438
  // ---- Machine self-control-plane (mck_-scoped) ----
1385
1439
  //
1386
1440
  // The four methods below are intended to be called from a daemon-mode
@@ -1410,6 +1464,12 @@ var ParallClient = class _ParallClient {
1410
1464
  async postMachineHeartbeat() {
1411
1465
  return this.request("POST", ENDPOINTS.MACHINES_ME_HEALTH);
1412
1466
  }
1467
+ async reportAgentWorkspaceState(agentId, state) {
1468
+ const res = await this.request("PUT", ENDPOINTS.MACHINES_ME_AGENT_WORKSPACE_STATE(agentId), state);
1469
+ if (res?.status === "ignored_stale") {
1470
+ throw new ApiError(409, "Workspace state report ignored as stale", "STALE_WORKSPACE_STATE");
1471
+ }
1472
+ }
1413
1473
  /**
1414
1474
  * `POST /machines/me/agents/{agentId}/launch-credential` — mint a
1415
1475
  * short-lived `agk_*` for one of this Machine's attached agents. The
@@ -1559,6 +1619,20 @@ var ParallClient = class _ParallClient {
1559
1619
  const res = await this.request("GET", ENDPOINTS.TASK_WATCHERS(orgId, taskId));
1560
1620
  return res.data;
1561
1621
  }
1622
+ async watchThread(threadRootId) {
1623
+ return this.request("POST", ENDPOINTS.MESSAGE_WATCH(threadRootId));
1624
+ }
1625
+ async unwatchThread(threadRootId) {
1626
+ return this.request("DELETE", ENDPOINTS.MESSAGE_WATCH(threadRootId));
1627
+ }
1628
+ async getThreadWatchers(threadRootId) {
1629
+ const res = await this.request("GET", ENDPOINTS.MESSAGE_WATCHERS(threadRootId));
1630
+ return res.data;
1631
+ }
1632
+ async isWatchingThread(threadRootId) {
1633
+ const res = await this.request("GET", ENDPOINTS.MESSAGE_WATCHING(threadRootId));
1634
+ return res.watching;
1635
+ }
1562
1636
  async getSubtasks(orgId, taskId) {
1563
1637
  const res = await this.request("GET", ENDPOINTS.TASK_SUBTASKS(orgId, taskId));
1564
1638
  return res.data;
@@ -1855,14 +1929,28 @@ var ParallClient = class _ParallClient {
1855
1929
  params.set("machine_id", opts.machine_id);
1856
1930
  if (opts?.unresolved_machine)
1857
1931
  params.set("unresolved_machine", "true");
1932
+ if (opts?.from)
1933
+ params.set("from", opts.from);
1934
+ if (opts?.to)
1935
+ params.set("to", opts.to);
1858
1936
  const qs = params.toString();
1859
1937
  return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}${qs ? `?${qs}` : ""}`);
1860
1938
  }
1861
- async listBillingTransactionAgentGroups(orgId) {
1862
- return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?group_by=agent`);
1863
- }
1864
- async listBillingTransactionMachineGroups(orgId) {
1865
- return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?group_by=machine`);
1939
+ async listBillingTransactionAgentGroups(orgId, opts) {
1940
+ const params = new URLSearchParams({ group_by: "agent" });
1941
+ if (opts?.from)
1942
+ params.set("from", opts.from);
1943
+ if (opts?.to)
1944
+ params.set("to", opts.to);
1945
+ return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?${params}`);
1946
+ }
1947
+ async listBillingTransactionMachineGroups(orgId, opts) {
1948
+ const params = new URLSearchParams({ group_by: "machine" });
1949
+ if (opts?.from)
1950
+ params.set("from", opts.from);
1951
+ if (opts?.to)
1952
+ params.set("to", opts.to);
1953
+ return this.request("GET", `${ENDPOINTS.BILLING_TRANSACTIONS(orgId)}?${params}`);
1866
1954
  }
1867
1955
  async createCheckout(orgId, req) {
1868
1956
  return this.request("POST", ENDPOINTS.BILLING_CHECKOUT(orgId), req);
@@ -1913,6 +2001,12 @@ var ApiError = class extends Error {
1913
2001
  };
1914
2002
 
1915
2003
  // ts/sdk/dist/ws.js
2004
+ function isRetryableNetworkError(err) {
2005
+ return err instanceof Error && err.name === "ApiError" && "status" in err && err.status === 0;
2006
+ }
2007
+ function isBrowserRuntime() {
2008
+ return typeof window !== "undefined";
2009
+ }
1916
2010
  var ParallWs = class {
1917
2011
  ws = null;
1918
2012
  options;
@@ -1948,7 +2042,11 @@ var ParallWs = class {
1948
2042
  try {
1949
2043
  ticket = await this.options.getTicket();
1950
2044
  } catch (err) {
1951
- console.error("Failed to get WS ticket:", err);
2045
+ if (isBrowserRuntime() && isRetryableNetworkError(err)) {
2046
+ console.warn("Failed to get WS ticket:", err);
2047
+ } else {
2048
+ console.error("Failed to get WS ticket:", err);
2049
+ }
1952
2050
  if (this.options.reconnect) {
1953
2051
  this.scheduleReconnect();
1954
2052
  } else {
@@ -2277,6 +2375,7 @@ var ParallAgentGateway = class {
2277
2375
  opts;
2278
2376
  chatInfoMap = /* @__PURE__ */ new Map();
2279
2377
  activeDispatches = /* @__PURE__ */ new Map();
2378
+ injectedTypingCounts = /* @__PURE__ */ new Map();
2280
2379
  dispatchedTasks = /* @__PURE__ */ new Set();
2281
2380
  dispatchedMessages = /* @__PURE__ */ new Set();
2282
2381
  forkStates = /* @__PURE__ */ new Map();
@@ -2312,9 +2411,9 @@ var ParallAgentGateway = class {
2312
2411
  this.SHUTDOWN_DEADLINE_MS = opts.shutdownDeadlineMs ?? 6e4;
2313
2412
  }
2314
2413
  async run(abortSignal) {
2315
- const { ws, log } = this.opts;
2414
+ const { ws, log: log2 } = this.opts;
2316
2415
  ws.onStateChange((state) => {
2317
- log?.info(`parall[${this.opts.accountId}]: connection state \u2192 ${state}`);
2416
+ log2?.info(`parall[${this.opts.accountId}]: connection state \u2192 ${state}`);
2318
2417
  });
2319
2418
  ws.on("hello", async (data) => {
2320
2419
  await this.handleHello(data);
@@ -2471,6 +2570,34 @@ var ParallAgentGateway = class {
2471
2570
  if (this.opts.ws.state === "connected")
2472
2571
  this.opts.ws.sendTyping(chatId, "stop");
2473
2572
  }
2573
+ shouldShowTyping(event) {
2574
+ return event.type === "message" && event.targetId.startsWith("cht_") && !event.noReply;
2575
+ }
2576
+ startInjectedTyping(event) {
2577
+ if (!this.shouldShowTyping(event))
2578
+ return;
2579
+ this.startTyping(event.targetId);
2580
+ this.injectedTypingCounts.set(event.targetId, (this.injectedTypingCounts.get(event.targetId) ?? 0) + 1);
2581
+ }
2582
+ takeInjectedTypingCount(chatId) {
2583
+ const count = this.injectedTypingCounts.get(chatId) ?? 0;
2584
+ this.injectedTypingCounts.delete(chatId);
2585
+ return count;
2586
+ }
2587
+ async runDispatchWithTyping(event, sessionKey, bodyForAgent, earlierEvents = [], captureText, opts = {}) {
2588
+ const showTyping = !opts.suppressStart && (this.shouldShowTyping(event) || earlierEvents.some((e) => this.shouldShowTyping(e)));
2589
+ if (showTyping)
2590
+ this.startTyping(event.targetId);
2591
+ try {
2592
+ return await this.runDispatch(event, sessionKey, bodyForAgent, earlierEvents, captureText);
2593
+ } finally {
2594
+ if (showTyping)
2595
+ this.stopTyping(event.targetId);
2596
+ for (let i = 0; i < (opts.injectedTypingCount ?? 0); i++) {
2597
+ this.stopTyping(event.targetId);
2598
+ }
2599
+ }
2600
+ }
2474
2601
  buildDispatchContext(event, sessionKey) {
2475
2602
  const binding = this.sessionBindings.get(sessionKey);
2476
2603
  return {
@@ -2503,7 +2630,8 @@ var ParallAgentGateway = class {
2503
2630
  trigger_ref: event.type === "task" ? { task_id: event.targetId } : event.type === "task_comment" ? { comment_id: event.messageId, task_id: event.targetId } : event.type === "schedule" ? { schedule_id: event.targetId, run_id: event.messageId } : event.type === "approval" ? { approval_id: event.messageId } : { message_id: event.messageId },
2504
2631
  sender_id: event.senderId,
2505
2632
  sender_name: event.senderName,
2506
- summary: event.body.substring(0, 200)
2633
+ summary: event.body.substring(0, 200),
2634
+ ...event.sentAt ? { sent_at: event.sentAt } : {}
2507
2635
  }
2508
2636
  });
2509
2637
  } catch (err) {
@@ -2727,7 +2855,8 @@ var ParallAgentGateway = class {
2727
2855
  continue;
2728
2856
  }
2729
2857
  if (!binding) {
2730
- throw new Error(`runtime emitted ${runtimeEvent.type} before runtime_session`);
2858
+ const detail = runtimeEvent.type === "error" ? `: ${runtimeEvent.message}` : "";
2859
+ throw new Error(`runtime emitted ${runtimeEvent.type} before runtime_session${detail}`);
2731
2860
  }
2732
2861
  if (!triggerMessageSet) {
2733
2862
  triggerMessageSet = true;
@@ -2801,7 +2930,7 @@ var ParallAgentGateway = class {
2801
2930
  const earlier = events.slice(0, -1);
2802
2931
  try {
2803
2932
  const batchText = [];
2804
- const dispatched = await this.runDispatch(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
2933
+ const dispatched = await this.runDispatchWithTyping(last, fork.fork.sessionKey, buildForkScopePrefix(last) + buildEventBody(last), earlier, batchText);
2805
2934
  if (!dispatched) {
2806
2935
  for (const item of items) {
2807
2936
  item.resolve(false);
@@ -2842,6 +2971,7 @@ var ParallAgentGateway = class {
2842
2971
  targetId: fork.targetId,
2843
2972
  summary: fork.processedEvents.length === 1 ? `${first.type} from ${first.senderName} in ${first.targetName ?? fork.targetId}` : `${fork.processedEvents.length} events in ${first.targetName ?? fork.targetId}`
2844
2973
  },
2974
+ eventBodies: fork.processedEvents.map((e) => buildEventBodyForForkResult(e)),
2845
2975
  actions: [],
2846
2976
  agentSummary,
2847
2977
  historyPath
@@ -2881,32 +3011,11 @@ var ParallAgentGateway = class {
2881
3011
  return;
2882
3012
  this.draining = true;
2883
3013
  try {
2884
- while (this.dispatchState.mainBuffer.length > 0 || this.dispatchState.pendingForkResults.length > 0) {
3014
+ while (this.dispatchState.mainBuffer.length > 0) {
2885
3015
  if (this.shuttingDown) {
2886
3016
  this.opts.log?.info(`parall[${this.opts.accountId}]: drainMainBuffer halted (shutting down) \u2014 ${this.dispatchState.mainBuffer.length} buffered, ${this.dispatchState.pendingForkResults.length} pending fork results left for catch-up`);
2887
3017
  break;
2888
3018
  }
2889
- if (this.dispatchState.mainBuffer.length === 0 && this.dispatchState.pendingForkResults.length > 0) {
2890
- const pending = this.dispatchState.pendingForkResults.splice(0);
2891
- const forkPrefix2 = buildForkResultPrefix(pending);
2892
- const syntheticEvent = {
2893
- type: "message",
2894
- targetId: "_orchestrator",
2895
- targetType: "system",
2896
- senderId: "system",
2897
- senderName: "system",
2898
- messageId: `synthetic-${this.opts.accountId}-${randomUUID()}`,
2899
- body: "[Orchestrator: fork session(s) completed \u2014 review results above]"
2900
- };
2901
- this.dispatchState.mainCurrentTargetId = void 0;
2902
- this.dispatchState.mainPreDispatchBranchPoint = this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
2903
- const dispatched2 = await this.runDispatch(syntheticEvent, this.opts.runtimeKey, forkPrefix2 + buildEventBody(syntheticEvent));
2904
- if (!dispatched2) {
2905
- this.dispatchState.pendingForkResults.unshift(...pending);
2906
- break;
2907
- }
2908
- continue;
2909
- }
2910
3019
  const targetId = this.dispatchState.mainBuffer[0].targetId;
2911
3020
  const events = [];
2912
3021
  while (this.dispatchState.mainBuffer[0]?.targetId === targetId) {
@@ -2914,12 +3023,13 @@ var ParallAgentGateway = class {
2914
3023
  }
2915
3024
  const event = events[events.length - 1];
2916
3025
  const earlier = events.slice(0, -1);
2917
- const skipForkSplice = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
2918
- const pendingFork = skipForkSplice ? [] : this.dispatchState.pendingForkResults.splice(0);
3026
+ const hasPendingInjections = this.opts.dispatchAdapter.hasPendingInjections?.(this.opts.runtimeKey) ?? false;
3027
+ const injectedTypingCount = hasPendingInjections ? this.takeInjectedTypingCount(event.targetId) : 0;
3028
+ const pendingFork = hasPendingInjections ? [] : this.dispatchState.pendingForkResults.splice(0);
2919
3029
  const forkPrefix = buildForkResultPrefix(pendingFork);
2920
3030
  this.dispatchState.mainCurrentTargetId = event.targetId;
2921
3031
  this.dispatchState.mainPreDispatchBranchPoint = this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
2922
- const dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier);
3032
+ const dispatched = await this.runDispatchWithTyping(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event), earlier, void 0, { suppressStart: injectedTypingCount > 0, injectedTypingCount });
2923
3033
  if (!dispatched) {
2924
3034
  this.dispatchState.mainBuffer.unshift(...events);
2925
3035
  this.dispatchState.pendingForkResults.unshift(...pendingFork);
@@ -2953,7 +3063,7 @@ var ParallAgentGateway = class {
2953
3063
  this.dispatchState.mainPreDispatchBranchPoint = this.opts.dispatchAdapter.getBranchPoint?.(this.opts.runtimeKey);
2954
3064
  let dispatched = false;
2955
3065
  try {
2956
- dispatched = await this.runDispatch(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
3066
+ dispatched = await this.runDispatchWithTyping(event, this.opts.runtimeKey, forkPrefix + buildEventBody(event));
2957
3067
  if (!dispatched) {
2958
3068
  this.dispatchState.pendingForkResults.unshift(...pendingFork);
2959
3069
  }
@@ -2966,10 +3076,15 @@ var ParallAgentGateway = class {
2966
3076
  if (this.shuttingDown) {
2967
3077
  return false;
2968
3078
  }
2969
- if (this.dispatchState.mainCurrentTargetId === event.targetId && this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
2970
- this.opts.log?.info(`parall[${this.opts.accountId}]: steer injected to stdin for ${event.messageId} (will drain for bookkeeping)`);
2971
- }
2972
3079
  this.dispatchState.mainBuffer.push(event);
3080
+ if (this.dispatchState.mainCurrentTargetId === event.targetId && await this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
3081
+ this.startInjectedTyping(event);
3082
+ this.opts.log?.info(`parall[${this.opts.accountId}]: steer injected for ${event.messageId} (will drain for bookkeeping)`);
3083
+ }
3084
+ if (!this.dispatchState.mainDispatching && !this.draining && this.dispatchState.mainBuffer.length > 0) {
3085
+ this.dispatchState.mainDispatching = true;
3086
+ void this.drainMainBuffer();
3087
+ }
2973
3088
  return false;
2974
3089
  }
2975
3090
  case "buffer-fork": {
@@ -3071,6 +3186,7 @@ var ParallAgentGateway = class {
3071
3186
  threadRootId: message.thread_root_id ?? void 0,
3072
3187
  noReply: message.hints?.no_reply ?? false,
3073
3188
  attachments: attachments.length > 0 ? attachments : void 0,
3189
+ sentAt: message.created_at,
3074
3190
  ackSourceType: "message",
3075
3191
  ackSourceId: message.id
3076
3192
  }
@@ -3092,9 +3208,6 @@ var ParallAgentGateway = class {
3092
3208
  return;
3093
3209
  }
3094
3210
  const event = decision.event;
3095
- const willDispatch = !this.dispatchState.mainDispatching || this.dispatchState.mainCurrentTargetId !== chatId;
3096
- if (willDispatch)
3097
- this.startTyping(chatId);
3098
3211
  try {
3099
3212
  const dispatched = await this.handleInboundEvent(event);
3100
3213
  if (dispatched) {
@@ -3106,9 +3219,6 @@ var ParallAgentGateway = class {
3106
3219
  } catch (err) {
3107
3220
  this.opts.log?.error(`parall[${this.opts.accountId}]: event dispatch failed for ${data.id}: ${String(err)}`);
3108
3221
  this.dispatchedMessages.delete(data.id);
3109
- } finally {
3110
- if (willDispatch)
3111
- this.stopTyping(chatId);
3112
3222
  }
3113
3223
  }
3114
3224
  async handleTaskAssignment(task, ackSourceId) {
@@ -3138,6 +3248,7 @@ var ParallAgentGateway = class {
3138
3248
  senderName: "system",
3139
3249
  messageId: task.id,
3140
3250
  body: parts.join("\n"),
3251
+ sentAt: task.updated_at ?? task.created_at,
3141
3252
  ackSourceType: "task_activity",
3142
3253
  ackSourceId
3143
3254
  };
@@ -3438,12 +3549,12 @@ var ParallAgentGateway = class {
3438
3549
  }
3439
3550
  }
3440
3551
  async handleHello(data) {
3441
- const { client, config, log } = this.opts;
3552
+ const { client, config, log: log2 } = this.opts;
3442
3553
  this.sessionId = data.session_id ?? "";
3443
3554
  const intervalSec = data.heartbeat_interval > 0 ? data.heartbeat_interval : 30;
3444
3555
  try {
3445
3556
  const count = await fetchAllChats(client, config.org_id, this.chatInfoMap);
3446
- log?.info(`parall[${this.opts.accountId}]: WebSocket connected, ${count} chats cached`);
3557
+ log2?.info(`parall[${this.opts.accountId}]: WebSocket connected, ${count} chats cached`);
3447
3558
  await this.opts.onSessionReady?.({
3448
3559
  activeSessionId: this.activeSessionId,
3449
3560
  ws: this.opts.ws,
@@ -3457,7 +3568,7 @@ var ParallAgentGateway = class {
3457
3568
  const expectedMs = intervalSec * 1e3;
3458
3569
  const drift = now - this.lastHeartbeatAt - expectedMs;
3459
3570
  if (drift > 15e3) {
3460
- log?.warn(`parall[${this.opts.accountId}]: heartbeat drift ${drift}ms \u2014 event loop may be blocked`);
3571
+ log2?.warn(`parall[${this.opts.accountId}]: heartbeat drift ${drift}ms \u2014 event loop may be blocked`);
3461
3572
  }
3462
3573
  this.lastHeartbeatAt = now;
3463
3574
  if (this.opts.ws.state !== "connected")
@@ -3473,10 +3584,10 @@ var ParallAgentGateway = class {
3473
3584
  const isFirstHello = !this.hadSuccessfulHello;
3474
3585
  this.hadSuccessfulHello = true;
3475
3586
  this.catchUpFromDispatch(isFirstHello).catch((err) => {
3476
- log?.warn(`parall[${this.opts.accountId}]: dispatch catch-up failed: ${String(err)}`);
3587
+ log2?.warn(`parall[${this.opts.accountId}]: dispatch catch-up failed: ${String(err)}`);
3477
3588
  });
3478
3589
  } catch (err) {
3479
- log?.error(`parall[${this.opts.accountId}]: failed to fetch chats: ${String(err)}`);
3590
+ log2?.error(`parall[${this.opts.accountId}]: failed to fetch chats: ${String(err)}`);
3480
3591
  }
3481
3592
  }
3482
3593
  // Resolves when in-flight dispatches hit 0 or the deadline elapses.
@@ -3581,7 +3692,7 @@ function extractDefaults(config, runtimeType) {
3581
3692
  return { model, thinkingEffort };
3582
3693
  }
3583
3694
  function createPlatformConfigManager(opts) {
3584
- const { client, stateDir, runtimeType, log } = opts;
3695
+ const { client, stateDir, runtimeType, log: log2 } = opts;
3585
3696
  let cachedVersion;
3586
3697
  let currentDefaults = { model: null, thinkingEffort: null };
3587
3698
  let currentRawConfig = null;
@@ -3598,20 +3709,20 @@ function createPlatformConfigManager(opts) {
3598
3709
  fresh = await client.getPlatformConfig(cachedVersion);
3599
3710
  } catch (err) {
3600
3711
  if (cached) {
3601
- log?.warn(`platform config fetch failed, using cached version ${cachedVersion}: ${String(err)}`);
3712
+ log2?.warn(`platform config fetch failed, using cached version ${cachedVersion}: ${String(err)}`);
3602
3713
  return currentDefaults;
3603
3714
  }
3604
- log?.warn(`platform config fetch failed and no cache available: ${String(err)}`);
3715
+ log2?.warn(`platform config fetch failed and no cache available: ${String(err)}`);
3605
3716
  return currentDefaults;
3606
3717
  }
3607
3718
  if (fresh === null) {
3608
3719
  return currentDefaults;
3609
3720
  }
3610
3721
  if (fresh.schema_version !== void 0 && fresh.schema_version > SUPPORTED_SCHEMA_VERSION) {
3611
- log?.warn(`platform config schema_version ${fresh.schema_version} > supported (${SUPPORTED_SCHEMA_VERSION}), keeping current`);
3722
+ log2?.warn(`platform config schema_version ${fresh.schema_version} > supported (${SUPPORTED_SCHEMA_VERSION}), keeping current`);
3612
3723
  return currentDefaults;
3613
3724
  }
3614
- log?.info(`platform config updated to version ${fresh.version}`);
3725
+ log2?.info(`platform config updated to version ${fresh.version}`);
3615
3726
  saveCache(stateDir, fresh);
3616
3727
  cachedVersion = fresh.version;
3617
3728
  currentRawConfig = fresh.config;
@@ -4199,9 +4310,8 @@ function stepIdFilePathForSession(stateDir, sessionKey) {
4199
4310
  }
4200
4311
 
4201
4312
  // ts/codex-agent/dist/dispatch.js
4202
- import { spawn } from "node:child_process";
4203
- import { execSync as execSync2 } from "node:child_process";
4204
- import { randomUUID as randomUUID2 } from "node:crypto";
4313
+ import { execSync as execSync2, spawn } from "node:child_process";
4314
+ import { randomUUID } from "node:crypto";
4205
4315
  import * as fs5 from "node:fs";
4206
4316
 
4207
4317
  // ts/agent-core/dist/internal/attachment-input.js
@@ -4503,7 +4613,7 @@ function sameFileIdentity(a, b) {
4503
4613
  function sameFile(a, b) {
4504
4614
  return sameFileIdentity(a, b) && a.size === b.size && a.mtimeMs === b.mtimeMs;
4505
4615
  }
4506
- async function cleanupOldAttachmentFiles(rootDir, ttlMs, log, preserveDirs) {
4616
+ async function cleanupOldAttachmentFiles(rootDir, ttlMs, log2, preserveDirs) {
4507
4617
  let entries;
4508
4618
  try {
4509
4619
  entries = await fs4.readdir(rootDir, { withFileTypes: true });
@@ -4525,11 +4635,11 @@ async function cleanupOldAttachmentFiles(rootDir, ttlMs, log, preserveDirs) {
4525
4635
  await fs4.rm(fullPath, { recursive: true, force: true });
4526
4636
  }
4527
4637
  } catch (err) {
4528
- log?.warn?.(`agent-core: failed to clean attachment temp dir ${fullPath}: ${String(err)}`);
4638
+ log2?.warn?.(`agent-core: failed to clean attachment temp dir ${fullPath}: ${String(err)}`);
4529
4639
  }
4530
4640
  }));
4531
4641
  }
4532
- async function pruneAttachmentCache(rootDir, maxBytes, log, preserveDirs) {
4642
+ async function pruneAttachmentCache(rootDir, maxBytes, log2, preserveDirs) {
4533
4643
  if (maxBytes <= 0)
4534
4644
  return;
4535
4645
  let entries;
@@ -4552,7 +4662,7 @@ async function pruneAttachmentCache(rootDir, maxBytes, log, preserveDirs) {
4552
4662
  dirs.push({ path: fullPath, mtimeMs: stat.mtimeMs, size });
4553
4663
  total += size;
4554
4664
  } catch (err) {
4555
- log?.warn?.(`agent-core: failed to inspect attachment cache dir ${fullPath}: ${String(err)}`);
4665
+ log2?.warn?.(`agent-core: failed to inspect attachment cache dir ${fullPath}: ${String(err)}`);
4556
4666
  }
4557
4667
  }
4558
4668
  if (total <= maxBytes)
@@ -4567,7 +4677,7 @@ async function pruneAttachmentCache(rootDir, maxBytes, log, preserveDirs) {
4567
4677
  await fs4.rm(dir.path, { recursive: true, force: true });
4568
4678
  total -= dir.size;
4569
4679
  } catch (err) {
4570
- log?.warn?.(`agent-core: failed to prune attachment cache dir ${dir.path}: ${String(err)}`);
4680
+ log2?.warn?.(`agent-core: failed to prune attachment cache dir ${dir.path}: ${String(err)}`);
4571
4681
  }
4572
4682
  }
4573
4683
  }
@@ -4996,14 +5106,16 @@ var DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
4996
5106
  var JsonRpcStdioClient = class {
4997
5107
  proc;
4998
5108
  requestTimeoutMs;
5109
+ killProcess;
4999
5110
  nextId = 1;
5000
5111
  pending = /* @__PURE__ */ new Map();
5001
5112
  buffer = "";
5002
5113
  onNotification = null;
5003
5114
  disposed = false;
5004
- constructor(proc, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
5115
+ constructor(proc, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, killProcess) {
5005
5116
  this.proc = proc;
5006
5117
  this.requestTimeoutMs = requestTimeoutMs;
5118
+ this.killProcess = killProcess;
5007
5119
  proc.stdout.setEncoding("utf8");
5008
5120
  proc.stdout.on("data", (chunk) => this.ingest(chunk));
5009
5121
  proc.once("close", () => this.dispose(new Error("app-server subprocess closed")));
@@ -5063,7 +5175,11 @@ var JsonRpcStdioClient = class {
5063
5175
  killUnhealthy(err) {
5064
5176
  this.dispose(err);
5065
5177
  if (this.proc.exitCode === null && this.proc.signalCode === null) {
5066
- this.proc.kill("SIGTERM");
5178
+ if (this.killProcess) {
5179
+ this.killProcess(this.proc);
5180
+ } else {
5181
+ this.proc.kill("SIGTERM");
5182
+ }
5067
5183
  }
5068
5184
  }
5069
5185
  ingest(chunk) {
@@ -5110,6 +5226,20 @@ function isNotification(m) {
5110
5226
  }
5111
5227
 
5112
5228
  // ts/codex-agent/dist/dispatch.js
5229
+ var IS_WIN32 = process.platform === "win32";
5230
+ function quoteWin32Arg(arg) {
5231
+ if (!/[\s"&|^<>()]/.test(arg))
5232
+ return arg;
5233
+ return `"${arg.replace(/"/g, '""')}"`;
5234
+ }
5235
+ function killWin32Tree(pid) {
5236
+ try {
5237
+ execSync2(`taskkill /T /F /PID ${pid}`, { windowsHide: true, stdio: "ignore" });
5238
+ return true;
5239
+ } catch {
5240
+ return false;
5241
+ }
5242
+ }
5113
5243
  var CodexAppServerAdapter = class {
5114
5244
  opts;
5115
5245
  client = null;
@@ -5117,6 +5247,8 @@ var CodexAppServerAdapter = class {
5117
5247
  initialized = false;
5118
5248
  startPromise = null;
5119
5249
  activeTurns = /* @__PURE__ */ new Map();
5250
+ activeTurnIds = /* @__PURE__ */ new Map();
5251
+ pendingInjections = /* @__PURE__ */ new Map();
5120
5252
  resumedThreadIds = /* @__PURE__ */ new Set();
5121
5253
  stopping = false;
5122
5254
  /**
@@ -5127,10 +5259,10 @@ var CodexAppServerAdapter = class {
5127
5259
  * replacement would be a perpetually hung dispatch generator, which is
5128
5260
  * hard to debug.
5129
5261
  */
5130
- setActiveTurn(threadId, sink, log) {
5262
+ setActiveTurn(threadId, sink, log2) {
5131
5263
  const existing = this.activeTurns.get(threadId);
5132
5264
  if (existing) {
5133
- (log ?? this.opts.log)?.warn?.(`codex-agent: thread ${threadId} already had an active turn; failing the previous dispatch`);
5265
+ (log2 ?? this.opts.log)?.warn?.(`codex-agent: thread ${threadId} already had an active turn; failing the previous dispatch`);
5134
5266
  existing.push({ kind: "error", message: `thread ${threadId} replaced by concurrent turn` });
5135
5267
  existing.close();
5136
5268
  }
@@ -5145,14 +5277,55 @@ var CodexAppServerAdapter = class {
5145
5277
  if (config.reasoningEffort !== void 0)
5146
5278
  this.opts.reasoningEffort = config.reasoningEffort ?? void 0;
5147
5279
  }
5280
+ async enqueueDuringDispatch(sessionKey, body) {
5281
+ const client = this.client;
5282
+ if (!client || client.isDisposed())
5283
+ return false;
5284
+ const threadId = this.opts.sessionManager.getThreadId(sessionKey);
5285
+ if (!threadId)
5286
+ return false;
5287
+ const turnId = this.activeTurnIds.get(threadId);
5288
+ if (!turnId)
5289
+ return false;
5290
+ try {
5291
+ await client.sendRequest("turn/steer", {
5292
+ threadId,
5293
+ expectedTurnId: turnId,
5294
+ input: buildTurnInput(body, [])
5295
+ });
5296
+ this.pendingInjections.set(sessionKey, (this.pendingInjections.get(sessionKey) ?? 0) + 1);
5297
+ return true;
5298
+ } catch (err) {
5299
+ this.opts.log?.warn?.(`codex-agent: turn/steer failed: ${errToString(err)}`);
5300
+ return false;
5301
+ }
5302
+ }
5303
+ hasPendingInjections(sessionKey) {
5304
+ return (this.pendingInjections.get(sessionKey) ?? 0) > 0;
5305
+ }
5148
5306
  async *dispatch({ event, bodyForAgent, sessionKey, context }) {
5307
+ const pending = this.pendingInjections.get(sessionKey) ?? 0;
5308
+ if (pending > 0) {
5309
+ this.pendingInjections.delete(sessionKey);
5310
+ const threadId2 = this.opts.sessionManager.getThreadId(sessionKey);
5311
+ if (threadId2 && this.client && !this.client.isDisposed()) {
5312
+ (this.opts.log ?? context.log)?.info?.(`codex-agent[${context.accountId}]: ${pending} steer injection(s) already sent; skipping turn/start`);
5313
+ yield {
5314
+ type: "runtime_session",
5315
+ runtimeSessionId: threadId2,
5316
+ runtimeLaneKey: sessionKey
5317
+ };
5318
+ return;
5319
+ }
5320
+ (this.opts.log ?? context.log)?.warn?.(`codex-agent[${context.accountId}]: pending steer invalidated (subprocess died); falling through to normal dispatch`);
5321
+ }
5149
5322
  await this.ensureStarted(context.log);
5150
5323
  const client = this.client;
5151
5324
  if (!client) {
5152
5325
  yield { type: "error", message: "Codex app-server not available (subprocess died during dispatch start)" };
5153
5326
  return;
5154
5327
  }
5155
- const log = this.opts.log ?? context.log;
5328
+ const log2 = this.opts.log ?? context.log;
5156
5329
  const isMainSession = this.opts.sessionManager.isMain(sessionKey);
5157
5330
  let threadId = this.opts.sessionManager.getThreadId(sessionKey);
5158
5331
  if (!threadId) {
@@ -5170,7 +5343,7 @@ var CodexAppServerAdapter = class {
5170
5343
  this.opts.sessionManager.recordThreadId(sessionKey, threadId);
5171
5344
  this.resumedThreadIds.add(threadId);
5172
5345
  } catch (err) {
5173
- log?.warn?.(`codex-agent: thread/resume failed (${errToString(err)}); attempting one-shot fresh-thread start`);
5346
+ log2?.warn?.(`codex-agent: thread/resume failed (${errToString(err)}); attempting one-shot fresh-thread start`);
5174
5347
  let freshThreadId;
5175
5348
  try {
5176
5349
  freshThreadId = await this.openThread(client, { resumeId: void 0 });
@@ -5188,8 +5361,8 @@ var CodexAppServerAdapter = class {
5188
5361
  }
5189
5362
  }
5190
5363
  const sink = new TurnSink();
5191
- this.setActiveTurn(threadId, sink, log);
5192
- const groupKey = randomUUID2();
5364
+ this.setActiveTurn(threadId, sink, log2);
5365
+ const groupKey = randomUUID();
5193
5366
  let sawTurnEnd = false;
5194
5367
  let releasePreparedAttachments = () => {
5195
5368
  };
@@ -5199,13 +5372,13 @@ var CodexAppServerAdapter = class {
5199
5372
  try {
5200
5373
  const prepared = await appendPreparedLocalAttachmentRefs(bodyForAgent, event, context, {
5201
5374
  workspaceDir: this.opts.workspaceDir,
5202
- log
5375
+ log: log2
5203
5376
  });
5204
5377
  preparedBody = prepared.body;
5205
5378
  preparedImages = prepared.attachments.images;
5206
5379
  releasePreparedAttachments = pinLocalAttachmentPaths(preparedImages);
5207
5380
  } catch (err) {
5208
- log?.warn?.(`codex-agent[${context.accountId}]: failed to prepare local attachments: ${errToString(err)}`);
5381
+ log2?.warn?.(`codex-agent[${context.accountId}]: failed to prepare local attachments: ${errToString(err)}`);
5209
5382
  }
5210
5383
  const turnInput = buildTurnInput(preparedBody, preparedImages);
5211
5384
  const startTurn = (targetThreadId) => client.sendRequest("turn/start", {
@@ -5226,7 +5399,7 @@ var CodexAppServerAdapter = class {
5226
5399
  yield { type: "error", message: `Codex turn/start failed: ${message}` };
5227
5400
  return;
5228
5401
  }
5229
- log?.warn?.(`codex-agent: turn/start on thread ${threadId} failed (${message}); attempting one-shot fresh-thread retry`);
5402
+ log2?.warn?.(`codex-agent: turn/start on thread ${threadId} failed (${message}); attempting one-shot fresh-thread retry`);
5230
5403
  this.activeTurns.delete(threadId);
5231
5404
  let freshThreadId;
5232
5405
  try {
@@ -5240,7 +5413,7 @@ var CodexAppServerAdapter = class {
5240
5413
  yield { type: "error", message: `Codex turn/start failed; could not create replacement thread: ${errToString(createErr)}` };
5241
5414
  return;
5242
5415
  }
5243
- this.setActiveTurn(freshThreadId, sink, log);
5416
+ this.setActiveTurn(freshThreadId, sink, log2);
5244
5417
  try {
5245
5418
  turnStartResult = await startTurn(freshThreadId);
5246
5419
  } catch (retryErr) {
@@ -5258,7 +5431,9 @@ var CodexAppServerAdapter = class {
5258
5431
  this.resumedThreadIds.add(freshThreadId);
5259
5432
  threadId = freshThreadId;
5260
5433
  }
5261
- void turnStartResult;
5434
+ const turnId = extractTurnId(turnStartResult);
5435
+ if (turnId)
5436
+ this.activeTurnIds.set(threadId, turnId);
5262
5437
  yield {
5263
5438
  type: "runtime_session",
5264
5439
  runtimeSessionId: threadId,
@@ -5292,6 +5467,7 @@ var CodexAppServerAdapter = class {
5292
5467
  } finally {
5293
5468
  releasePreparedAttachments();
5294
5469
  this.activeTurns.delete(threadId);
5470
+ this.activeTurnIds.delete(threadId);
5295
5471
  if (!sawTurnEnd) {
5296
5472
  sink.close();
5297
5473
  }
@@ -5309,10 +5485,19 @@ var CodexAppServerAdapter = class {
5309
5485
  return null;
5310
5486
  const handle = this.opts.sessionManager.createForkSessionKey();
5311
5487
  try {
5312
- const result = await client.sendRequest("thread/fork", {
5488
+ const forkParams = {
5313
5489
  threadId: parentThreadId,
5314
5490
  ephemeral: true
5315
- });
5491
+ };
5492
+ if (this.opts.useParallProvider) {
5493
+ forkParams.modelProvider = "parall";
5494
+ }
5495
+ if (this.opts.model)
5496
+ forkParams.model = this.opts.model;
5497
+ if (this.opts.reasoningEffort) {
5498
+ forkParams.config = { modelReasoningEffort: this.opts.reasoningEffort };
5499
+ }
5500
+ const result = await client.sendRequest("thread/fork", forkParams);
5316
5501
  const forkedThreadId = extractThreadId(result);
5317
5502
  if (!forkedThreadId) {
5318
5503
  this.opts.log?.warn?.("codex-agent: thread/fork returned no thread id");
@@ -5338,19 +5523,25 @@ var CodexAppServerAdapter = class {
5338
5523
  this.proc = null;
5339
5524
  this.client = null;
5340
5525
  this.initialized = false;
5526
+ this.activeTurnIds.clear();
5527
+ this.pendingInjections.clear();
5341
5528
  if (client)
5342
5529
  client.dispose(new Error("adapter stopped"));
5343
5530
  if (proc && proc.exitCode === null && proc.signalCode === null) {
5344
- proc.kill("SIGTERM");
5531
+ if (!IS_WIN32 || !proc.pid || !killWin32Tree(proc.pid)) {
5532
+ proc.kill("SIGTERM");
5533
+ }
5345
5534
  }
5346
5535
  }
5347
- async ensureStarted(log) {
5536
+ async ensureStarted(log2) {
5348
5537
  if (this.client?.isDisposed()) {
5349
5538
  for (const activeSink of this.activeTurns.values()) {
5350
5539
  activeSink.push({ kind: "error", message: "Codex app-server disposed; resetting adapter" });
5351
5540
  activeSink.close();
5352
5541
  }
5353
5542
  this.activeTurns.clear();
5543
+ this.activeTurnIds.clear();
5544
+ this.pendingInjections.clear();
5354
5545
  this.client = null;
5355
5546
  this.proc = null;
5356
5547
  this.initialized = false;
@@ -5360,14 +5551,14 @@ var CodexAppServerAdapter = class {
5360
5551
  return;
5361
5552
  if (this.startPromise)
5362
5553
  return this.startPromise;
5363
- this.startPromise = this.doStart(log);
5554
+ this.startPromise = this.doStart(log2);
5364
5555
  try {
5365
5556
  await this.startPromise;
5366
5557
  } finally {
5367
5558
  this.startPromise = null;
5368
5559
  }
5369
5560
  }
5370
- async doStart(log) {
5561
+ async doStart(log2) {
5371
5562
  this.stopping = false;
5372
5563
  ensureGitRepo(this.opts.workspaceDir);
5373
5564
  const env = {
@@ -5380,20 +5571,25 @@ var CodexAppServerAdapter = class {
5380
5571
  env.PRLL_CONTEXT_FILE = this.opts.contextFilePath;
5381
5572
  }
5382
5573
  const args = ["app-server", "--listen", "stdio://"];
5383
- (log ?? this.opts.log)?.info?.(`codex-agent: spawning ${this.opts.codexBin} ${args.join(" ")}`);
5384
- const proc = spawn(this.opts.codexBin, args, {
5574
+ (log2 ?? this.opts.log)?.info?.(`codex-agent: spawning ${this.opts.codexBin} ${args.join(" ")}`);
5575
+ const proc = spawn(IS_WIN32 ? quoteWin32Arg(this.opts.codexBin) : this.opts.codexBin, IS_WIN32 ? args.map(quoteWin32Arg) : args, {
5385
5576
  cwd: this.opts.workspaceDir,
5386
5577
  env,
5387
- stdio: ["pipe", "pipe", "pipe"]
5578
+ stdio: ["pipe", "pipe", "pipe"],
5579
+ shell: IS_WIN32
5388
5580
  });
5389
5581
  proc.stderr.setEncoding("utf8");
5390
5582
  proc.stderr.on("data", (chunk) => {
5391
- (log ?? this.opts.log)?.warn?.(`codex-agent[stderr]: ${chunk.trim()}`);
5583
+ (log2 ?? this.opts.log)?.warn?.(`codex-agent[stderr]: ${chunk.trim()}`);
5584
+ });
5585
+ const client = new JsonRpcStdioClient(proc, void 0, (p) => {
5586
+ if (!IS_WIN32 || !p.pid || !killWin32Tree(p.pid)) {
5587
+ p.kill("SIGTERM");
5588
+ }
5392
5589
  });
5393
- const client = new JsonRpcStdioClient(proc);
5394
5590
  client.setNotificationHandler((method, params) => this.routeNotification(method, params));
5395
- proc.once("close", (code, signal) => this.handleSubprocessClose(proc, code, signal, log));
5396
- proc.once("error", (err) => this.handleSubprocessClose(proc, null, null, log, err));
5591
+ proc.once("close", (code, signal) => this.handleSubprocessClose(proc, code, signal, log2));
5592
+ proc.once("error", (err) => this.handleSubprocessClose(proc, null, null, log2, err));
5397
5593
  try {
5398
5594
  await client.sendRequest("initialize", {
5399
5595
  clientInfo: { name: "parall-codex-agent", version: "1" },
@@ -5402,19 +5598,22 @@ var CodexAppServerAdapter = class {
5402
5598
  client.sendNotification("initialized", {});
5403
5599
  } catch (err) {
5404
5600
  client.dispose(err instanceof Error ? err : new Error(String(err)));
5405
- if (proc.exitCode === null && proc.signalCode === null)
5406
- proc.kill("SIGTERM");
5601
+ if (proc.exitCode === null && proc.signalCode === null) {
5602
+ if (!IS_WIN32 || !proc.pid || !killWin32Tree(proc.pid)) {
5603
+ proc.kill("SIGTERM");
5604
+ }
5605
+ }
5407
5606
  throw err;
5408
5607
  }
5409
5608
  this.proc = proc;
5410
5609
  this.client = client;
5411
5610
  this.initialized = true;
5412
5611
  }
5413
- handleSubprocessClose(proc, code, signal, log, err) {
5612
+ handleSubprocessClose(proc, code, signal, log2, err) {
5414
5613
  if (this.proc !== null && this.proc !== proc)
5415
5614
  return;
5416
5615
  const reason = err ? `spawn error: ${err.message}` : `exited (code=${code ?? "null"}${signal ? `, signal=${signal}` : ""})`;
5417
- const logger = log ?? this.opts.log;
5616
+ const logger = log2 ?? this.opts.log;
5418
5617
  if (this.stopping) {
5419
5618
  logger?.info?.(`codex-agent: app-server subprocess ${reason} during graceful stop`);
5420
5619
  } else {
@@ -5426,6 +5625,8 @@ var CodexAppServerAdapter = class {
5426
5625
  activeSink.close();
5427
5626
  }
5428
5627
  this.activeTurns.clear();
5628
+ this.activeTurnIds.clear();
5629
+ this.pendingInjections.clear();
5429
5630
  this.resumedThreadIds.clear();
5430
5631
  this.client = null;
5431
5632
  this.proc = null;
@@ -5471,6 +5672,7 @@ var CodexAppServerAdapter = class {
5471
5672
  sink.push({ kind: "runtime", event });
5472
5673
  }
5473
5674
  if (method === "turn/completed") {
5675
+ this.activeTurnIds.delete(threadId);
5474
5676
  sink.push({ kind: "turn_end", threadId });
5475
5677
  }
5476
5678
  }
@@ -5548,6 +5750,17 @@ function extractThreadId(result) {
5548
5750
  return thread.id;
5549
5751
  return void 0;
5550
5752
  }
5753
+ function extractTurnId(result) {
5754
+ if (!result || typeof result !== "object")
5755
+ return void 0;
5756
+ const r = result;
5757
+ if (typeof r.turnId === "string")
5758
+ return r.turnId;
5759
+ const turn = r.turn;
5760
+ if (turn && typeof turn.id === "string")
5761
+ return turn.id;
5762
+ return void 0;
5763
+ }
5551
5764
  function extractThreadIdFromNotification(params) {
5552
5765
  if (!params || typeof params !== "object")
5553
5766
  return void 0;
@@ -6332,7 +6545,7 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
6332
6545
  }
6333
6546
 
6334
6547
  // ts/codex-agent/dist/workspace.js
6335
- function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
6548
+ function ensureWorkspaceTrusted(codexHome, workspaceDir, log2) {
6336
6549
  const configPath = path7.join(codexHome, "config.toml");
6337
6550
  const normalizedPath = path7.resolve(workspaceDir);
6338
6551
  try {
@@ -6348,7 +6561,7 @@ function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
6348
6561
  try {
6349
6562
  parsed = parse(content);
6350
6563
  } catch {
6351
- log?.warn(`Codex config.toml is not valid TOML; skipping trust write for ${normalizedPath}`);
6564
+ log2?.warn(`Codex config.toml is not valid TOML; skipping trust write for ${normalizedPath}`);
6352
6565
  return;
6353
6566
  }
6354
6567
  }
@@ -6380,9 +6593,9 @@ ${trustLine}
6380
6593
  }
6381
6594
  fs7.writeFileSync(configPath, content, "utf8");
6382
6595
  } else if (projects?.[normalizedPath] !== void 0) {
6383
- log?.warn(`Codex config.toml has non-canonical header for ${normalizedPath}; skipping trust write`);
6596
+ log2?.warn(`Codex config.toml has non-canonical header for ${normalizedPath}; skipping trust write`);
6384
6597
  } else if (projects && !content.includes("[projects.")) {
6385
- log?.warn(`Codex config.toml uses inline table for projects; skipping trust write for ${normalizedPath}`);
6598
+ log2?.warn(`Codex config.toml uses inline table for projects; skipping trust write for ${normalizedPath}`);
6386
6599
  } else {
6387
6600
  fs7.mkdirSync(codexHome, { recursive: true });
6388
6601
  fs7.appendFileSync(configPath, `
@@ -6391,7 +6604,7 @@ ${trustLine}
6391
6604
  `, "utf8");
6392
6605
  }
6393
6606
  } catch (err) {
6394
- log?.warn(`failed to write Codex project trust for ${normalizedPath}: ${String(err)}`);
6607
+ log2?.warn(`failed to write Codex project trust for ${normalizedPath}: ${String(err)}`);
6395
6608
  }
6396
6609
  }
6397
6610
  function isParallProxyMode(env = process.env) {
@@ -6401,7 +6614,7 @@ function isParallProxyMode(env = process.env) {
6401
6614
  return false;
6402
6615
  return baseUrl === apiUrl || baseUrl.startsWith(`${apiUrl}/`);
6403
6616
  }
6404
- function ensureParallProvider(codexHome, apiUrl, log) {
6617
+ function ensureParallProvider(codexHome, apiUrl, log2) {
6405
6618
  const configPath = path7.join(codexHome, "config.toml");
6406
6619
  const baseUrl = apiUrl.replace(/\/$/, "") + "/api/llm/v1";
6407
6620
  try {
@@ -6445,7 +6658,7 @@ function findSectionEnd(content, fromIndex) {
6445
6658
  const nextHeader = content.indexOf("\n[", fromIndex);
6446
6659
  return nextHeader === -1 ? content.length : nextHeader;
6447
6660
  }
6448
- function ensureCodexWorkspace(workspaceDir, log, agentIdentity) {
6661
+ function ensureCodexWorkspace(workspaceDir, log2, agentIdentity) {
6449
6662
  const systemPrompt = [
6450
6663
  buildIdentity(agentIdentity),
6451
6664
  BRIDGE_WORKSPACE_INSTRUCTIONS,
@@ -6468,13 +6681,7 @@ ${systemPrompt.replace(/\\/g, "\\\\").replace(/"""/g, '\\"""')}
6468
6681
  }
6469
6682
 
6470
6683
  // ts/codex-agent/dist/index.js
6471
- function createLogger(prefix) {
6472
- return {
6473
- info: (msg) => console.log(`[${prefix}] ${msg}`),
6474
- warn: (msg) => console.warn(`[${prefix}] ${msg}`),
6475
- error: (msg) => console.error(`[${prefix}] ${msg}`)
6476
- };
6477
- }
6684
+ var log = createLogger("codex-agent");
6478
6685
  async function getAgentMeWithLegacyFallback(client, orgId) {
6479
6686
  try {
6480
6687
  return await client.getAgentMe(orgId);
@@ -6488,7 +6695,6 @@ async function getAgentMeWithLegacyFallback(client, orgId) {
6488
6695
  }
6489
6696
  async function main() {
6490
6697
  const config = resolveCodexAgentConfig(process.env);
6491
- const log = createLogger("codex-agent");
6492
6698
  const client = new ParallClient({
6493
6699
  baseUrl: config.apiUrl,
6494
6700
  token: config.apiKey,
@@ -6596,7 +6802,7 @@ async function main() {
6596
6802
  }
6597
6803
  }
6598
6804
  main().catch((err) => {
6599
- console.error(`[codex-agent] fatal: ${String(err)}`);
6805
+ log.error(`fatal: ${String(err)}`);
6600
6806
  process.exitCode = 1;
6601
6807
  });
6602
6808
  /*! Bundled license information: