@parall/claude-agent 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.
package/dist/dispatch.js CHANGED
@@ -92,7 +92,7 @@ export class ClaudeCodeAdapter {
92
92
  const pending = this.pendingInjections.get(sessionKey) ?? 0;
93
93
  if (pending > 0) {
94
94
  this.pendingInjections.delete(sessionKey);
95
- context.log?.info?.(`claude-agent[${context.accountId}]: consuming ${pending} steer turn(s)`);
95
+ context.log?.info?.(`consuming ${pending} steer turn(s)`);
96
96
  for (let i = 0; i < pending; i++) {
97
97
  yield* this.consumeSteerTurn(sessionKey, context.log);
98
98
  }
@@ -109,7 +109,7 @@ export class ClaudeCodeAdapter {
109
109
  releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
110
110
  }
111
111
  catch (err) {
112
- context.log?.warn?.(`claude-agent[${context.accountId}]: failed to prepare local attachments: ${String(err)}`);
112
+ context.log?.warn?.(`failed to prepare local attachments: ${String(err)}`);
113
113
  }
114
114
  try {
115
115
  yield* this.runTurn(sessionKey, promptBody, context.log);
@@ -161,7 +161,7 @@ export class ClaudeCodeAdapter {
161
161
  async *consumeSteerTurn(sessionKey, log) {
162
162
  const state = this.processes.get(sessionKey);
163
163
  if (!state || state.done) {
164
- throw new Error("claude-agent: process dead during steer consumption");
164
+ throw new Error("process dead during steer consumption");
165
165
  }
166
166
  const groupKey = randomUUID();
167
167
  const parserNext = state.parser.next();
@@ -171,7 +171,7 @@ export class ClaudeCodeAdapter {
171
171
  ]);
172
172
  if (firstRead.kind === "timeout") {
173
173
  state.steerReadPending = parserNext;
174
- log?.info?.(`claude-agent: steer turn timeout — steer was incorporated into previous turn`);
174
+ log?.info?.(`steer turn timeout — steer was incorporated into previous turn`);
175
175
  return;
176
176
  }
177
177
  let next = firstRead.result;
@@ -180,7 +180,7 @@ export class ClaudeCodeAdapter {
180
180
  if (next.done) {
181
181
  state.done = true;
182
182
  this.processes.delete(sessionKey);
183
- throw new Error("claude-agent: process exited while consuming steer turn");
183
+ throw new Error("process exited while consuming steer turn");
184
184
  }
185
185
  const parsed = next.value;
186
186
  if (parsed.type === "session_id") {
@@ -263,7 +263,7 @@ export class ClaudeCodeAdapter {
263
263
  const detail = state.handle.stderrChunks.join("").trim();
264
264
  const exit = await state.handle.exitPromise.catch(() => ({ code: null, signal: null }));
265
265
  if (detail) {
266
- log?.warn?.(`claude-agent: subprocess stderr: ${detail}`);
266
+ log?.warn?.(`subprocess stderr: ${detail}`);
267
267
  }
268
268
  if (!sawError) {
269
269
  yield {
@@ -308,7 +308,7 @@ export class ClaudeCodeAdapter {
308
308
  }
309
309
  ensureProcess(sessionKey, log) {
310
310
  if (this.shuttingDown) {
311
- throw new Error("claude-agent: adapter shutting down, refusing new process");
311
+ throw new Error("adapter shutting down, refusing new process");
312
312
  }
313
313
  const existing = this.processes.get(sessionKey);
314
314
  if (existing && !existing.done) {
@@ -333,7 +333,7 @@ export class ClaudeCodeAdapter {
333
333
  spawnProcess(sessionKey, log) {
334
334
  const args = this.buildArgs(sessionKey);
335
335
  const env = buildSpawnEnv(process.env, this.opts.claudeHome, this.buildPlaceholderContext(sessionKey), { allowApiKey: this.opts.allowApiKey, effortLevel: this._effortLevel });
336
- log?.info(`claude-agent: spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`);
336
+ log?.info(`spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`);
337
337
  const proc = spawn(IS_WIN32 ? quoteWin32Arg(this.opts.claudeBin) : this.opts.claudeBin, IS_WIN32 ? args.map(quoteWin32Arg) : args, {
338
338
  cwd: this.opts.workspaceDir,
339
339
  env,
package/dist/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import * as os from "node:os";
3
- import { ParallAgentGateway, createPlatformConfigManager, createLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
3
+ import { ParallAgentGateway, createPlatformConfigManager, createLogger, childLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
4
4
  import { ApiError, ParallClient, ParallWs } from "@parall/sdk";
5
5
  import { buildClaudeRuntimeKey, contextFilePathForSession, resolveClaudeAgentConfig, resolveWsUrl, sessionStateFilePathForRuntime, stepIdFilePathForSession, } from "./config.js";
6
6
  import { ClaudeCodeAdapter } from "./dispatch.js";
7
7
  import { ClaudeSessionManager } from "./session-manager.js";
8
8
  import { ensureClaudeWorkspace } from "./workspace.js";
9
9
  const log = createLogger("claude-agent");
10
+ let activeLog = log;
10
11
  async function getAgentMeWithLegacyFallback(client, orgId) {
11
12
  try {
12
13
  return await client.getAgentMe(orgId);
@@ -35,20 +36,22 @@ async function main() {
35
36
  });
36
37
  const me = await getAgentMeWithLegacyFallback(client, config.orgId);
37
38
  const agentUserId = me.id;
38
- ensureClaudeWorkspace(config.workspaceDir, log, {
39
+ const agentLog = childLogger(log, agentUserId);
40
+ activeLog = agentLog;
41
+ ensureClaudeWorkspace(config.workspaceDir, agentLog, {
39
42
  userId: agentUserId,
40
43
  displayName: me.display_name,
41
44
  description: me.agent_profile?.description ?? undefined,
42
45
  });
43
46
  const runtimeKey = config.runtimeKey || buildClaudeRuntimeKey(agentUserId);
44
47
  const sessionStateFilePath = sessionStateFilePathForRuntime(config.stateDir, runtimeKey);
45
- const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, log);
48
+ const sessionManager = new ClaudeSessionManager(runtimeKey, sessionStateFilePath, agentLog);
46
49
  const resolvedWsUrl = resolveWsUrl(config.apiUrl, config.wsUrl, config.swimlaneName);
47
50
  const ws = new ParallWs({
48
51
  getTicket: () => client.getWsTicket(),
49
52
  wsUrl: resolvedWsUrl,
50
53
  });
51
- const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log });
54
+ const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log: agentLog });
52
55
  const platformDefaults = await configMgr.fetch();
53
56
  let platformManaged = isPlatformManagedProfile(me.agent_profile);
54
57
  const resolvedModel = platformManaged ? (platformDefaults.model ?? config.model) : config.model;
@@ -56,9 +59,9 @@ async function main() {
56
59
  ? (platformDefaults.thinkingEffort ?? (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined))
57
60
  : (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
58
61
  if (platformDefaults.model)
59
- log.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
62
+ agentLog.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
60
63
  if (platformDefaults.thinkingEffort)
61
- log.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
64
+ agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
62
65
  const adapter = new ClaudeCodeAdapter({
63
66
  claudeBin: config.claudeBin,
64
67
  claudeHome: config.claudeHome,
@@ -103,7 +106,7 @@ async function main() {
103
106
  claude_home: config.claudeHome,
104
107
  },
105
108
  dispatchAdapter: adapter,
106
- log,
109
+ log: agentLog,
107
110
  shutdownDeadlineMs: parseShutdownDeadlineMs(process.env.PRLL_SHUTDOWN_DEADLINE_MS),
108
111
  contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
109
112
  stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
@@ -132,13 +135,17 @@ async function main() {
132
135
  // onBeforeDisconnect to close stdin and SIGTERM any survivors after
133
136
  // in-flight drains finish.
134
137
  onBeforeDisconnect: () => adapter.shutdown(),
138
+ onNewSession: async () => {
139
+ sessionManager.clearMainSession();
140
+ await adapter.shutdown();
141
+ },
135
142
  });
136
143
  const abortController = new AbortController();
137
144
  const abort = () => abortController.abort();
138
145
  process.on("SIGINT", abort);
139
146
  process.on("SIGTERM", abort);
140
147
  try {
141
- log.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
148
+ agentLog.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
142
149
  await gateway.run(abortController.signal);
143
150
  }
144
151
  finally {
@@ -147,6 +154,6 @@ async function main() {
147
154
  }
148
155
  }
149
156
  main().catch((err) => {
150
- log.error(`fatal: ${String(err)}`);
157
+ activeLog.error(`fatal: ${String(err)}`);
151
158
  process.exitCode = 1;
152
159
  });
@@ -37,6 +37,7 @@ export declare class ClaudeSessionManager {
37
37
  */
38
38
  private raceWithTimeout;
39
39
  private closeHandle;
40
+ clearMainSession(): void;
40
41
  private restore;
41
42
  private persist;
42
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5D,KAAK,0BAA0B,GAAG;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,8BAA8B,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC7E,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,qBAAa,oBAAoB;IAM7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAP1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;gBAGjD,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,0BAA0B,YAAA;IAKtD,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAU3C,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAQrD,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAYrE,WAAW,CAAC,UAAU,EAAE,MAAM;IAU9B,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI/D,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB;IAsB/D,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,mBAAmB;IAO7D,qEAAqE;IACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAE5C,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAQpB,WAAW;IAuCzB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,OAAO;CAahB"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5D,KAAK,0BAA0B,GAAG;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,8BAA8B,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC7E,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,qBAAa,oBAAoB;IAM7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAP1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA6B;IACxD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;gBAGjD,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,0BAA0B,YAAA;IAKtD,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAU3C,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAQrD,iBAAiB,CAAC,gBAAgB,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAYrE,WAAW,CAAC,UAAU,EAAE,MAAM;IAU9B,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAI/D,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB;IAsB/D,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,mBAAmB;IAO7D,qEAAqE;IACrE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAE5C,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;YAQpB,WAAW;IAuCzB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAuBvB,OAAO,CAAC,WAAW;IAqBnB,gBAAgB;IAShB,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,OAAO;CAahB"}
@@ -164,6 +164,15 @@ export class ClaudeSessionManager {
164
164
  }
165
165
  }
166
166
  }
167
+ clearMainSession() {
168
+ this.sessionIds.delete(this.mainSessionKey);
169
+ try {
170
+ fs.unlinkSync(this.stateFilePath);
171
+ }
172
+ catch {
173
+ // File may not exist.
174
+ }
175
+ }
167
176
  restore() {
168
177
  try {
169
178
  const raw = fs.readFileSync(this.stateFilePath, "utf8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/claude-agent",
3
- "version": "1.29.3",
3
+ "version": "1.30.0",
4
4
  "description": "Claude Code bridge runtime for self-hosted Parall agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -25,9 +25,9 @@
25
25
  "src"
26
26
  ],
27
27
  "dependencies": {
28
- "@parall/agent-core": "1.29.3",
29
- "@parall/cli": "1.29.3",
30
- "@parall/sdk": "1.29.3"
28
+ "@parall/agent-core": "1.30.0",
29
+ "@parall/cli": "1.30.0",
30
+ "@parall/sdk": "1.30.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/node": "^22.0.0",
package/src/dispatch.ts CHANGED
@@ -150,7 +150,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
150
150
  const pending = this.pendingInjections.get(sessionKey) ?? 0;
151
151
  if (pending > 0) {
152
152
  this.pendingInjections.delete(sessionKey);
153
- context.log?.info?.(`claude-agent[${context.accountId}]: consuming ${pending} steer turn(s)`);
153
+ context.log?.info?.(`consuming ${pending} steer turn(s)`);
154
154
  for (let i = 0; i < pending; i++) {
155
155
  yield* this.consumeSteerTurn(sessionKey, context.log);
156
156
  }
@@ -168,7 +168,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
168
168
  releasePreparedAttachments = pinLocalAttachmentPaths(prepared.attachments.images);
169
169
  } catch (err) {
170
170
  context.log?.warn?.(
171
- `claude-agent[${context.accountId}]: failed to prepare local attachments: ${String(err)}`,
171
+ `failed to prepare local attachments: ${String(err)}`,
172
172
  );
173
173
  }
174
174
 
@@ -230,7 +230,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
230
230
  ): AsyncGenerator<RuntimeEvent> {
231
231
  const state = this.processes.get(sessionKey);
232
232
  if (!state || state.done) {
233
- throw new Error("claude-agent: process dead during steer consumption");
233
+ throw new Error("process dead during steer consumption");
234
234
  }
235
235
 
236
236
  const groupKey = randomUUID();
@@ -245,7 +245,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
245
245
 
246
246
  if (firstRead.kind === "timeout") {
247
247
  state.steerReadPending = parserNext;
248
- log?.info?.(`claude-agent: steer turn timeout — steer was incorporated into previous turn`);
248
+ log?.info?.(`steer turn timeout — steer was incorporated into previous turn`);
249
249
  return;
250
250
  }
251
251
 
@@ -255,7 +255,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
255
255
  if (next.done) {
256
256
  state.done = true;
257
257
  this.processes.delete(sessionKey);
258
- throw new Error("claude-agent: process exited while consuming steer turn");
258
+ throw new Error("process exited while consuming steer turn");
259
259
  }
260
260
  const parsed = next.value;
261
261
 
@@ -334,7 +334,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
334
334
  const detail = state.handle.stderrChunks.join("").trim();
335
335
  const exit = await state.handle.exitPromise.catch(() => ({ code: null, signal: null } as const));
336
336
  if (detail) {
337
- log?.warn?.(`claude-agent: subprocess stderr: ${detail}`);
337
+ log?.warn?.(`subprocess stderr: ${detail}`);
338
338
  }
339
339
  if (!sawError) {
340
340
  yield {
@@ -387,7 +387,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
387
387
 
388
388
  private ensureProcess(sessionKey: string, log: GatewayLogger | undefined): ProcessState {
389
389
  if (this.shuttingDown) {
390
- throw new Error("claude-agent: adapter shutting down, refusing new process");
390
+ throw new Error("adapter shutting down, refusing new process");
391
391
  }
392
392
 
393
393
  const existing = this.processes.get(sessionKey);
@@ -420,7 +420,7 @@ export class ClaudeCodeAdapter implements DispatchAdapter {
420
420
  );
421
421
 
422
422
  log?.info(
423
- `claude-agent: spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`,
423
+ `spawn long-lived ${this.opts.claudeBin} (session ${sessionKey}, model=${this._model || "default"}, effort=${this._effortLevel || "default"}, mode=${this.opts.permissionMode})`,
424
424
  );
425
425
 
426
426
  const proc = spawn(
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import * as os from "node:os";
4
- import { ParallAgentGateway, createPlatformConfigManager, createLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
4
+ import { ParallAgentGateway, createPlatformConfigManager, createLogger, childLogger, isPlatformManagedProfile, parseShutdownDeadlineMs } from "@parall/agent-core";
5
5
  import { ApiError, ParallClient, ParallWs } from "@parall/sdk";
6
6
  import {
7
7
  buildClaudeRuntimeKey,
@@ -16,6 +16,7 @@ import { ClaudeSessionManager } from "./session-manager.js";
16
16
  import { ensureClaudeWorkspace } from "./workspace.js";
17
17
 
18
18
  const log = createLogger("claude-agent");
19
+ let activeLog = log;
19
20
 
20
21
  async function getAgentMeWithLegacyFallback(client: ParallClient, orgId: string) {
21
22
  try {
@@ -52,7 +53,9 @@ async function main() {
52
53
 
53
54
  const me = await getAgentMeWithLegacyFallback(client, config.orgId);
54
55
  const agentUserId = me.id;
55
- ensureClaudeWorkspace(config.workspaceDir, log, {
56
+ const agentLog = childLogger(log, agentUserId);
57
+ activeLog = agentLog;
58
+ ensureClaudeWorkspace(config.workspaceDir, agentLog, {
56
59
  userId: agentUserId,
57
60
  displayName: me.display_name,
58
61
  description: me.agent_profile?.description ?? undefined,
@@ -62,7 +65,7 @@ async function main() {
62
65
  const sessionManager = new ClaudeSessionManager(
63
66
  runtimeKey,
64
67
  sessionStateFilePath,
65
- log,
68
+ agentLog,
66
69
  );
67
70
 
68
71
  const resolvedWsUrl = resolveWsUrl(config.apiUrl, config.wsUrl, config.swimlaneName);
@@ -71,15 +74,15 @@ async function main() {
71
74
  wsUrl: resolvedWsUrl,
72
75
  });
73
76
 
74
- const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log });
77
+ const configMgr = createPlatformConfigManager({ client, stateDir: config.stateDir, runtimeType: "claude-code", log: agentLog });
75
78
  const platformDefaults = await configMgr.fetch();
76
79
  let platformManaged = isPlatformManagedProfile(me.agent_profile);
77
80
  const resolvedModel = platformManaged ? (platformDefaults.model ?? config.model) : config.model;
78
81
  const resolvedEffort = platformManaged
79
82
  ? (platformDefaults.thinkingEffort ?? (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined))
80
83
  : (process.env.CLAUDE_CODE_EFFORT_LEVEL?.trim() || undefined);
81
- if (platformDefaults.model) log.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
82
- if (platformDefaults.thinkingEffort) log.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
84
+ if (platformDefaults.model) agentLog.info(`platform config: model=${platformDefaults.model} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
85
+ if (platformDefaults.thinkingEffort) agentLog.info(`platform config: thinking_effort=${platformDefaults.thinkingEffort} (${platformManaged ? "applied" : "ignored, model_management=self"})`);
83
86
 
84
87
  const adapter = new ClaudeCodeAdapter({
85
88
  claudeBin: config.claudeBin,
@@ -126,7 +129,7 @@ async function main() {
126
129
  claude_home: config.claudeHome,
127
130
  },
128
131
  dispatchAdapter: adapter,
129
- log,
132
+ log: agentLog,
130
133
  shutdownDeadlineMs: parseShutdownDeadlineMs(process.env.PRLL_SHUTDOWN_DEADLINE_MS),
131
134
  contextFilePathForSession: (sessionKey) => contextFilePathForSession(config.stateDir, sessionKey),
132
135
  stepIdFilePathForSession: (sessionKey) => stepIdFilePathForSession(config.stateDir, sessionKey),
@@ -155,6 +158,10 @@ async function main() {
155
158
  // onBeforeDisconnect to close stdin and SIGTERM any survivors after
156
159
  // in-flight drains finish.
157
160
  onBeforeDisconnect: () => adapter.shutdown(),
161
+ onNewSession: async () => {
162
+ sessionManager.clearMainSession();
163
+ await adapter.shutdown();
164
+ },
158
165
  });
159
166
 
160
167
  const abortController = new AbortController();
@@ -163,7 +170,7 @@ async function main() {
163
170
  process.on("SIGTERM", abort);
164
171
 
165
172
  try {
166
- log.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
173
+ agentLog.info(`starting self-hosted Claude runtime for ${me.display_name} (${agentUserId})`);
167
174
  await gateway.run(abortController.signal);
168
175
  } finally {
169
176
  process.off("SIGINT", abort);
@@ -172,6 +179,6 @@ async function main() {
172
179
  }
173
180
 
174
181
  main().catch((err) => {
175
- log.error(`fatal: ${String(err)}`);
182
+ activeLog.error(`fatal: ${String(err)}`);
176
183
  process.exitCode = 1;
177
184
  });
@@ -207,6 +207,15 @@ export class ClaudeSessionManager {
207
207
  }
208
208
  }
209
209
 
210
+ clearMainSession() {
211
+ this.sessionIds.delete(this.mainSessionKey);
212
+ try {
213
+ fs.unlinkSync(this.stateFilePath);
214
+ } catch {
215
+ // File may not exist.
216
+ }
217
+ }
218
+
210
219
  private restore() {
211
220
  try {
212
221
  const raw = fs.readFileSync(this.stateFilePath, "utf8");