@parall/daemon 1.29.3 → 1.30.0

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.
@@ -428,9 +428,13 @@ function createLogger(prefix) {
428
428
  return {
429
429
  info: (msg) => console.log(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
430
430
  warn: (msg) => console.warn(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
431
- error: (msg) => console.error(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`)
431
+ error: (msg) => console.error(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
432
+ child: (sub) => createLogger(`${prefix}:${sub}`)
432
433
  };
433
434
  }
435
+ function childLogger(logger, sub) {
436
+ return logger.child ? logger.child(sub) : logger;
437
+ }
434
438
 
435
439
  // ts/agent-core/dist/gateway-base.js
436
440
  import * as os from "node:os";
@@ -513,6 +517,7 @@ var ENDPOINTS = {
513
517
  AGENT_ACTIVITY: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/activity`,
514
518
  AGENT_MONITOR: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/monitor`,
515
519
  AGENT_ME: (orgId) => `${API_BASE}/orgs/${orgId}/agents/me`,
520
+ AGENT_NEW_SESSION: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/new-session`,
516
521
  AGENT_SESSIONS: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions`,
517
522
  AGENT_SESSION: (orgId, agentId, sessionId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}`,
518
523
  AGENT_SESSION_STEPS: (orgId, agentId, sessionId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}/steps`,
@@ -551,6 +556,7 @@ var ENDPOINTS = {
551
556
  MACHINE_KEY: (orgId, machineId, keyId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys/${keyId}`,
552
557
  MACHINE_RUNTIME_AUTH_SESSIONS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth-sessions`,
553
558
  MACHINE_RUNTIME_AUTH_SESSION_COMPLETE: (orgId, machineId, sessionId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth-sessions/${sessionId}/complete`,
559
+ MACHINE_BROWSE: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/browse`,
554
560
  // Machine self-control-plane (mck_-scoped). The bearer token implicitly
555
561
  // identifies the Machine, so there is no `:mid` URL parameter — these are
556
562
  // "self" routes called by the daemon for its own host.
@@ -560,6 +566,7 @@ var ENDPOINTS = {
560
566
  MACHINES_ME_AGENT_LAUNCH_CREDENTIAL: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/launch-credential`,
561
567
  MACHINES_ME_AGENT_WORKSPACE_STATE: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/workspace-state`,
562
568
  MACHINES_ME_WS_TICKET: `${API_BASE}/machines/me/ws/ticket`,
569
+ MACHINES_ME_BROWSE_RESPONSE: (requestId) => `${API_BASE}/machines/me/browse-response/${requestId}`,
563
570
  // Tasks (org-scoped)
564
571
  TASKS: (orgId) => `${API_BASE}/orgs/${orgId}/tasks`,
565
572
  TASK: (orgId, taskId) => `${API_BASE}/orgs/${orgId}/tasks/${taskId}`,
@@ -739,7 +746,9 @@ var WS_EVENTS = {
739
746
  MACHINE_AGENT_ATTACHED: "machine.agent.attached",
740
747
  MACHINE_AGENT_DETACHED: "machine.agent.detached",
741
748
  MACHINE_STOP: "machine.stop",
742
- MACHINE_WORKSPACE_SETUP_REQUESTED: "machine.workspace.setup.requested"
749
+ MACHINE_WORKSPACE_SETUP_REQUESTED: "machine.workspace.setup.requested",
750
+ MACHINE_FILESYSTEM_BROWSE: "machine.filesystem.browse",
751
+ AGENT_NEW_SESSION: "agent.new_session"
743
752
  };
744
753
 
745
754
  // ts/sdk/dist/client.js
@@ -1285,6 +1294,9 @@ var ParallClient = class _ParallClient {
1285
1294
  return this.request("GET", ENDPOINTS.AGENT_ME(orgId));
1286
1295
  }
1287
1296
  // ---- Agent Sessions (org-scoped) ----
1297
+ async requestNewAgentSession(orgId, agentId) {
1298
+ return this.request("POST", ENDPOINTS.AGENT_NEW_SESSION(orgId, agentId));
1299
+ }
1288
1300
  async createAgentSession(orgId, agentId, req) {
1289
1301
  return this.request("POST", ENDPOINTS.AGENT_SESSIONS(orgId, agentId), req);
1290
1302
  }
@@ -1484,9 +1496,15 @@ var ParallClient = class _ParallClient {
1484
1496
  async getMachineWsTicket() {
1485
1497
  return this.request("POST", ENDPOINTS.MACHINES_ME_WS_TICKET);
1486
1498
  }
1499
+ async postBrowseResponse(requestId, response) {
1500
+ return this.request("POST", ENDPOINTS.MACHINES_ME_BROWSE_RESPONSE(requestId), response);
1501
+ }
1487
1502
  async resizeMachine(orgId, machineId, spec) {
1488
1503
  return this.request("PATCH", ENDPOINTS.MACHINE_SPEC(orgId, machineId), spec);
1489
1504
  }
1505
+ async browseMachineFilesystem(orgId, machineId, path9) {
1506
+ return this.request("POST", ENDPOINTS.MACHINE_BROWSE(orgId, machineId), { path: path9 }, void 0, false, { timeoutMs: 15e3 });
1507
+ }
1490
1508
  /** Create a new machine key. Returns the raw key string (shown once) + metadata. */
1491
1509
  async createMachineKey(orgId, machineId, name) {
1492
1510
  return this.request("POST", ENDPOINTS.MACHINE_KEYS(orgId, machineId), name ? { name } : void 0);
@@ -2399,6 +2417,7 @@ var ParallAgentGateway = class {
2399
2417
  shuttingDown = false;
2400
2418
  inFlightDispatches = 0;
2401
2419
  drainResolvers = [];
2420
+ pendingRestartNotification = null;
2402
2421
  DISPATCHED_MESSAGES_CAP = 5e3;
2403
2422
  COLD_START_WINDOW_MS;
2404
2423
  // SHUTDOWN_DEADLINE_MS is read by waitForDrain via the configured value
@@ -2413,7 +2432,7 @@ var ParallAgentGateway = class {
2413
2432
  async run(abortSignal) {
2414
2433
  const { ws, log: log2 } = this.opts;
2415
2434
  ws.onStateChange((state) => {
2416
- log2?.info(`parall[${this.opts.accountId}]: connection state \u2192 ${state}`);
2435
+ log2?.info(`connection state \u2192 ${state}`);
2417
2436
  });
2418
2437
  ws.on("hello", async (data) => {
2419
2438
  await this.handleHello(data);
@@ -2442,16 +2461,29 @@ var ParallAgentGateway = class {
2442
2461
  await this.handleMessage(data);
2443
2462
  });
2444
2463
  ws.on("agent_config.update", async (data) => {
2445
- this.opts.log?.info(`parall[${this.opts.accountId}]: config update notification (version=${data.version})`);
2464
+ this.opts.log?.info(`config update notification (version=${data.version})`);
2446
2465
  try {
2447
2466
  await this.opts.onConfigUpdate?.(data);
2448
2467
  } catch (err) {
2449
- this.opts.log?.warn(`parall[${this.opts.accountId}]: config update failed: ${String(err)}`);
2468
+ this.opts.log?.warn(`config update failed: ${String(err)}`);
2469
+ }
2470
+ });
2471
+ ws.on("agent.new_session", async (data) => {
2472
+ const prevId = data.previous_session_id ?? "";
2473
+ this.opts.log?.info(`new session signal received (previous=${prevId})`);
2474
+ this.sessionBindings.clear();
2475
+ if (prevId) {
2476
+ this.pendingRestartNotification = `[Harness Notification] This is a fresh session. Your previous session (${prevId}) was ended by the user and you have been restarted.`;
2477
+ }
2478
+ try {
2479
+ await this.opts.onNewSession?.(prevId);
2480
+ } catch (err) {
2481
+ this.opts.log?.warn(`onNewSession callback failed: ${String(err)}`);
2450
2482
  }
2451
2483
  });
2452
2484
  ws.on("recovery.overflow", () => {
2453
- this.opts.log?.warn(`parall[${this.opts.accountId}]: recovery.overflow \u2014 triggering full catch-up`);
2454
- this.catchUpFromDispatch().catch((err) => this.opts.log?.warn(`parall[${this.opts.accountId}]: overflow catch-up failed: ${String(err)}`));
2485
+ this.opts.log?.warn(`recovery.overflow \u2014 triggering full catch-up`);
2486
+ this.catchUpFromDispatch().catch((err) => this.opts.log?.warn(`overflow catch-up failed: ${String(err)}`));
2455
2487
  });
2456
2488
  ws.on("task.assigned", async (data) => {
2457
2489
  if (data.assignee_id !== this.opts.agentUserId)
@@ -2465,7 +2497,7 @@ var ParallAgentGateway = class {
2465
2497
  });
2466
2498
  }
2467
2499
  } catch (err) {
2468
- this.opts.log?.error(`parall[${this.opts.accountId}]: task dispatch failed for ${data.id}: ${String(err)}`);
2500
+ this.opts.log?.error(`task dispatch failed for ${data.id}: ${String(err)}`);
2469
2501
  }
2470
2502
  });
2471
2503
  ws.on("dispatch.new", async (data) => {
@@ -2479,7 +2511,7 @@ var ParallAgentGateway = class {
2479
2511
  });
2480
2512
  }
2481
2513
  } catch (err) {
2482
- this.opts.log?.error(`parall[${this.opts.accountId}]: task comment dispatch failed for ${data.source_id}: ${String(err)}`);
2514
+ this.opts.log?.error(`task comment dispatch failed for ${data.source_id}: ${String(err)}`);
2483
2515
  }
2484
2516
  } else if (data.event_type === "task_update") {
2485
2517
  if (!data.task_id)
@@ -2491,7 +2523,7 @@ var ParallAgentGateway = class {
2491
2523
  });
2492
2524
  }
2493
2525
  } catch (err) {
2494
- this.opts.log?.error(`parall[${this.opts.accountId}]: task update dispatch failed for ${data.task_id}: ${String(err)}`);
2526
+ this.opts.log?.error(`task update dispatch failed for ${data.task_id}: ${String(err)}`);
2495
2527
  }
2496
2528
  } else if (data.event_type === "schedule.fire") {
2497
2529
  if (!data.source_id)
@@ -2503,7 +2535,7 @@ var ParallAgentGateway = class {
2503
2535
  });
2504
2536
  }
2505
2537
  } catch (err) {
2506
- this.opts.log?.error(`parall[${this.opts.accountId}]: schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
2538
+ this.opts.log?.error(`schedule fire dispatch failed for ${data.source_id}: ${String(err)}`);
2507
2539
  }
2508
2540
  } else if (data.event_type === "approval_decided") {
2509
2541
  if (!data.source_id)
@@ -2515,13 +2547,13 @@ var ParallAgentGateway = class {
2515
2547
  });
2516
2548
  }
2517
2549
  } catch (err) {
2518
- this.opts.log?.error(`parall[${this.opts.accountId}]: approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
2550
+ this.opts.log?.error(`approval decided dispatch failed for ${data.source_id}: ${String(err)}`);
2519
2551
  }
2520
2552
  } else if (data.event_type !== "message" && data.event_type !== "task_assign") {
2521
- this.opts.log?.info(`parall[${this.opts.accountId}]: dispatch.new with unhandled event_type=${String(data.event_type)} (id=${data.id}) \u2014 no-op`);
2553
+ this.opts.log?.info(`dispatch.new with unhandled event_type=${String(data.event_type)} (id=${data.id}) \u2014 no-op`);
2522
2554
  }
2523
2555
  });
2524
- this.opts.log?.info(`parall[${this.opts.accountId}]: connecting to ${this.opts.connectionLabel ?? "Parall WS"}...`);
2556
+ this.opts.log?.info(`connecting to ${this.opts.connectionLabel ?? "Parall WS"}...`);
2525
2557
  await ws.connect();
2526
2558
  return new Promise((resolve3) => {
2527
2559
  abortSignal.addEventListener("abort", async () => {
@@ -2635,7 +2667,7 @@ var ParallAgentGateway = class {
2635
2667
  }
2636
2668
  });
2637
2669
  } catch (err) {
2638
- this.opts.log?.warn(`parall[${this.opts.accountId}]: failed to create input step: ${String(err)}`);
2670
+ this.opts.log?.warn(`failed to create input step: ${String(err)}`);
2639
2671
  }
2640
2672
  }
2641
2673
  async createRuntimeStep(sessionId, event, runtimeEvent, stepIdFilePath, contextFilePath) {
@@ -2713,12 +2745,12 @@ var ParallAgentGateway = class {
2713
2745
  target_type: target.target_type,
2714
2746
  target_id: target.target_id,
2715
2747
  content: { text: runtimeEvent.message, suppressed: false },
2716
- projection: true
2748
+ projection: false
2717
2749
  });
2718
2750
  break;
2719
2751
  }
2720
2752
  } catch (err) {
2721
- this.opts.log?.warn(`parall[${this.opts.accountId}]: failed to create ${runtimeEvent.type} step: ${String(err)}`);
2753
+ this.opts.log?.warn(`failed to create ${runtimeEvent.type} step: ${String(err)}`);
2722
2754
  }
2723
2755
  }
2724
2756
  writeContextFile(filePath, ctx) {
@@ -2726,7 +2758,7 @@ var ParallAgentGateway = class {
2726
2758
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
2727
2759
  fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
2728
2760
  } catch (err) {
2729
- this.opts.log?.warn(`parall[${this.opts.accountId}]: failed to write context file ${filePath}: ${String(err)}`);
2761
+ this.opts.log?.warn(`failed to write context file ${filePath}: ${String(err)}`);
2730
2762
  }
2731
2763
  }
2732
2764
  updateContextFileStepId(filePath, stepId) {
@@ -2736,7 +2768,7 @@ var ParallAgentGateway = class {
2736
2768
  ctx.step_id = stepId;
2737
2769
  fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
2738
2770
  } catch (err) {
2739
- this.opts.log?.warn(`parall[${this.opts.accountId}]: failed to update context file step_id ${filePath}: ${String(err)}`);
2771
+ this.opts.log?.warn(`failed to update context file step_id ${filePath}: ${String(err)}`);
2740
2772
  }
2741
2773
  }
2742
2774
  updateContextFileSessionId(filePath, sessionId) {
@@ -2746,7 +2778,7 @@ var ParallAgentGateway = class {
2746
2778
  ctx.session_id = sessionId;
2747
2779
  fs.writeFileSync(filePath, JSON.stringify(ctx), "utf8");
2748
2780
  } catch (err) {
2749
- this.opts.log?.warn(`parall[${this.opts.accountId}]: failed to update context file session_id ${filePath}: ${String(err)}`);
2781
+ this.opts.log?.warn(`failed to update context file session_id ${filePath}: ${String(err)}`);
2750
2782
  }
2751
2783
  }
2752
2784
  /** @deprecated Use writeContextFile / updateContextFileStepId. */
@@ -2755,7 +2787,7 @@ var ParallAgentGateway = class {
2755
2787
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
2756
2788
  fs.writeFileSync(filePath, stepId, "utf8");
2757
2789
  } catch (err) {
2758
- this.opts.log?.warn(`parall[${this.opts.accountId}]: failed to write step id file ${filePath}: ${String(err)}`);
2790
+ this.opts.log?.warn(`failed to write step id file ${filePath}: ${String(err)}`);
2759
2791
  }
2760
2792
  }
2761
2793
  /** @deprecated Use writeContextFile / updateContextFileStepId. */
@@ -2812,9 +2844,13 @@ var ParallAgentGateway = class {
2812
2844
  // catch-up on the replacement pod — otherwise we silently drop work.
2813
2845
  async runDispatch(event, sessionKey, bodyForAgent, earlierEvents = [], captureText) {
2814
2846
  if (this.shuttingDown) {
2815
- this.opts.log?.info(`parall[${this.opts.accountId}]: skipping dispatch for ${event.messageId} (shutting down) \u2014 leaving unacked for catch-up on replacement pod`);
2847
+ this.opts.log?.info(`skipping dispatch for ${event.messageId} (shutting down) \u2014 leaving unacked for catch-up on replacement pod`);
2816
2848
  return false;
2817
2849
  }
2850
+ if (this.pendingRestartNotification) {
2851
+ bodyForAgent = this.pendingRestartNotification + "\n\n---\n\n" + bodyForAgent;
2852
+ this.pendingRestartNotification = null;
2853
+ }
2818
2854
  setSessionChatId(sessionKey, event.targetId);
2819
2855
  setSessionMessageId(sessionKey, event.messageId);
2820
2856
  setDispatchMessageId(sessionKey, event.messageId);
@@ -2944,7 +2980,7 @@ var ParallAgentGateway = class {
2944
2980
  item.resolve(true);
2945
2981
  }
2946
2982
  } catch (err) {
2947
- this.opts.log?.error(`parall[${this.opts.accountId}]: fork dispatch failed for ${last.messageId}: ${String(err)}`);
2983
+ this.opts.log?.error(`fork dispatch failed for ${last.messageId}: ${String(err)}`);
2948
2984
  for (const item of items) {
2949
2985
  item.resolve(false);
2950
2986
  }
@@ -2962,7 +2998,7 @@ var ParallAgentGateway = class {
2962
2998
  try {
2963
2999
  historyPath = this.opts.dispatchAdapter.getSessionHistoryPath?.(fork.fork.sessionKey);
2964
3000
  } catch (err) {
2965
- this.opts.log?.warn?.(`parall[${this.opts.accountId}]: failed to resolve fork history path: ${String(err)}`);
3001
+ this.opts.log?.warn?.(`failed to resolve fork history path: ${String(err)}`);
2966
3002
  }
2967
3003
  this.dispatchState.pendingForkResults.push({
2968
3004
  forkSessionKey: fork.fork.sessionKey,
@@ -3013,7 +3049,7 @@ var ParallAgentGateway = class {
3013
3049
  try {
3014
3050
  while (this.dispatchState.mainBuffer.length > 0) {
3015
3051
  if (this.shuttingDown) {
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`);
3052
+ this.opts.log?.info(`drainMainBuffer halted (shutting down) \u2014 ${this.dispatchState.mainBuffer.length} buffered, ${this.dispatchState.pendingForkResults.length} pending fork results left for catch-up`);
3017
3053
  break;
3018
3054
  }
3019
3055
  const targetId = this.dispatchState.mainBuffer[0].targetId;
@@ -3079,7 +3115,7 @@ var ParallAgentGateway = class {
3079
3115
  this.dispatchState.mainBuffer.push(event);
3080
3116
  if (this.dispatchState.mainCurrentTargetId === event.targetId && await this.opts.dispatchAdapter.enqueueDuringDispatch?.(this.opts.runtimeKey, buildEventBody(event))) {
3081
3117
  this.startInjectedTyping(event);
3082
- this.opts.log?.info(`parall[${this.opts.accountId}]: steer injected for ${event.messageId} (will drain for bookkeeping)`);
3118
+ this.opts.log?.info(`steer injected for ${event.messageId} (will drain for bookkeeping)`);
3083
3119
  }
3084
3120
  if (!this.dispatchState.mainDispatching && !this.draining && this.dispatchState.mainBuffer.length > 0) {
3085
3121
  this.dispatchState.mainDispatching = true;
@@ -3108,7 +3144,7 @@ var ParallAgentGateway = class {
3108
3144
  preDispatchBranchPoint: this.dispatchState.mainPreDispatchBranchPoint
3109
3145
  });
3110
3146
  if (!fork) {
3111
- this.opts.log?.warn(`parall[${this.opts.accountId}]: fork failed, buffering event for main session`);
3147
+ this.opts.log?.warn(`fork failed, buffering event for main session`);
3112
3148
  this.dispatchState.mainBuffer.push(event);
3113
3149
  return false;
3114
3150
  }
@@ -3124,7 +3160,7 @@ var ParallAgentGateway = class {
3124
3160
  activeFork.queue.push({ event, resolve: resolve3 });
3125
3161
  });
3126
3162
  this.runForkDrainLoop(activeFork).catch((err) => {
3127
- this.opts.log?.error(`parall[${this.opts.accountId}]: fork drain loop error: ${String(err)}`);
3163
+ this.opts.log?.error(`fork drain loop error: ${String(err)}`);
3128
3164
  });
3129
3165
  return firstEventPromise;
3130
3166
  }
