agent-shim 9.11.0 → 9.12.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.
package/README.md CHANGED
@@ -265,6 +265,7 @@ Issues and pull requests are welcome. Please keep the tool itself free of assump
265
265
  - [docs/rc-interception-rig.md](docs/rc-interception-rig.md): the Remote Control interception rig: bring-up, per-host TLS proof, teardown, and the manual login step.
266
266
  - [docs/rc-web-client.md](docs/rc-web-client.md): the self-hosted Remote Control web client: the page the door serves behind its control token for browser control of its sessions, how it authenticates and speaks the typed API, and how it is tested.
267
267
  - [docs/rc-agent-events.md](docs/rc-agent-events.md): the task and subagent lifecycle events a Remote Control session's read stream carries, and the keys that join them to the transcripts on disk.
268
+ - [docs/agent-transcripts.md](docs/agent-transcripts.md): how Claude Code lays out a session's subagents, forks, workflow runs, tasks, teams and jobs on disk, and which fields are always present.
268
269
 
269
270
  ## License
270
271
 
package/dist/cli.cjs CHANGED
@@ -27866,6 +27866,10 @@ function realIsProcessZombie(pid) {
27866
27866
  function realIsProcessRunning(pid) {
27867
27867
  return realIsProcessAlive(pid) && !realIsProcessZombie(pid);
27868
27868
  }
27869
+ function realIsFrontDoorSupervisor(pid) {
27870
+ const result = (0, import_node_child_process2.spawnSync)("ps", ["-o", "command=", "-p", String(pid)], { encoding: "utf8" });
27871
+ return result.status === 0 && result.stdout.split(/\s+/).includes(FRONT_DOOR_SUPERVISOR_SUBCOMMAND);
27872
+ }
27869
27873
  function expandHome(filePath) {
27870
27874
  return filePath.startsWith("~/") ? import_node_path8.default.join(import_node_os2.default.homedir(), filePath.slice(1)) : filePath;
27871
27875
  }
@@ -28068,7 +28072,7 @@ function realResolveClaudeBinary(isOwnBinary) {
28068
28072
  function realInstalledClaudeVersions() {
28069
28073
  return installedVersions(listVersionsDir(defaultVersionsDir()));
28070
28074
  }
28071
- var import_node_child_process2, import_node_crypto4, import_node_fs3, import_node_os2, import_node_path8, import_node_sea, realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, realLogPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
28075
+ var import_node_child_process2, import_node_crypto4, import_node_fs3, import_node_os2, import_node_path8, import_node_sea, realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, FRONT_DOOR_SUPERVISOR_SUBCOMMAND, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, realLogPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
28072
28076
  var init_realPorts = __esm({
28073
28077
  "src/realPorts.ts"() {
28074
28078
  "use strict";
@@ -28209,6 +28213,7 @@ var init_realPorts = __esm({
28209
28213
  }
28210
28214
  };
28211
28215
  INT32_BYTE_LENGTH = 4;
28216
+ FRONT_DOOR_SUPERVISOR_SUBCOMMAND = "__frontdoor-supervisor";
28212
28217
  realRunPort = {
28213
28218
  run(command, args) {
28214
28219
  const result = (0, import_node_child_process2.spawnSync)(command, [...args], { encoding: "utf8" });
@@ -33243,7 +33248,7 @@ var init_package = __esm({
33243
33248
  "package.json"() {
33244
33249
  package_default = {
33245
33250
  name: "agent-shim",
33246
- version: "9.11.0",
33251
+ version: "9.12.1",
33247
33252
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
33248
33253
  license: "MIT",
33249
33254
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -61034,20 +61039,34 @@ function ensureFrontDoor(params) {
61034
61039
  let replaced = false;
61035
61040
  const distrusted = /* @__PURE__ */ new Set();
61036
61041
  let lastRejection;
61042
+ const verifyWithRetry = (port) => {
61043
+ let verdict = ports.verifyListener(port);
61044
+ for (let attempt = 1; !verdict.ok && attempt < FRONTDOOR_PROBE_ATTEMPTS; attempt += 1) {
61045
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
61046
+ verdict = ports.verifyListener(port);
61047
+ }
61048
+ return verdict;
61049
+ };
61050
+ const stopAndAwaitExit = (supervisorPid, failure2) => {
61051
+ ports.stopSupervisor(supervisorPid);
61052
+ while (ports.isRunning(supervisorPid)) {
61053
+ if (ports.now() >= deadline) {
61054
+ throw new FrontDoorStartError(`${failure2}. Daemon log: ${paths.frontdoorLogPath}`);
61055
+ }
61056
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
61057
+ }
61058
+ };
61037
61059
  for (; ; ) {
61038
61060
  const state = readFrontDoorState(ports.fs, paths.frontdoorStateFile);
61039
61061
  const supervisorPid = state?.supervisorPid;
61040
61062
  if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
61041
61063
  if (state?.port !== void 0 && state.connectPort !== void 0) {
61042
- const verdict = ports.verifyListener(state.port);
61064
+ const verdict = verifyWithRetry(state.port);
61043
61065
  if (verdict.ok && !replaced && !spawned && (params.replace === true || (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL)) {
61044
- ports.stopSupervisor(supervisorPid);
61045
- while (ports.isRunning(supervisorPid)) {
61046
- if (ports.now() >= deadline) {
61047
- throw new FrontDoorStartError(`the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit. Daemon log: ${paths.frontdoorLogPath}`);
61048
- }
61049
- ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
61050
- }
61066
+ stopAndAwaitExit(
61067
+ supervisorPid,
61068
+ `the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit`
61069
+ );
61051
61070
  replaced = true;
61052
61071
  continue;
61053
61072
  }
@@ -61060,6 +61079,10 @@ function ensureFrontDoor(params) {
61060
61079
  if (spawned) {
61061
61080
  throw new FrontDoorStartError(`${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
61062
61081
  }
61082
+ if (ports.isFrontDoorSupervisor(supervisorPid)) {
61083
+ stopAndAwaitExit(supervisorPid, `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
61084
+ continue;
61085
+ }
61063
61086
  distrusted.add(supervisorPid);
61064
61087
  continue;
61065
61088
  }
@@ -61107,7 +61130,7 @@ function restartFrontDoor(params) {
61107
61130
  }
61108
61131
  return { action: "restarted", previousPid, pid };
61109
61132
  }
61110
- var import_node_crypto10, FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FrontDoorStartError;
61133
+ var import_node_crypto10, FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FRONTDOOR_PROBE_ATTEMPTS, FrontDoorStartError;
61111
61134
  var init_ensure2 = __esm({
61112
61135
  "src/frontdoor/ensure.ts"() {
61113
61136
  "use strict";
@@ -61117,6 +61140,7 @@ var init_ensure2 = __esm({
61117
61140
  init_state2();
61118
61141
  FRONTDOOR_START_TIMEOUT_MS = 3e4;
61119
61142
  FRONTDOOR_LAUNCHER_POLL_MS = 100;
61143
+ FRONTDOOR_PROBE_ATTEMPTS = 3;
61120
61144
  FrontDoorStartError = class extends CliError {
61121
61145
  constructor(message) {
61122
61146
  super(message);
@@ -61242,6 +61266,7 @@ function realEnsurePorts(paths, spawnDaemon) {
61242
61266
  now: () => Date.now(),
61243
61267
  sleep: realSleepSync,
61244
61268
  spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
61269
+ isFrontDoorSupervisor: realIsFrontDoorSupervisor,
61245
61270
  stopSupervisor: (pid) => {
61246
61271
  process.kill(pid, "SIGTERM");
61247
61272
  },
package/dist/index.cjs CHANGED
@@ -2663,7 +2663,7 @@ var init_package = __esm({
2663
2663
  "package.json"() {
2664
2664
  package_default = {
2665
2665
  name: "agent-shim",
2666
- version: "9.11.0",
2666
+ version: "9.12.1",
2667
2667
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
2668
2668
  license: "MIT",
2669
2669
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -3427,6 +3427,10 @@ function realIsProcessZombie(pid) {
3427
3427
  function realIsProcessRunning(pid) {
3428
3428
  return realIsProcessAlive(pid) && !realIsProcessZombie(pid);
3429
3429
  }
3430
+ function realIsFrontDoorSupervisor(pid) {
3431
+ const result = (0, import_node_child_process2.spawnSync)("ps", ["-o", "command=", "-p", String(pid)], { encoding: "utf8" });
3432
+ return result.status === 0 && result.stdout.split(/\s+/).includes(FRONT_DOOR_SUPERVISOR_SUBCOMMAND);
3433
+ }
3430
3434
  function expandHome2(filePath) {
3431
3435
  return filePath.startsWith("~/") ? import_node_path13.default.join(import_node_os2.default.homedir(), filePath.slice(1)) : filePath;
3432
3436
  }
@@ -3624,7 +3628,7 @@ function realResolveClaudeBinary(isOwnBinary) {
3624
3628
  function realInstalledClaudeVersions() {
3625
3629
  return installedVersions(listVersionsDir(defaultVersionsDir()));
3626
3630
  }
3627
- var import_node_child_process2, import_node_crypto8, import_node_fs2, import_node_os2, import_node_path13, import_node_sea, realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
3631
+ var import_node_child_process2, import_node_crypto8, import_node_fs2, import_node_os2, import_node_path13, import_node_sea, realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, FRONT_DOOR_SUPERVISOR_SUBCOMMAND, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
3628
3632
  var init_realPorts = __esm({
3629
3633
  "src/realPorts.ts"() {
3630
3634
  "use strict";
@@ -3765,6 +3769,7 @@ var init_realPorts = __esm({
3765
3769
  }
3766
3770
  };
3767
3771
  INT32_BYTE_LENGTH = 4;
3772
+ FRONT_DOOR_SUPERVISOR_SUBCOMMAND = "__frontdoor-supervisor";
3768
3773
  realRunPort = {
3769
3774
  run(command, args) {
3770
3775
  const result = (0, import_node_child_process2.spawnSync)(command, [...args], { encoding: "utf8" });
@@ -6166,20 +6171,34 @@ function ensureFrontDoor(params) {
6166
6171
  let replaced = false;
6167
6172
  const distrusted = /* @__PURE__ */ new Set();
6168
6173
  let lastRejection;
6174
+ const verifyWithRetry = (port) => {
6175
+ let verdict = ports.verifyListener(port);
6176
+ for (let attempt = 1; !verdict.ok && attempt < FRONTDOOR_PROBE_ATTEMPTS; attempt += 1) {
6177
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6178
+ verdict = ports.verifyListener(port);
6179
+ }
6180
+ return verdict;
6181
+ };
6182
+ const stopAndAwaitExit = (supervisorPid, failure) => {
6183
+ ports.stopSupervisor(supervisorPid);
6184
+ while (ports.isRunning(supervisorPid)) {
6185
+ if (ports.now() >= deadline) {
6186
+ throw new FrontDoorStartError(`${failure}. Daemon log: ${paths.frontdoorLogPath}`);
6187
+ }
6188
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6189
+ }
6190
+ };
6169
6191
  for (; ; ) {
6170
6192
  const state = readFrontDoorState(ports.fs, paths.frontdoorStateFile);
6171
6193
  const supervisorPid = state?.supervisorPid;
6172
6194
  if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
6173
6195
  if (state?.port !== void 0 && state.connectPort !== void 0) {
6174
- const verdict = ports.verifyListener(state.port);
6196
+ const verdict = verifyWithRetry(state.port);
6175
6197
  if (verdict.ok && !replaced && !spawned && (params.replace === true || (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL)) {
6176
- ports.stopSupervisor(supervisorPid);
6177
- while (ports.isRunning(supervisorPid)) {
6178
- if (ports.now() >= deadline) {
6179
- throw new FrontDoorStartError(`the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit. Daemon log: ${paths.frontdoorLogPath}`);
6180
- }
6181
- ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6182
- }
6198
+ stopAndAwaitExit(
6199
+ supervisorPid,
6200
+ `the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit`
6201
+ );
6183
6202
  replaced = true;
6184
6203
  continue;
6185
6204
  }
@@ -6192,6 +6211,10 @@ function ensureFrontDoor(params) {
6192
6211
  if (spawned) {
6193
6212
  throw new FrontDoorStartError(`${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
6194
6213
  }
6214
+ if (ports.isFrontDoorSupervisor(supervisorPid)) {
6215
+ stopAndAwaitExit(supervisorPid, `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
6216
+ continue;
6217
+ }
6195
6218
  distrusted.add(supervisorPid);
6196
6219
  continue;
6197
6220
  }
@@ -6222,7 +6245,7 @@ function ensureFrontDoor(params) {
6222
6245
  ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6223
6246
  }
6224
6247
  }
6225
- var import_node_crypto9, FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FrontDoorStartError;
6248
+ var import_node_crypto9, FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FRONTDOOR_PROBE_ATTEMPTS, FrontDoorStartError;
6226
6249
  var init_ensure2 = __esm({
6227
6250
  "src/frontdoor/ensure.ts"() {
6228
6251
  "use strict";
@@ -6232,6 +6255,7 @@ var init_ensure2 = __esm({
6232
6255
  init_state();
6233
6256
  FRONTDOOR_START_TIMEOUT_MS = 3e4;
6234
6257
  FRONTDOOR_LAUNCHER_POLL_MS = 100;
6258
+ FRONTDOOR_PROBE_ATTEMPTS = 3;
6235
6259
  FrontDoorStartError = class extends CliError {
6236
6260
  constructor(message) {
6237
6261
  super(message);
@@ -7418,6 +7442,7 @@ function realEnsurePorts(paths, spawnDaemon) {
7418
7442
  now: () => Date.now(),
7419
7443
  sleep: realSleepSync,
7420
7444
  spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
7445
+ isFrontDoorSupervisor: realIsFrontDoorSupervisor,
7421
7446
  stopSupervisor: (pid) => {
7422
7447
  process.kill(pid, "SIGTERM");
7423
7448
  },
package/dist/index.mjs CHANGED
@@ -2639,7 +2639,7 @@ var init_package = __esm({
2639
2639
  "package.json"() {
2640
2640
  package_default = {
2641
2641
  name: "agent-shim",
2642
- version: "9.11.0",
2642
+ version: "9.12.1",
2643
2643
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
2644
2644
  license: "MIT",
2645
2645
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -3408,6 +3408,10 @@ function realIsProcessZombie(pid) {
3408
3408
  function realIsProcessRunning(pid) {
3409
3409
  return realIsProcessAlive(pid) && !realIsProcessZombie(pid);
3410
3410
  }
3411
+ function realIsFrontDoorSupervisor(pid) {
3412
+ const result = spawnSync("ps", ["-o", "command=", "-p", String(pid)], { encoding: "utf8" });
3413
+ return result.status === 0 && result.stdout.split(/\s+/).includes(FRONT_DOOR_SUPERVISOR_SUBCOMMAND);
3414
+ }
3411
3415
  function expandHome2(filePath) {
3412
3416
  return filePath.startsWith("~/") ? path13.join(os3.homedir(), filePath.slice(1)) : filePath;
3413
3417
  }
@@ -3605,7 +3609,7 @@ function realResolveClaudeBinary(isOwnBinary) {
3605
3609
  function realInstalledClaudeVersions() {
3606
3610
  return installedVersions(listVersionsDir(defaultVersionsDir()));
3607
3611
  }
3608
- var realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
3612
+ var realFsPort, OWNER_ONLY_DIR_MODE, OWNER_ONLY_FILE_MODE, PERMISSION_BITS, realFarmFs, INT32_BYTE_LENGTH, FRONT_DOOR_SUPERVISOR_SUBCOMMAND, realRunPort, MACOS_GUI_SESSION_MANAGER, realCredentialPort, SOCKET_PERMISSION_BITS, realHeadroomSocketTrust, realSpawnPort, realProcPort, EXECUTE_BITS_MASK, WINDOWS_DEFAULT_PATHEXT;
3609
3613
  var init_realPorts = __esm({
3610
3614
  "src/realPorts.ts"() {
3611
3615
  "use strict";
@@ -3740,6 +3744,7 @@ var init_realPorts = __esm({
3740
3744
  }
3741
3745
  };
3742
3746
  INT32_BYTE_LENGTH = 4;
3747
+ FRONT_DOOR_SUPERVISOR_SUBCOMMAND = "__frontdoor-supervisor";
3743
3748
  realRunPort = {
3744
3749
  run(command, args) {
3745
3750
  const result = spawnSync(command, [...args], { encoding: "utf8" });
@@ -6140,20 +6145,34 @@ function ensureFrontDoor(params) {
6140
6145
  let replaced = false;
6141
6146
  const distrusted = /* @__PURE__ */ new Set();
6142
6147
  let lastRejection;
6148
+ const verifyWithRetry = (port) => {
6149
+ let verdict = ports.verifyListener(port);
6150
+ for (let attempt = 1; !verdict.ok && attempt < FRONTDOOR_PROBE_ATTEMPTS; attempt += 1) {
6151
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6152
+ verdict = ports.verifyListener(port);
6153
+ }
6154
+ return verdict;
6155
+ };
6156
+ const stopAndAwaitExit = (supervisorPid, failure) => {
6157
+ ports.stopSupervisor(supervisorPid);
6158
+ while (ports.isRunning(supervisorPid)) {
6159
+ if (ports.now() >= deadline) {
6160
+ throw new FrontDoorStartError(`${failure}. Daemon log: ${paths.frontdoorLogPath}`);
6161
+ }
6162
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6163
+ }
6164
+ };
6143
6165
  for (; ; ) {
6144
6166
  const state = readFrontDoorState(ports.fs, paths.frontdoorStateFile);
6145
6167
  const supervisorPid = state?.supervisorPid;
6146
6168
  if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
6147
6169
  if (state?.port !== void 0 && state.connectPort !== void 0) {
6148
- const verdict = ports.verifyListener(state.port);
6170
+ const verdict = verifyWithRetry(state.port);
6149
6171
  if (verdict.ok && !replaced && !spawned && (params.replace === true || (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL)) {
6150
- ports.stopSupervisor(supervisorPid);
6151
- while (ports.isRunning(supervisorPid)) {
6152
- if (ports.now() >= deadline) {
6153
- throw new FrontDoorStartError(`the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit. Daemon log: ${paths.frontdoorLogPath}`);
6154
- }
6155
- ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6156
- }
6172
+ stopAndAwaitExit(
6173
+ supervisorPid,
6174
+ `the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit`
6175
+ );
6157
6176
  replaced = true;
6158
6177
  continue;
6159
6178
  }
@@ -6166,6 +6185,10 @@ function ensureFrontDoor(params) {
6166
6185
  if (spawned) {
6167
6186
  throw new FrontDoorStartError(`${lastRejection}; refusing to send this session's credentials to it. Daemon log: ${paths.frontdoorLogPath}`);
6168
6187
  }
6188
+ if (ports.isFrontDoorSupervisor(supervisorPid)) {
6189
+ stopAndAwaitExit(supervisorPid, `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
6190
+ continue;
6191
+ }
6169
6192
  distrusted.add(supervisorPid);
6170
6193
  continue;
6171
6194
  }
@@ -6196,7 +6219,7 @@ function ensureFrontDoor(params) {
6196
6219
  ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
6197
6220
  }
6198
6221
  }
6199
- var FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FrontDoorStartError;
6222
+ var FRONTDOOR_START_TIMEOUT_MS, FRONTDOOR_LAUNCHER_POLL_MS, FRONTDOOR_PROBE_ATTEMPTS, FrontDoorStartError;
6200
6223
  var init_ensure2 = __esm({
6201
6224
  "src/frontdoor/ensure.ts"() {
6202
6225
  "use strict";
@@ -6205,6 +6228,7 @@ var init_ensure2 = __esm({
6205
6228
  init_state();
6206
6229
  FRONTDOOR_START_TIMEOUT_MS = 3e4;
6207
6230
  FRONTDOOR_LAUNCHER_POLL_MS = 100;
6231
+ FRONTDOOR_PROBE_ATTEMPTS = 3;
6208
6232
  FrontDoorStartError = class extends CliError {
6209
6233
  constructor(message) {
6210
6234
  super(message);
@@ -7391,6 +7415,7 @@ function realEnsurePorts(paths, spawnDaemon) {
7391
7415
  now: () => Date.now(),
7392
7416
  sleep: realSleepSync,
7393
7417
  spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
7418
+ isFrontDoorSupervisor: realIsFrontDoorSupervisor,
7394
7419
  stopSupervisor: (pid) => {
7395
7420
  process.kill(pid, "SIGTERM");
7396
7421
  },
@@ -11662,8 +11662,10 @@ interface EnsureFrontDoorPorts {
11662
11662
  readonly spawnSupervisor: (paths: LayoutPaths) => number;
11663
11663
  /** Authenticates the provider listener on `port`: a TLS handshake chaining to agent-shim's CA and a healthy answer, with no capability sent (see `probeFrontDoorSync`). */
11664
11664
  readonly verifyListener: (port: number) => ListenerVerdict;
11665
- /** Asks a running front-door supervisor to exit, without waiting for it to: the caller polls `isRunning`. Only ever called for a pid whose recorded listener has just authenticated as agent-shim's own. */
11665
+ /** Asks a running front-door supervisor to exit, without waiting for it to: the caller polls `isRunning`. Only ever called for a pid whose recorded listener has just authenticated as agent-shim's own, or whose process is agent-shim's front-door supervisor (`isFrontDoorSupervisor`). */
11666
11666
  readonly stopSupervisor: (pid: number) => void;
11667
+ /** Whether `pid` is a live agent-shim front-door supervisor process, read from the process's own command line. This is what separates a wedged door of this tool, which a replacement must retire so the two never coexist, from an unrelated process that reuses the recorded pid, which must never be signalled. */
11668
+ readonly isFrontDoorSupervisor: (pid: number) => boolean;
11667
11669
  }
11668
11670
  /**
11669
11671
  * Brings the front door up for this launch, or finds it serving, and registers this launcher pid in its session registry: the fact that keeps the door from idling out while this session lives, and the record that holds this launch's capability token. The same lock-and-poll coordination as headroom's and the old codex daemon's ensure: the exclusive-create start lock decides which of several concurrent launches spawns the one supervisor, everyone waits on state.json, and a lock whose holder died is removed and retried. Ready means state names a live supervisor and both listeners' ports, which the supervisor writes only after both have bound (and the provider listener has answered its own health probe).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-shim",
3
- "version": "9.11.0",
3
+ "version": "9.12.1",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "MIT",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",