@@ -3144,7 +3180,7 @@ var ParallAgentGateway = class {
3144
3180
  this.chatInfoMap.set(chatId, chatInfo);
3145
3181
  return chatInfo;
3146
3182
  } catch (err) {
3147
- this.opts.log?.warn(`parall[${this.opts.accountId}]: failed to resolve chat ${chatId}: ${String(err)}`);
3183
+ this.opts.log?.warn(`failed to resolve chat ${chatId}: ${String(err)}`);
3148
3184
  return null;
3149
3185
  }
3150
3186
  }
@@ -3217,7 +3253,7 @@ var ParallAgentGateway = class {
3217
3253
  this.dispatchedMessages.delete(data.id);
3218
3254
  }
3219
3255
  } catch (err) {
3220
- this.opts.log?.error(`parall[${this.opts.accountId}]: event dispatch failed for ${data.id}: ${String(err)}`);
3256
+ this.opts.log?.error(`event dispatch failed for ${data.id}: ${String(err)}`);
3221
3257
  this.dispatchedMessages.delete(data.id);
3222
3258
  }
3223
3259
  }
@@ -3226,11 +3262,11 @@ var ParallAgentGateway = class {
3226
3262
  return false;
3227
3263
  const dedupeKey = `${task.id}:${task.updated_at}`;
3228
3264
  if (this.dispatchedTasks.has(dedupeKey)) {
3229
- this.opts.log?.info(`parall[${this.opts.accountId}]: skipping already-dispatched task ${task.identifier ?? task.id}`);
3265
+ this.opts.log?.info(`skipping already-dispatched task ${task.identifier ?? task.id}`);
3230
3266
  return false;
3231
3267
  }
3232
3268
  this.dispatchedTasks.add(dedupeKey);
3233
- this.opts.log?.info(`parall[${this.opts.accountId}]: task assigned: ${task.identifier ?? task.id} "${task.title}"`);
3269
+ this.opts.log?.info(`task assigned: ${task.identifier ?? task.id} "${task.title}"`);
3234
3270
  const parts = [`Title: ${task.title}`];
3235
3271
  parts.push(`Status: ${task.status}`, `Priority: ${task.priority}`);
3236
3272
  if (task.project_id)
@@ -3271,7 +3307,7 @@ var ParallAgentGateway = class {
3271
3307
  const isAssignee = task.assignee_id === this.opts.agentUserId;
3272
3308
  const isCreatorUpdate = opts.allowCreator === true && task.creator_id === this.opts.agentUserId;
3273
3309
  if (!isAssignee && !isCreatorUpdate) {
3274
- this.opts.log?.info(`parall[${this.opts.accountId}]: skipping stale task dispatch ${ackSourceId ?? taskId} \u2014 assigned to ${task.assignee_id}, creator ${task.creator_id}`);
3310
+ this.opts.log?.info(`skipping stale task dispatch ${ackSourceId ?? taskId} \u2014 assigned to ${task.assignee_id}, creator ${task.creator_id}`);
3275
3311
  return true;
3276
3312
  }
3277
3313
  return this.handleTaskAssignment(task, ackSourceId);
@@ -3289,7 +3325,7 @@ var ParallAgentGateway = class {
3289
3325
  } catch (err) {
3290
3326
  const status = err?.status;
3291
3327
  if (status === 404) {
3292
- this.opts.log?.info(`parall[${this.opts.accountId}]: skipping deleted comment ${commentId}, acking stale dispatch`);
3328
+ this.opts.log?.info(`skipping deleted comment ${commentId}, acking stale dispatch`);
3293
3329
  this.dispatchedTasks.delete(dedupeKey);
3294
3330
  return true;
3295
3331
  }
@@ -3301,7 +3337,7 @@ var ParallAgentGateway = class {
3301
3337
  return true;
3302
3338
  }
3303
3339
  if (comment.hints?.no_reply) {
3304
- this.opts.log?.info(`parall[${this.opts.accountId}]: skipping no_reply task comment ${commentId}, acking stale dispatch`);
3340
+ this.opts.log?.info(`skipping no_reply task comment ${commentId}, acking stale dispatch`);
3305
3341
  this.dispatchedTasks.delete(dedupeKey);
3306
3342
  return true;
3307
3343
  }
@@ -3311,7 +3347,7 @@ var ParallAgentGateway = class {
3311
3347
  } catch {
3312
3348
  }
3313
3349
  const taskLabel = task ? `${task.identifier ?? task.id} "${task.title}"` : taskId;
3314
- this.opts.log?.info(`parall[${this.opts.accountId}]: task comment on ${taskLabel} by ${actorId ?? "unknown"}`);
3350
+ this.opts.log?.info(`task comment on ${taskLabel} by ${actorId ?? "unknown"}`);
3315
3351
  const parts = [];
3316
3352
  if (task) {
3317
3353
  parts.push(`Task: ${task.title} (prll://${task.id})`);
@@ -3361,10 +3397,10 @@ var ParallAgentGateway = class {
3361
3397
  } catch (err) {
3362
3398
  const status = err?.status;
3363
3399
  if (status === 404) {
3364
- this.opts.log?.warn(`parall[${this.opts.accountId}]: schedule run ${runId} not accessible (404), acking stale dispatch`);
3400
+ this.opts.log?.warn(`schedule run ${runId} not accessible (404), acking stale dispatch`);
3365
3401
  return true;
3366
3402
  }
3367
- this.opts.log?.warn(`parall[${this.opts.accountId}]: schedule run fetch failed for ${runId}, leaving pending: ${String(err)}`);
3403
+ this.opts.log?.warn(`schedule run fetch failed for ${runId}, leaving pending: ${String(err)}`);
3368
3404
  return false;
3369
3405
  }
3370
3406
  if (!run)
@@ -3378,7 +3414,7 @@ var ParallAgentGateway = class {
3378
3414
  if (this.dispatchedTasks.has(dedupeKey))
3379
3415
  return false;
3380
3416
  this.dispatchedTasks.add(dedupeKey);
3381
- this.opts.log?.info(`parall[${this.opts.accountId}]: schedule fired: ${run.id} (schedule ${run.schedule_id})`);
3417
+ this.opts.log?.info(`schedule fired: ${run.id} (schedule ${run.schedule_id})`);
3382
3418
  const event = {
3383
3419
  type: "schedule",
3384
3420
  // Route by schedule_id (not attached chat_id) so concurrent fires of
@@ -3415,10 +3451,10 @@ var ParallAgentGateway = class {
3415
3451
  } catch (err) {
3416
3452
  const status = err?.status;
3417
3453
  if (status === 404 || status === 403) {
3418
- this.opts.log?.warn(`parall[${this.opts.accountId}]: approval ${approvalId} not accessible (${status}), acking stale dispatch`);
3454
+ this.opts.log?.warn(`approval ${approvalId} not accessible (${status}), acking stale dispatch`);
3419
3455
  return true;
3420
3456
  }
3421
- this.opts.log?.warn(`parall[${this.opts.accountId}]: approval fetch failed for ${approvalId}, leaving pending: ${String(err)}`);
3457
+ this.opts.log?.warn(`approval fetch failed for ${approvalId}, leaving pending: ${String(err)}`);
3422
3458
  return false;
3423
3459
  }
3424
3460
  if (!approval)
@@ -3429,7 +3465,7 @@ var ParallAgentGateway = class {
3429
3465
  if (this.dispatchedTasks.has(dedupeKey))
3430
3466
  return false;
3431
3467
  this.dispatchedTasks.add(dedupeKey);
3432
- this.opts.log?.info(`parall[${this.opts.accountId}]: approval decided: ${approval.id} (${approval.status})`);
3468
+ this.opts.log?.info(`approval decided: ${approval.id} (${approval.status})`);
3433
3469
  const statusLabel = approval.status === "approved" ? "Approved" : "Rejected";
3434
3470
  const execInfo = approval.execution_status ? ` | execution: ${approval.execution_status}` : "";
3435
3471
  const body = `${statusLabel}: ${approval.title}${execInfo}`;
@@ -3479,14 +3515,14 @@ var ParallAgentGateway = class {
3479
3515
  try {
3480
3516
  dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id);
3481
3517
  } catch (err) {
3482
- this.opts.log?.warn(`parall[${this.opts.accountId}]: catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
3518
+ this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
3483
3519
  continue;
3484
3520
  }
3485
3521
  } else if (item.event_type === "task_update" && item.task_id) {
3486
3522
  try {
3487
3523
  dispatched = await this.handleTaskDispatch(item.task_id, item.source_id ?? item.task_id, { allowCreator: true });
3488
3524
  } catch (err) {
3489
- this.opts.log?.warn(`parall[${this.opts.accountId}]: catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
3525
+ this.opts.log?.warn(`catch-up task fetch failed for ${item.task_id}, leaving pending: ${String(err)}`);
3490
3526
  continue;
3491
3527
  }
3492
3528
  } else if (item.event_type === "task_comment" && item.source_id && item.task_id) {
@@ -3508,7 +3544,7 @@ var ParallAgentGateway = class {
3508
3544
  msg = null;
3509
3545
  } else {
3510
3546
  msgFetchFailed = true;
3511
- this.opts.log?.warn(`parall[${this.opts.accountId}]: catch-up message fetch failed for ${item.source_id}, leaving pending: ${String(err)}`);
3547
+ this.opts.log?.warn(`catch-up message fetch failed for ${item.source_id}, leaving pending: ${String(err)}`);
3512
3548
  }
3513
3549
  }
3514
3550
  if (msgFetchFailed) {
@@ -3539,13 +3575,13 @@ var ParallAgentGateway = class {
3539
3575
  });
3540
3576
  }
3541
3577
  } catch (err) {
3542
- this.opts.log?.warn(`parall[${this.opts.accountId}]: catch-up dispatch ${item.id} (${item.event_type}) failed: ${String(err)}`);
3578
+ this.opts.log?.warn(`catch-up dispatch ${item.id} (${item.event_type}) failed: ${String(err)}`);
3543
3579
  }
3544
3580
  }
3545
3581
  cursor = !this.shuttingDown && page.has_more ? page.next_cursor : void 0;
3546
3582
  } while (cursor);
3547
3583
  if (processed > 0 || skippedOld > 0) {
3548
- this.opts.log?.info(`parall[${this.opts.accountId}]: dispatch catch-up: processed ${processed}, skipped ${skippedOld} old item(s)`);
3584
+ this.opts.log?.info(`dispatch catch-up: processed ${processed}, skipped ${skippedOld} old item(s)`);
3549
3585
  }
3550
3586
  }
3551
3587
  async handleHello(data) {
@@ -3554,7 +3590,7 @@ var ParallAgentGateway = class {
3554
3590
  const intervalSec = data.heartbeat_interval > 0 ? data.heartbeat_interval : 30;
3555
3591
  try {
3556
3592
  const count = await fetchAllChats(client, config.org_id, this.chatInfoMap);
3557
- log2?.info(`parall[${this.opts.accountId}]: WebSocket connected, ${count} chats cached`);
3593
+ log2?.info(`WebSocket connected, ${count} chats cached`);
3558
3594
  await this.opts.onSessionReady?.({
3559
3595
  activeSessionId: this.activeSessionId,
3560
3596
  ws: this.opts.ws,
@@ -3568,7 +3604,7 @@ var ParallAgentGateway = class {
3568
3604
  const expectedMs = intervalSec * 1e3;
3569
3605
  const drift = now - this.lastHeartbeatAt - expectedMs;
3570
3606
  if (drift > 15e3) {
3571
- log2?.warn(`parall[${this.opts.accountId}]: heartbeat drift ${drift}ms \u2014 event loop may be blocked`);
3607
+ log2?.warn(`heartbeat drift ${drift}ms \u2014 event loop may be blocked`);
3572
3608
  }
3573
3609
  this.lastHeartbeatAt = now;
3574
3610
  if (this.opts.ws.state !== "connected")
@@ -3584,10 +3620,10 @@ var ParallAgentGateway = class {
3584
3620
  const isFirstHello = !this.hadSuccessfulHello;
3585
3621
  this.hadSuccessfulHello = true;
3586
3622
  this.catchUpFromDispatch(isFirstHello).catch((err) => {
3587
- log2?.warn(`parall[${this.opts.accountId}]: dispatch catch-up failed: ${String(err)}`);
3623
+ log2?.warn(`dispatch catch-up failed: ${String(err)}`);
3588
3624
  });
3589
3625
  } catch (err) {
3590
- log2?.error(`parall[${this.opts.accountId}]: failed to fetch chats: ${String(err)}`);
3626
+ log2?.error(`failed to fetch chats: ${String(err)}`);
3591
3627
  }
3592
3628
  }
3593
3629
  // Resolves when in-flight dispatches hit 0 or the deadline elapses.
@@ -3613,12 +3649,12 @@ var ParallAgentGateway = class {
3613
3649
  async shutdown() {
3614
3650
  this.shuttingDown = true;
3615
3651
  if (this.inFlightDispatches > 0) {
3616
- this.opts.log?.info(`parall[${this.opts.accountId}]: draining ${this.inFlightDispatches} in-flight dispatch(es), deadline ${this.SHUTDOWN_DEADLINE_MS}ms`);
3652
+ this.opts.log?.info(`draining ${this.inFlightDispatches} in-flight dispatch(es), deadline ${this.SHUTDOWN_DEADLINE_MS}ms`);
3617
3653
  await this.waitForDrain(this.SHUTDOWN_DEADLINE_MS);
3618
3654
  if (this.inFlightDispatches > 0) {
3619
- this.opts.log?.warn(`parall[${this.opts.accountId}]: drain deadline hit; ${this.inFlightDispatches} dispatch(es) still running \u2014 they will be killed by process exit`);
3655
+ this.opts.log?.warn(`drain deadline hit; ${this.inFlightDispatches} dispatch(es) still running \u2014 they will be killed by process exit`);
3620
3656
  } else {
3621
- this.opts.log?.info(`parall[${this.opts.accountId}]: drain complete`);
3657
+ this.opts.log?.info(`drain complete`);
3622
3658
  }
3623
3659
  }
3624
3660
  if (this.heartbeatTimer)
@@ -3629,7 +3665,7 @@ var ParallAgentGateway = class {
3629
3665
  this.activeDispatches.clear();
3630
3666
  await this.opts.onBeforeDisconnect?.();
3631
3667
  this.opts.ws.disconnect();
3632
- this.opts.log?.info(`parall[${this.opts.accountId}]: disconnected`);
3668
+ this.opts.log?.info(`disconnected`);
3633
3669
  }
3634
3670
  };
3635
3671
 
@@ -5149,7 +5185,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5149
5185
  const pending = this.pendingInjections.get(sessionKey) ?? 0;
5150
5186
  if (pending > 0) {
5151
5187
  this.pendingInjections.delete(sessionKey);
5152
- context.log?.info?.(`claude-agent[${context.accountId}]: consuming ${pending} steer turn(s)`);
5188
+ context.log?.info?.(`consuming ${pending} steer turn(s)`);
5153
5189
  for (let i = 0; i < pending; i++) {
5154
5190
  yield* this.consumeSteerTurn(sessionKey, context.log);
5155
5191
  }
@@ -5166,7 +5202,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5166
5202
  promptBody = prepared.body;
5167
5203
  releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
5168
5204
  } catch (err) {
5169
- context.log?.warn?.(`claude-agent[${context.accountId}]: failed to prepare local attachments: ${String(err)}`);
5205
+ context.log?.warn?.(`failed to prepare local attachments: ${String(err)}`);
5170
5206
  }
5171
5207
  try {
5172
5208
  yield* this.runTurn(sessionKey, promptBody, context.log);
@@ -5217,7 +5253,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5217
5253
  async *consumeSteerTurn(sessionKey, log2) {
5218
5254
  const state = this.processes.get(sessionKey);
5219
5255
  if (!state || state.done) {
5220
- throw new Error("claude-agent: process dead during steer consumption");
5256
+ throw new Error("process dead during steer consumption");
5221
5257
  }
5222
5258
  const groupKey = randomUUID();
5223
5259
  const parserNext = state.parser.next();
@@ -5227,7 +5263,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5227
5263
  ]);
5228
5264
  if (firstRead.kind === "timeout") {
5229
5265
  state.steerReadPending = parserNext;
5230
- log2?.info?.(`claude-agent: steer turn timeout \u2014 steer was incorporated into previous turn`);
5266
+ log2?.info?.(`steer turn timeout \u2014 steer was incorporated into previous turn`);
5231
5267
  return;
5232
5268
  }
5233
5269
  let next = firstRead.result;
@@ -5235,7 +5271,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5235
5271
  if (next.done) {
5236
5272
  state.done = true;
5237
5273
  this.processes.delete(sessionKey);
5238
- throw new Error("claude-agent: process exited while consuming steer turn");
5274
+ throw new Error("process exited while consuming steer turn");
5239
5275
  }
5240
5276
  const parsed = next.value;
5241
5277
  if (parsed.type === "session_id") {
@@ -5306,7 +5342,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5306
5342
  const detail = state.handle.stderrChunks.join("").trim();
5307
5343
  const exit = await state.handle.exitPromise.catch(() => ({ code: null, signal: null }));
5308
5344
  if (detail) {
5309
- log2?.warn?.(`claude-agent: subprocess stderr: ${detail}`);
5345
+ log2?.warn?.(`subprocess stderr: ${detail}`);
5310
5346
  }
5311
5347
  if (!sawError) {
5312
5348
  yield {
@@ -5350,7 +5386,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5350
5386
  }
5351
5387
  ensureProcess(sessionKey, log2) {
5352
5388
  if (this.shuttingDown) {
5353
- throw new Error("claude-agent: adapter shutting down, refusing new process");
5389
+ throw new Error("adapter shutting down, refusing new process");
5354
5390
  }
5355
5391
  const existing = this.processes.get(sessionKey);
5356
5392
  if (existing && !existing.done) {
@@ -5373,7 +5409,7 @@ var ClaudeCodeAdapter = class _ClaudeCodeAdapter {
5373
5409
  spawnProcess(sessionKey, log2) {
5374
5410
  const args = this.buildArgs(sessionKey);
5375
5411
  const env = buildSpawnEnv(process.env, this.opts.claudeHome, this.buildPlaceholderContext(sessionKey), { allowApiKey: this.opts.allowApiKey, effortLevel: this._effortLevel });
5376
- log2?.info(`claude-agent: spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`);
5412
+ log2?.info(`spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`);
5377
5413
  const proc = spawn(IS_WIN32 ? quoteWin32Arg(this.opts.claudeBin) : this.opts.claudeBin, IS_WIN32 ? args.map(quoteWin32Arg) : args, {
5378
5414
  cwd: this.opts.workspaceDir,
5379
5415
  env,
@@ -5628,6 +5664,13 @@ var ClaudeSessionManager = class _ClaudeSessionManager {
5628
5664
  }
5629
5665
  }
5630
5666
  }
5667
+ clearMainSession() {
5668
+ this.sessionIds.delete(this.mainSessionKey);
5669
+ try {
5670
+ fs6.unlinkSync(this.stateFilePath);
5671
+ } catch {
5672
+ }
5673
+ }
5631
5674
  restore() {
5632
5675
  try {
5633
5676
  const raw = fs6.readFileSync(this.stateFilePath, "utf8");
@@ -5673,6 +5716,7 @@ function ensureClaudeWorkspace(workspaceDir, log2, agentIdentity) {
5673
5716
 
5674
5717
  // ts/claude-agent/dist/index.js
5675
5718
  var log = createLogger("claude-agent");
5719
+ var activeLog = log;
5676
5720
  async function getAgentMeWithLegacyFallback(client, orgId) {
5677
5721
  try {
5678
5722
  return await client.getAgentMe(orgId);
@@ -5696,28 +5740,30 @@ async function main() {
5696
5740
  });
5697
5741
  const me = await getAgentMeWithLegacyFallback(client, config.orgId);
5698
5742
  const agentUserId = me.id;
5699
- ensureClaudeWorkspace(config.workspaceDir, log, {
5743
+ const agentLog = childLogger(log, agentUserId);
5744
+ activeLog = agentLog;
5745
+ ensureClaudeWorkspace(config.workspaceDir, agentLog, {
5700
5746
  userId: agentUserId,
5701
5747
  displayName: me.display_name,
5702
5748
  description: me.agent_profile?.description ?? void 0
5703
5749
  });
5704
5750
  const runtimeKey = config.runtimeKey || buildClaudeRuntimeKey(agentUserId);
5705
5751
  const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
5706
- const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, log);
5752
+ const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, agentLog);
5707
5753
  const resolvedWsUrl = resolveWsUrl(config.apiUrl, config.wsUrl, config.swimlaneName);
5708
5754
  const ws = new ParallWs({
5709
5755
  getTicket: () => client.getWsTicket(),
5710
5756
  wsUrl: resolvedWsUrl
5711
5757
  });
5712
- const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log });
5758
+ const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log: agentLog });
5713
5759
  const platformDefaults = await configMgr.fetch();
5714
5760
  let platformManaged = isPlatformManagedProfile(me.agent_profile);
5715
5761
  const resolvedModel = platformManaged ? platformDefaults.model ?? config.model : config.model;
5716
5762
  const resolvedEffort = platformManaged ? platformDefaults.thinkingEffort ?? (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || void 0) : process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || void 0;
5717
5763
  if (platformDefaults.model)
5718
- log.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
5764
+ agentLog.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
5719
5765
  if (platformDefaults.thinkingEffort)
5720
- log.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
5766
+ agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
5721
5767
  const adapter = new ClaudeCodeAdapter({
5722
5768
  claudeBin: config.claudeBin,
5723
5769
  claudeHome: config.claudeHome,
@@ -5762,7 +5808,7 @@ async function main() {
5762
5808
  claude_home: config.claudeHome
5763
5809
  },
5764
5810
  dispatchAdapter: adapter,
5765
- log,
5811
+ log: agentLog,
5766
5812
  shutdownDeadlineMs: parseShutdownDeadlineMs(process.env.PRLL_SHUTDOWN_DEADLINE_MS),
5767
5813
  contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
5768
5814
  stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
@@ -5790,14 +5836,18 @@ async function main() {
5790
5836
  // gateway's shuttingDown flag alone does not tear them down. Piggyback on
5791
5837
  // onBeforeDisconnect to close stdin and SIGTERM any survivors after
5792
5838
  // in-flight drains finish.
5793
- onBeforeDisconnect: () => adapter.shutdown()
5839
+ onBeforeDisconnect: () => adapter.shutdown(),
5840
+ onNewSession: async () => {
5841
+ sessionManager.clearMainSession();
5842
+ await adapter.shutdown();
5843
+ }
5794
5844
  });
5795
5845
  const abortController = new AbortController();
5796
5846
  const abort = () => abortController.abort();
5797
5847
  process.on("SIGINT", abort);
5798
5848
  process.on("SIGTERM", abort);
5799
5849
  try {
5800
- log.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
5850
+ agentLog.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
5801
5851
  await gateway.run(abortController.signal);
5802
5852
  } finally {
5803
5853
  process.off("SIGINT", abort);
@@ -5805,6 +5855,6 @@ async function main() {
5805
5855
  }
5806
5856
  }
5807
5857
  main().catch((err) => {
5808
- log.error(`fatal: ${String(err)}`);
5858
+ activeLog.error(`fatal: ${String(err)}`);
5809
5859
  process.exitCode = 1;
5810
5860
  });