@codexhost/cli-linux-arm64 0.6.2 → 0.7.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.
@@ -2278,7 +2278,7 @@ var require_websocket = __commonJS({
2278
2278
  var http = __require("http");
2279
2279
  var net5 = __require("net");
2280
2280
  var tls = __require("tls");
2281
- var { randomBytes: randomBytes3, createHash: createHash8 } = __require("crypto");
2281
+ var { randomBytes: randomBytes3, createHash: createHash9 } = __require("crypto");
2282
2282
  var { Duplex: Duplex2, Readable } = __require("stream");
2283
2283
  var { URL: URL2 } = __require("url");
2284
2284
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -2946,7 +2946,7 @@ var require_websocket = __commonJS({
2946
2946
  abortHandshake(websocket, socket, "Invalid Upgrade header");
2947
2947
  return;
2948
2948
  }
2949
- const digest2 = createHash8("sha1").update(key + GUID).digest("base64");
2949
+ const digest2 = createHash9("sha1").update(key + GUID).digest("base64");
2950
2950
  if (res.headers["sec-websocket-accept"] !== digest2) {
2951
2951
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2952
2952
  return;
@@ -3315,7 +3315,7 @@ var require_websocket_server = __commonJS({
3315
3315
  var EventEmitter = __require("events");
3316
3316
  var http = __require("http");
3317
3317
  var { Duplex: Duplex2 } = __require("stream");
3318
- var { createHash: createHash8 } = __require("crypto");
3318
+ var { createHash: createHash9 } = __require("crypto");
3319
3319
  var extension2 = require_extension();
3320
3320
  var PerMessageDeflate2 = require_permessage_deflate();
3321
3321
  var subprotocol2 = require_subprotocol();
@@ -3622,7 +3622,7 @@ var require_websocket_server = __commonJS({
3622
3622
  );
3623
3623
  }
3624
3624
  if (this._state > RUNNING) return abortHandshake(socket, 503);
3625
- const digest2 = createHash8("sha1").update(key + GUID).digest("base64");
3625
+ const digest2 = createHash9("sha1").update(key + GUID).digest("base64");
3626
3626
  const headers = [
3627
3627
  "HTTP/1.1 101 Switching Protocols",
3628
3628
  "Upgrade: websocket",
@@ -4267,7 +4267,7 @@ async function runDelegationCli(input) {
4267
4267
 
4268
4268
  // packages/host-runtime/src/run-host-runtime.ts
4269
4269
  import { randomBytes } from "node:crypto";
4270
- import path20 from "node:path";
4270
+ import path21 from "node:path";
4271
4271
  import { homedir } from "node:os";
4272
4272
  import { fileURLToPath as fileURLToPath2 } from "node:url";
4273
4273
 
@@ -4613,9 +4613,85 @@ function selectInstallerReleaseArtifact(release, target) {
4613
4613
  });
4614
4614
  }
4615
4615
 
4616
+ // packages/update-manager/dist/github-cli-release.js
4617
+ import { execFile } from "node:child_process";
4618
+ import path2 from "node:path";
4619
+ var GITHUB_LATEST_RELEASE_ENDPOINT = "repos/BytePioneer-AI/codex-host/releases/latest";
4620
+ var MAX_RELEASE_RESPONSE_BYTES = 1024 * 1024;
4621
+ var GITHUB_CLI_TIMEOUT_MS = 5e3;
4622
+ function defaultExecutableCandidates(environment, platform) {
4623
+ if (environment.CODEXHOST_GH_COMMAND)
4624
+ return [environment.CODEXHOST_GH_COMMAND];
4625
+ const candidates = ["gh"];
4626
+ if (platform === "darwin") {
4627
+ candidates.push("/opt/homebrew/bin/gh", "/usr/local/bin/gh");
4628
+ } else if (platform === "win32") {
4629
+ const programFiles = environment.ProgramFiles ?? environment.PROGRAMFILES;
4630
+ const localAppData = environment.LOCALAPPDATA;
4631
+ if (programFiles)
4632
+ candidates.push(path2.win32.join(programFiles, "GitHub CLI", "gh.exe"));
4633
+ if (localAppData) {
4634
+ candidates.push(path2.win32.join(localAppData, "Programs", "GitHub CLI", "gh.exe"));
4635
+ }
4636
+ } else {
4637
+ candidates.push("/usr/local/bin/gh", "/usr/bin/gh", "/snap/bin/gh");
4638
+ }
4639
+ return [...new Set(candidates.filter((candidate) => Boolean(candidate)))];
4640
+ }
4641
+ function runGitHubCli(executable2, arguments_2, options2) {
4642
+ return new Promise((resolve, reject) => {
4643
+ execFile(executable2, [...arguments_2], {
4644
+ encoding: "utf8",
4645
+ env: options2.environment,
4646
+ maxBuffer: MAX_RELEASE_RESPONSE_BYTES,
4647
+ timeout: GITHUB_CLI_TIMEOUT_MS,
4648
+ windowsHide: true,
4649
+ ...options2.signal ? { signal: options2.signal } : {}
4650
+ }, (error51, stdout) => {
4651
+ if (error51)
4652
+ reject(error51);
4653
+ else
4654
+ resolve(stdout);
4655
+ });
4656
+ });
4657
+ }
4658
+ async function fetchLatestGitHubReleaseWithGitHubCli(options2 = {}) {
4659
+ const environment = options2.environment ?? process.env;
4660
+ const platform = options2.platform ?? process.platform;
4661
+ const candidates = options2.executableCandidates ?? defaultExecutableCandidates(environment, platform);
4662
+ const run = options2.run ?? runGitHubCli;
4663
+ const arguments_2 = [
4664
+ "api",
4665
+ "--hostname",
4666
+ "github.com",
4667
+ "--method",
4668
+ "GET",
4669
+ "--header",
4670
+ "Accept: application/vnd.github+json",
4671
+ "--header",
4672
+ "X-GitHub-Api-Version: 2022-11-28",
4673
+ GITHUB_LATEST_RELEASE_ENDPOINT
4674
+ ];
4675
+ for (const executable2 of candidates) {
4676
+ options2.signal?.throwIfAborted();
4677
+ try {
4678
+ return parseLatestGitHubRelease(JSON.parse(await run(executable2, arguments_2, {
4679
+ environment,
4680
+ ...options2.signal ? { signal: options2.signal } : {}
4681
+ })));
4682
+ } catch (error51) {
4683
+ options2.signal?.throwIfAborted();
4684
+ const code = error51?.code;
4685
+ if (code !== "ENOENT" && code !== "EACCES")
4686
+ return null;
4687
+ }
4688
+ }
4689
+ return null;
4690
+ }
4691
+
4616
4692
  // packages/update-manager/dist/operation-state.js
4617
4693
  import { lstat as lstat2, mkdir, open, readFile as readFile2, readdir, rm, writeFile } from "node:fs/promises";
4618
- import path2 from "node:path";
4694
+ import path3 from "node:path";
4619
4695
  var LOCK_FILE = "active-update-v1.lock";
4620
4696
  var STATUS_FILE = "status-v1.json";
4621
4697
  var TERMINAL_PHASES = /* @__PURE__ */ new Set(["succeeded", "failed"]);
@@ -4630,12 +4706,12 @@ async function regularFile(filePath) {
4630
4706
  }
4631
4707
  }
4632
4708
  async function isUpdateOperationActive(stateDirectory) {
4633
- if (!path2.isAbsolute(stateDirectory))
4709
+ if (!path3.isAbsolute(stateDirectory))
4634
4710
  throw new Error("update state directory must be absolute");
4635
- return regularFile(path2.join(stateDirectory, LOCK_FILE));
4711
+ return regularFile(path3.join(stateDirectory, LOCK_FILE));
4636
4712
  }
4637
4713
  async function discoverLatestUpdateStatus(stateDirectory) {
4638
- if (!path2.isAbsolute(stateDirectory))
4714
+ if (!path3.isAbsolute(stateDirectory))
4639
4715
  throw new Error("update state directory must be absolute");
4640
4716
  let entries;
4641
4717
  try {
@@ -4649,7 +4725,7 @@ async function discoverLatestUpdateStatus(stateDirectory) {
4649
4725
  for (const entry of entries) {
4650
4726
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
4651
4727
  continue;
4652
- const statusPath = path2.join(stateDirectory, entry.name, STATUS_FILE);
4728
+ const statusPath = path3.join(stateDirectory, entry.name, STATUS_FILE);
4653
4729
  if (!await regularFile(statusPath))
4654
4730
  continue;
4655
4731
  try {
@@ -4677,8 +4753,8 @@ async function cleanupTerminalUpdateState(stateDirectory, options2 = {}) {
4677
4753
  for (const entry of entries) {
4678
4754
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
4679
4755
  continue;
4680
- const directory = path2.join(stateDirectory, entry.name);
4681
- const statusPath = path2.join(directory, STATUS_FILE);
4756
+ const directory = path3.join(stateDirectory, entry.name);
4757
+ const statusPath = path3.join(directory, STATUS_FILE);
4682
4758
  try {
4683
4759
  const status = parseUpdateStatus(JSON.parse(await readFile2(statusPath, "utf8")));
4684
4760
  if (TERMINAL_PHASES.has(status.phase) && now - status.updatedAt > retentionSeconds) {
@@ -4689,10 +4765,10 @@ async function cleanupTerminalUpdateState(stateDirectory, options2 = {}) {
4689
4765
  }
4690
4766
  }
4691
4767
  async function acquireUpdateOperationLock(stateDirectory) {
4692
- if (!path2.isAbsolute(stateDirectory))
4768
+ if (!path3.isAbsolute(stateDirectory))
4693
4769
  throw new Error("update state directory must be absolute");
4694
4770
  await mkdir(stateDirectory, { recursive: true, mode: 448 });
4695
- const lockPath = path2.join(stateDirectory, LOCK_FILE);
4771
+ const lockPath = path3.join(stateDirectory, LOCK_FILE);
4696
4772
  let handle;
4697
4773
  try {
4698
4774
  handle = await open(lockPath, "wx", 384);
@@ -4711,9 +4787,9 @@ async function acquireUpdateOperationLock(stateDirectory) {
4711
4787
  async setStatusPath(statusPath) {
4712
4788
  if (released)
4713
4789
  throw new Error("update operation lock is released");
4714
- if (!path2.isAbsolute(statusPath))
4790
+ if (!path3.isAbsolute(statusPath))
4715
4791
  throw new Error("update status path must be absolute");
4716
- await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path2.normalize(statusPath) })}
4792
+ await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path3.normalize(statusPath) })}
4717
4793
  `, { encoding: "utf8", mode: 384 });
4718
4794
  },
4719
4795
  async release() {
@@ -4735,7 +4811,7 @@ function processIsAlive(processId) {
4735
4811
  }
4736
4812
  }
4737
4813
  async function recoverUpdateOperationLock(stateDirectory) {
4738
- const lockPath = path2.join(stateDirectory, LOCK_FILE);
4814
+ const lockPath = path3.join(stateDirectory, LOCK_FILE);
4739
4815
  if (!await regularFile(lockPath))
4740
4816
  return;
4741
4817
  let ownerPid;
@@ -4747,7 +4823,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
4747
4823
  } catch {
4748
4824
  return;
4749
4825
  }
4750
- if (typeof statusPath !== "string" || !path2.isAbsolute(statusPath))
4826
+ if (typeof statusPath !== "string" || !path3.isAbsolute(statusPath))
4751
4827
  return;
4752
4828
  try {
4753
4829
  const status = parseUpdateStatus(JSON.parse(await readFile2(statusPath, "utf8")));
@@ -4762,7 +4838,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
4762
4838
  import { spawn } from "node:child_process";
4763
4839
  import { randomUUID } from "node:crypto";
4764
4840
  import { chmod, copyFile, lstat as lstat4, mkdir as mkdir2, readFile as readFile3, rename, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
4765
- import path3 from "node:path";
4841
+ import path4 from "node:path";
4766
4842
 
4767
4843
  // packages/update-manager/dist/artifact.js
4768
4844
  import { createHash } from "node:crypto";
@@ -4883,9 +4959,9 @@ async function replaceStatusFile(temporaryPath, statusPath) {
4883
4959
  }
4884
4960
  }
4885
4961
  function requireAbsolutePath(value2, label) {
4886
- if (!path3.isAbsolute(value2))
4962
+ if (!path4.isAbsolute(value2))
4887
4963
  throw new Error(`${label} must be an absolute path`);
4888
- return path3.normalize(value2);
4964
+ return path4.normalize(value2);
4889
4965
  }
4890
4966
  async function requireRegularFile(value2, label) {
4891
4967
  const filePath = requireAbsolutePath(value2, label);
@@ -4928,7 +5004,7 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
4928
5004
  const now = dependencies2.now ?? Date.now;
4929
5005
  const preparedRequests = /* @__PURE__ */ new Set();
4930
5006
  async function writeStatusSnapshot(statusPath, status) {
4931
- const temporaryPath = path3.join(path3.dirname(statusPath), `.update-status-${randomId()}.tmp`);
5007
+ const temporaryPath = path4.join(path4.dirname(statusPath), `.update-status-${randomId()}.tmp`);
4932
5008
  try {
4933
5009
  await writeFile2(temporaryPath, `${JSON.stringify(status)}
4934
5010
  `, {
@@ -4988,15 +5064,15 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
4988
5064
  const updaterExecutable = await requireRegularFile(options2.updaterExecutable, "Updater executable");
4989
5065
  const stateDirectory = requireAbsolutePath(options2.stateDirectory, "update state directory");
4990
5066
  await mkdir2(stateDirectory, { recursive: true, mode: 448 });
4991
- const workDirectory = path3.join(stateDirectory, `update-${version2}-${randomId()}`);
5067
+ const workDirectory = path4.join(stateDirectory, `update-${version2}-${randomId()}`);
4992
5068
  await mkdir2(workDirectory, { recursive: false, mode: 448 });
4993
5069
  const executableSuffix = platform === "win32" ? ".exe" : "";
4994
- const helperPath = path3.join(workDirectory, `codexhost-updater${executableSuffix}`);
5070
+ const helperPath = path4.join(workDirectory, `codexhost-updater${executableSuffix}`);
4995
5071
  await copyFile(updaterExecutable, helperPath);
4996
5072
  if (platform !== "win32")
4997
5073
  await chmod(helperPath, 448);
4998
- const requestPath = path3.join(workDirectory, "request-v1.json");
4999
- const statusPath = path3.join(workDirectory, "status-v1.json");
5074
+ const requestPath = path4.join(workDirectory, "request-v1.json");
5075
+ const statusPath = path4.join(workDirectory, "status-v1.json");
5000
5076
  await writePrivateJson(statusPath, preparedStatus(version2, installation, now()));
5001
5077
  await options2.onPrepared?.({ version: version2, installation, statusPath });
5002
5078
  return {
@@ -5012,8 +5088,8 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
5012
5088
  }
5013
5089
  async function prepareArtifact(common, installation, sourceValue, fileName) {
5014
5090
  const source = validateArtifact(sourceValue);
5015
- const temporaryPath = path3.join(common.workDirectory, `.${fileName}.download`);
5016
- const artifactPath = path3.join(common.workDirectory, fileName);
5091
+ const temporaryPath = path4.join(common.workDirectory, `.${fileName}.download`);
5092
+ const artifactPath = path4.join(common.workDirectory, fileName);
5017
5093
  const progress = progressReporter(common.statusPath, common.version, installation, source.size);
5018
5094
  try {
5019
5095
  const result = await download(source, temporaryPath, progress.update);
@@ -5087,7 +5163,7 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
5087
5163
  throw new Error("macOS DMG updates require macOS");
5088
5164
  const common = await prepareCommon(options2, "macos-dmg");
5089
5165
  const appPath = requireAbsolutePath(options2.appPath, "macOS application path");
5090
- if (path3.extname(appPath) !== ".app") {
5166
+ if (path4.extname(appPath) !== ".app") {
5091
5167
  throw new Error("macOS application path must end in .app");
5092
5168
  }
5093
5169
  const artifact = await prepareArtifact(common, "macos-dmg", options2.artifact, "update.dmg");
@@ -5886,10 +5962,10 @@ function mergeDefs(...defs) {
5886
5962
  function cloneDef(schema) {
5887
5963
  return mergeDefs(schema._zod.def);
5888
5964
  }
5889
- function getElementAtPath(obj, path25) {
5890
- if (!path25)
5965
+ function getElementAtPath(obj, path26) {
5966
+ if (!path26)
5891
5967
  return obj;
5892
- return path25.reduce((acc, key) => acc?.[key], obj);
5968
+ return path26.reduce((acc, key) => acc?.[key], obj);
5893
5969
  }
5894
5970
  function promiseAllObject(promisesObj) {
5895
5971
  const keys = Object.keys(promisesObj);
@@ -6298,11 +6374,11 @@ function explicitlyAborted(x, startIndex = 0) {
6298
6374
  }
6299
6375
  return false;
6300
6376
  }
6301
- function prefixIssues(path25, issues) {
6377
+ function prefixIssues(path26, issues) {
6302
6378
  return issues.map((iss) => {
6303
6379
  var _a3;
6304
6380
  (_a3 = iss).path ?? (_a3.path = []);
6305
- iss.path.unshift(path25);
6381
+ iss.path.unshift(path26);
6306
6382
  return iss;
6307
6383
  });
6308
6384
  }
@@ -6449,16 +6525,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
6449
6525
  }
6450
6526
  function formatError(error51, mapper = (issue2) => issue2.message) {
6451
6527
  const fieldErrors = { _errors: [] };
6452
- const processError = (error52, path25 = []) => {
6528
+ const processError = (error52, path26 = []) => {
6453
6529
  for (const issue2 of error52.issues) {
6454
6530
  if (issue2.code === "invalid_union" && issue2.errors.length) {
6455
- issue2.errors.map((issues) => processError({ issues }, [...path25, ...issue2.path]));
6531
+ issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
6456
6532
  } else if (issue2.code === "invalid_key") {
6457
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6533
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6458
6534
  } else if (issue2.code === "invalid_element") {
6459
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6535
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6460
6536
  } else {
6461
- const fullpath = [...path25, ...issue2.path];
6537
+ const fullpath = [...path26, ...issue2.path];
6462
6538
  if (fullpath.length === 0) {
6463
6539
  fieldErrors._errors.push(mapper(issue2));
6464
6540
  } else {
@@ -6485,17 +6561,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
6485
6561
  }
6486
6562
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
6487
6563
  const result = { errors: [] };
6488
- const processError = (error52, path25 = []) => {
6564
+ const processError = (error52, path26 = []) => {
6489
6565
  var _a3, _b;
6490
6566
  for (const issue2 of error52.issues) {
6491
6567
  if (issue2.code === "invalid_union" && issue2.errors.length) {
6492
- issue2.errors.map((issues) => processError({ issues }, [...path25, ...issue2.path]));
6568
+ issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
6493
6569
  } else if (issue2.code === "invalid_key") {
6494
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6570
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6495
6571
  } else if (issue2.code === "invalid_element") {
6496
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6572
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6497
6573
  } else {
6498
- const fullpath = [...path25, ...issue2.path];
6574
+ const fullpath = [...path26, ...issue2.path];
6499
6575
  if (fullpath.length === 0) {
6500
6576
  result.errors.push(mapper(issue2));
6501
6577
  continue;
@@ -6527,8 +6603,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
6527
6603
  }
6528
6604
  function toDotPath(_path) {
6529
6605
  const segs = [];
6530
- const path25 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6531
- for (const seg of path25) {
6606
+ const path26 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6607
+ for (const seg of path26) {
6532
6608
  if (typeof seg === "number")
6533
6609
  segs.push(`[${seg}]`);
6534
6610
  else if (typeof seg === "symbol")
@@ -19220,13 +19296,13 @@ function resolveRef(ref, ctx) {
19220
19296
  if (!ref.startsWith("#")) {
19221
19297
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
19222
19298
  }
19223
- const path25 = ref.slice(1).split("/").filter(Boolean);
19224
- if (path25.length === 0) {
19299
+ const path26 = ref.slice(1).split("/").filter(Boolean);
19300
+ if (path26.length === 0) {
19225
19301
  return ctx.rootSchema;
19226
19302
  }
19227
19303
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
19228
- if (path25[0] === defsKey) {
19229
- const key = path25[1];
19304
+ if (path26[0] === defsKey) {
19305
+ const key = path26[1];
19230
19306
  if (!key || !ctx.defs[key]) {
19231
19307
  throw new Error(`Reference not found: ${ref}`);
19232
19308
  }
@@ -20649,7 +20725,7 @@ import { execFileSync } from "node:child_process";
20649
20725
  import { randomUUID as randomUUID2 } from "node:crypto";
20650
20726
  import { constants } from "node:fs";
20651
20727
  import { copyFile as copyFile2, mkdir as mkdir3, open as open3, readFile as readFile4, readdir as readdir2, rename as rename2, rm as rm3, stat } from "node:fs/promises";
20652
- import path4 from "node:path";
20728
+ import path5 from "node:path";
20653
20729
 
20654
20730
  // packages/mapping-store/dist/records.js
20655
20731
  var nonBlankTextSchema6 = external_exports.string().refine((value2) => value2.trim().length > 0, {
@@ -20900,12 +20976,12 @@ var MappingStore = class {
20900
20976
  #initialized = false;
20901
20977
  #lockHandle = null;
20902
20978
  constructor(options2) {
20903
- this.#directory = path4.resolve(options2.directory);
20904
- this.#threadsDirectory = path4.join(this.#directory, "threads");
20905
- this.#delegationsDirectory = path4.join(this.#directory, "delegations");
20906
- this.#backupsDirectory = path4.join(this.#directory, "backups");
20907
- this.#quarantineDirectory = path4.join(this.#directory, "quarantine");
20908
- this.#lockPath = path4.join(this.#directory, "store.lock");
20979
+ this.#directory = path5.resolve(options2.directory);
20980
+ this.#threadsDirectory = path5.join(this.#directory, "threads");
20981
+ this.#delegationsDirectory = path5.join(this.#directory, "delegations");
20982
+ this.#backupsDirectory = path5.join(this.#directory, "backups");
20983
+ this.#quarantineDirectory = path5.join(this.#directory, "quarantine");
20984
+ this.#lockPath = path5.join(this.#directory, "store.lock");
20909
20985
  this.#instanceId = options2.instanceId ?? randomUUID2();
20910
20986
  this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
20911
20987
  this.#beforeReplace = options2.beforeReplace;
@@ -20924,8 +21000,8 @@ var MappingStore = class {
20924
21000
  await this.#cleanupResidue();
20925
21001
  const names = (await readdir2(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
20926
21002
  for (const name of names) {
20927
- const primary = path4.join(this.#threadsDirectory, name);
20928
- const backup = path4.join(this.#backupsDirectory, name);
21003
+ const primary = path5.join(this.#threadsDirectory, name);
21004
+ const backup = path5.join(this.#backupsDirectory, name);
20929
21005
  let record3 = null;
20930
21006
  try {
20931
21007
  record3 = await this.#readRecord(primary, name);
@@ -20934,7 +21010,7 @@ var MappingStore = class {
20934
21010
  record3 = await this.#readRecord(backup, name);
20935
21011
  await this.#replaceFile(primary, record3, false);
20936
21012
  } catch (backupError) {
20937
- const quarantine = path4.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
21013
+ const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
20938
21014
  await rename2(primary, quarantine).catch(() => void 0);
20939
21015
  void primaryError;
20940
21016
  void backupError;
@@ -20950,14 +21026,14 @@ var MappingStore = class {
20950
21026
  }
20951
21027
  const delegationNames = (await readdir2(this.#delegationsDirectory)).filter((name) => name.endsWith(".json"));
20952
21028
  for (const name of delegationNames) {
20953
- const file2 = path4.join(this.#delegationsDirectory, name);
21029
+ const file2 = path5.join(this.#delegationsDirectory, name);
20954
21030
  try {
20955
21031
  const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile4(file2, "utf8")));
20956
21032
  if (`${parsed.delegationId}.json` !== name)
20957
21033
  throw new Error("filename mismatch");
20958
21034
  this.#delegations.set(parsed.delegationId, parsed);
20959
21035
  } catch {
20960
- const quarantine = path4.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
21036
+ const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
20961
21037
  await rename2(file2, quarantine).catch(() => void 0);
20962
21038
  }
20963
21039
  }
@@ -21115,10 +21191,35 @@ var MappingStore = class {
21115
21191
  turnMappings: this.#mergeMappings(current.turnMappings, input.turnMappings ?? [])
21116
21192
  }));
21117
21193
  }
21194
+ // Keep native ref, Turn mappings and the indexed create request in one serialized
21195
+ // record mutation; separate setters could leave a child pointing at mixed Sessions.
21196
+ async rebindSubagentSession(input) {
21197
+ return this.#update(input.hostThreadId, (current) => {
21198
+ const parent = this.#records.get(input.parentHostThreadId);
21199
+ if (current.state !== "ready" || !current.nativeSessionRef || current.subagent?.parentHostThreadId !== input.parentHostThreadId || parent?.state !== "ready" || parent.harnessId !== current.harnessId || input.previousNativeSessionRef.harnessId !== current.harnessId || input.nativeSessionRef.harnessId !== current.harnessId || !sameJson(parent.nativeSessionRef, input.nativeSessionRef))
21200
+ throw new MappingStoreError("MAPPING_CONFLICT", "Subagent replacement must belong to its current parent Session");
21201
+ if (sameJson(current.nativeSessionRef, input.nativeSessionRef) && current.createRequestId === input.createRequestId)
21202
+ return null;
21203
+ if (!sameJson(current.nativeSessionRef, input.previousNativeSessionRef)) {
21204
+ throw new MappingStoreError("MAPPING_CONFLICT", "Subagent replacement source Session is stale");
21205
+ }
21206
+ const nativeSessionId = input.nativeSessionRef.nativeSessionId;
21207
+ return {
21208
+ ...current,
21209
+ createRequestId: input.createRequestId,
21210
+ nativeSessionRef: input.nativeSessionRef,
21211
+ turnMappings: current.turnMappings.map((mapping) => ({
21212
+ ...mapping,
21213
+ nativeTurnRef: { ...mapping.nativeTurnRef, nativeSessionId },
21214
+ ...mapping.nativeCheckpointRef ? { nativeCheckpointRef: { ...mapping.nativeCheckpointRef, nativeSessionId } } : {}
21215
+ }))
21216
+ };
21217
+ });
21218
+ }
21118
21219
  async replaceReadySession(input) {
21119
21220
  return this.#update(input.hostThreadId, (current) => {
21120
- if (current.state !== "ready" || !current.nativeSessionRef || !current.forkSource || current.forkSource.hostThreadId !== input.forkSource.hostThreadId || current.nativeSessionRef.nativeSessionId === input.nativeSessionRef.nativeSessionId || input.turnMappings.length < 1 || input.turnMappings.length >= current.turnMappings.length || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
21121
- throw new MappingStoreError("MAPPING_CONFLICT", "Ready Session replacement must retain an exact shorter derived prefix");
21221
+ if (current.state !== "ready" || !current.nativeSessionRef || current.revision !== input.expectedRevision || !sameJson(current.nativeSessionRef, input.expectedNativeSessionRef) || !current.forkSource || current.forkSource.hostThreadId !== input.forkSource.hostThreadId || current.nativeSessionRef.nativeSessionId === input.nativeSessionRef.nativeSessionId || input.turnMappings.length < 1 || input.turnMappings.length >= current.turnMappings.length || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
21222
+ throw new MappingStoreError("MAPPING_CONFLICT", "Ready Session replacement must match the expected record and retain an exact shorter derived prefix");
21122
21223
  }
21123
21224
  return {
21124
21225
  ...current,
@@ -21130,8 +21231,8 @@ var MappingStore = class {
21130
21231
  }
21131
21232
  async replaceReadySessionAfterLastTurn(input) {
21132
21233
  return this.#update(input.hostThreadId, (current) => {
21133
- if (current.state !== "ready" || !current.nativeSessionRef || input.turnMappings.length !== current.turnMappings.length - 1 || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
21134
- throw new MappingStoreError("MAPPING_CONFLICT", "Last-Turn Session replacement must retain the exact shorter Host Turn prefix");
21234
+ if (current.state !== "ready" || !current.nativeSessionRef || current.revision !== input.expectedRevision || !sameJson(current.nativeSessionRef, input.expectedNativeSessionRef) || input.turnMappings.length !== current.turnMappings.length - 1 || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
21235
+ throw new MappingStoreError("MAPPING_CONFLICT", "Last-Turn Session replacement must match the expected record and retain the exact shorter Host Turn prefix");
21135
21236
  }
21136
21237
  return {
21137
21238
  ...current,
@@ -21352,10 +21453,10 @@ var MappingStore = class {
21352
21453
  readdir2(this.#directory)
21353
21454
  ]);
21354
21455
  await Promise.all([
21355
- ...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path4.join(this.#threadsDirectory, name), { force: true })),
21356
- ...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path4.join(this.#delegationsDirectory, name), { force: true })),
21456
+ ...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#threadsDirectory, name), { force: true })),
21457
+ ...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#delegationsDirectory, name), { force: true })),
21357
21458
  // Renamed aside by #acquireLock; nothing reads them back, and they accumulate one per run.
21358
- ...rootNames.filter((name) => name.startsWith(`${path4.basename(this.#lockPath)}.stale-`)).map((name) => rm3(path4.join(this.#directory, name), { force: true }))
21459
+ ...rootNames.filter((name) => name.startsWith(`${path5.basename(this.#lockPath)}.stale-`)).map((name) => rm3(path5.join(this.#directory, name), { force: true }))
21359
21460
  ]);
21360
21461
  }
21361
21462
  async #acquireLock() {
@@ -21456,13 +21557,13 @@ var MappingStore = class {
21456
21557
  await next;
21457
21558
  }
21458
21559
  #recordPath(hostThreadId) {
21459
- return path4.join(this.#threadsDirectory, `${hostThreadId}.json`);
21560
+ return path5.join(this.#threadsDirectory, `${hostThreadId}.json`);
21460
21561
  }
21461
21562
  #delegationPath(delegationId) {
21462
- return path4.join(this.#delegationsDirectory, `${delegationId}.json`);
21563
+ return path5.join(this.#delegationsDirectory, `${delegationId}.json`);
21463
21564
  }
21464
21565
  #backupPath(hostThreadId) {
21465
- return path4.join(this.#backupsDirectory, `${hostThreadId}.json`);
21566
+ return path5.join(this.#backupsDirectory, `${hostThreadId}.json`);
21466
21567
  }
21467
21568
  #requireInitialized() {
21468
21569
  if (!this.#initialized) {
@@ -22215,8 +22316,8 @@ function projectFileChangeKind(kind) {
22215
22316
  return { type: kind };
22216
22317
  }
22217
22318
  function projectFileChanges(changes) {
22218
- return changes.map(({ path: path25, kind, unifiedDiff }) => ({
22219
- path: path25,
22319
+ return changes.map(({ path: path26, kind, unifiedDiff }) => ({
22320
+ path: path26,
22220
22321
  kind: projectFileChangeKind(kind),
22221
22322
  diff: unifiedDiff
22222
22323
  }));
@@ -22531,9 +22632,9 @@ function projectHistoricalTurn(input) {
22531
22632
  return [];
22532
22633
  }
22533
22634
  return item.type === "reasoning" ? [
22534
- projectItem(item, outcome, cwd, true, ""),
22635
+ projectItem(item, outcome, cwd, true, input.threadId ?? ""),
22535
22636
  projectReasoningTranscriptItem(item, outcome, cwd)
22536
- ] : [projectItem(item, outcome, cwd, true, "")];
22637
+ ] : [projectItem(item, outcome, cwd, true, input.threadId ?? "")];
22537
22638
  })
22538
22639
  ],
22539
22640
  error: error51,
@@ -23165,13 +23266,13 @@ function decodeThreadForkRequest(request) {
23165
23266
  if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
23166
23267
  throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
23167
23268
  }
23168
- const path25 = optionalText(params, "path", { allowEmpty: true });
23269
+ const path26 = optionalText(params, "path", { allowEmpty: true });
23169
23270
  const ephemeral = optionalBoolean(params, "ephemeral");
23170
23271
  return {
23171
23272
  threadId: threadId3,
23172
23273
  ...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
23173
23274
  ...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
23174
- ...path25 ? { path: path25 } : {},
23275
+ ...path26 ? { path: path26 } : {},
23175
23276
  ...optionalField(params, "model"),
23176
23277
  ...optionalField(params, "modelProvider"),
23177
23278
  ...optionalField(params, "cwd"),
@@ -24182,18 +24283,149 @@ async function inspectHarnessAccounts(adapters, descriptors, timeoutMs = 12e3) {
24182
24283
  }
24183
24284
 
24184
24285
  // packages/host-runtime/src/app-server-host.ts
24185
- import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
24286
+ import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
24186
24287
  import { rm as rm4 } from "node:fs/promises";
24187
24288
  import os2 from "node:os";
24188
- import path11 from "node:path";
24289
+ import path12 from "node:path";
24189
24290
 
24190
24291
  // packages/host-runtime/src/external-thread-fork.ts
24191
24292
  import nodePath from "node:path";
24192
24293
 
24193
24294
  // packages/host-runtime/src/external-thread-repository.ts
24194
- import { randomUUID as randomUUID3 } from "node:crypto";
24295
+ import { randomUUID as randomUUID4 } from "node:crypto";
24195
24296
  import os from "node:os";
24196
- import path5 from "node:path";
24297
+ import path6 from "node:path";
24298
+
24299
+ // packages/host-runtime/src/external-subagent-threads.ts
24300
+ import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
24301
+ function childCreateRequest(parent, nativeRef, id2) {
24302
+ const key = createHash3("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
24303
+ return `subagent:${key}`;
24304
+ }
24305
+ function subagentMaterializer(store, parent, previousParent) {
24306
+ if (previousParent && (previousParent.hostThreadId !== parent.hostThreadId || previousParent.harnessId !== parent.harnessId)) {
24307
+ throw new Error("Subagent Session replacement must stay in the same Host Thread");
24308
+ }
24309
+ const previousRef = previousParent?.nativeSessionRef;
24310
+ let legacy;
24311
+ const legacyRecords = () => legacy ??= store.listThreads().then((records) => {
24312
+ const byRequest = /* @__PURE__ */ new Map();
24313
+ const children = /* @__PURE__ */ new Map();
24314
+ for (const record3 of records) {
24315
+ if (!record3.subagent || record3.harnessId !== parent.harnessId || !record3.nativeSessionRef)
24316
+ continue;
24317
+ const owner = {
24318
+ hostThreadId: record3.subagent.parentHostThreadId,
24319
+ harnessId: record3.harnessId
24320
+ };
24321
+ const key = childCreateRequest(
24322
+ owner,
24323
+ record3.nativeSessionRef,
24324
+ record3.subagent.nativeSubagentId
24325
+ );
24326
+ if (!byRequest.has(key) || record3.state === "ready") byRequest.set(key, record3);
24327
+ const siblings = children.get(owner.hostThreadId) ?? [];
24328
+ siblings.push(record3);
24329
+ children.set(owner.hostThreadId, siblings);
24330
+ }
24331
+ return { byRequest, children };
24332
+ });
24333
+ const rebind = async (existing, owner, visited = /* @__PURE__ */ new Set()) => {
24334
+ if (!previousRef || !owner.nativeSessionRef || !existing.subagent || visited.has(existing.hostThreadId)) {
24335
+ throw new Error("Invalid retained Subagent Session tree");
24336
+ }
24337
+ visited.add(existing.hostThreadId);
24338
+ const rebound = await store.rebindSubagentSession({
24339
+ hostThreadId: existing.hostThreadId,
24340
+ parentHostThreadId: owner.hostThreadId,
24341
+ previousNativeSessionRef: previousRef,
24342
+ nativeSessionRef: owner.nativeSessionRef,
24343
+ createRequestId: childCreateRequest(
24344
+ owner,
24345
+ owner.nativeSessionRef,
24346
+ existing.subagent.nativeSubagentId
24347
+ )
24348
+ });
24349
+ for (const descendant of (await legacyRecords()).children.get(existing.hostThreadId) ?? []) {
24350
+ if (descendant.state === "ready" && descendant.nativeSessionRef?.nativeSessionId === previousRef.nativeSessionId) {
24351
+ await rebind(descendant, rebound, visited);
24352
+ }
24353
+ }
24354
+ return rebound;
24355
+ };
24356
+ return async (child) => {
24357
+ if (!child.nativeSubagentId || !parent.nativeSessionRef || parent.state !== "ready")
24358
+ return null;
24359
+ const nativeRef = parent.nativeSessionRef;
24360
+ const createRequestId = childCreateRequest(parent, nativeRef, child.nativeSubagentId);
24361
+ const previousRequest = previousRef && previousRef.nativeSessionId !== nativeRef.nativeSessionId ? childCreateRequest(parent, previousRef, child.nativeSubagentId) : void 0;
24362
+ let existing = await store.getThreadByCreateRequest(createRequestId);
24363
+ if (!existing && previousRequest)
24364
+ existing = await store.getThreadByCreateRequest(previousRequest);
24365
+ if (!existing) {
24366
+ const { byRequest } = await legacyRecords();
24367
+ existing = byRequest.get(createRequestId) ?? (previousRequest ? byRequest.get(previousRequest) : void 0) ?? null;
24368
+ }
24369
+ if (existing?.state === "ready") {
24370
+ if (existing.nativeSessionRef?.nativeSessionId === nativeRef.nativeSessionId) return existing;
24371
+ if (!previousRef) throw new Error("Subagent belongs to a different Native Session");
24372
+ return rebind(existing, parent);
24373
+ }
24374
+ const provisional = existing ?? await store.createProvisional({
24375
+ hostThreadId: hostThreadIdSchema.parse(randomUUID3()),
24376
+ createRequestId,
24377
+ harnessId: parent.harnessId,
24378
+ cwd: parent.cwd,
24379
+ title: child.description,
24380
+ transportModelId: parent.transportModelId,
24381
+ ephemeral: parent.ephemeral,
24382
+ historyMode: "paginated",
24383
+ subagent: {
24384
+ parentHostThreadId: parent.hostThreadId,
24385
+ nativeSubagentId: child.nativeSubagentId,
24386
+ ...child.role ? { role: child.role } : {}
24387
+ }
24388
+ });
24389
+ return provisional.state === "ready" ? provisional : store.commitReady({
24390
+ hostThreadId: provisional.hostThreadId,
24391
+ nativeSessionRef: nativeRef
24392
+ });
24393
+ };
24394
+ }
24395
+ async function materializeExternalSubagent(store, parent, child) {
24396
+ return subagentMaterializer(store, parent)(child);
24397
+ }
24398
+ async function projectExternalSnapshot(store, record3, snapshot, previousParent) {
24399
+ const materialize = subagentMaterializer(store, record3, previousParent);
24400
+ const turns = [];
24401
+ for (const [index, turn] of snapshot.turns.entries()) {
24402
+ const mapping = record3.turnMappings[index];
24403
+ if (!mapping) throw new Error("External Snapshot mapping is incomplete");
24404
+ const items = await Promise.all(
24405
+ turn.items.map(async (entry) => {
24406
+ if (entry.item.type !== "subagentDelegation") return entry;
24407
+ const subagents = await Promise.all(
24408
+ entry.item.subagents.map(async (child) => {
24409
+ const stored = await materialize(child);
24410
+ return stored ? { ...child, subagentId: stored.hostThreadId } : child;
24411
+ })
24412
+ );
24413
+ return { ...entry, item: { ...entry.item, subagents } };
24414
+ })
24415
+ );
24416
+ turns.push(
24417
+ projectHistoricalTurn({
24418
+ threadId: record3.hostThreadId,
24419
+ turnId: mapping.hostTurnId,
24420
+ cwd: record3.cwd,
24421
+ snapshot: { ...turn, items }
24422
+ })
24423
+ );
24424
+ }
24425
+ return turns;
24426
+ }
24427
+
24428
+ // packages/host-runtime/src/external-thread-repository.ts
24197
24429
  function nativeTurnKey2(ref) {
24198
24430
  return `${ref.harnessId}\0${ref.nativeSessionId}\0${ref.nativeTurnKey}\0${ref.formatVersion}`;
24199
24431
  }
@@ -24202,8 +24434,8 @@ function sameMapping(left, right) {
24202
24434
  }
24203
24435
  function defaultMappingStoreDirectory(environment) {
24204
24436
  const dataDirectory = environment.CODEXHOST_DATA_DIR;
24205
- return path5.join(
24206
- dataDirectory ? path5.resolve(dataDirectory) : path5.join(os.homedir(), ".codexhost"),
24437
+ return path6.join(
24438
+ dataDirectory ? path6.resolve(dataDirectory) : path6.join(os.homedir(), ".codexhost"),
24207
24439
  "mapping-store"
24208
24440
  );
24209
24441
  }
@@ -24228,6 +24460,9 @@ var ExternalThreadRepository = class {
24228
24460
  list() {
24229
24461
  return this.store.listThreads();
24230
24462
  }
24463
+ materializeSubagent(parent, child) {
24464
+ return materializeExternalSubagent(this.store, parent, child);
24465
+ }
24231
24466
  findByCreateRequest(createRequestId) {
24232
24467
  return this.store.getThreadByCreateRequest(createRequestId);
24233
24468
  }
@@ -24297,7 +24532,7 @@ var ExternalThreadRepository = class {
24297
24532
  throw new Error("Derived Snapshot identity does not belong to its Native Session");
24298
24533
  }
24299
24534
  return {
24300
- hostTurnId: hostTurnIdSchema.parse(randomUUID3()),
24535
+ hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
24301
24536
  nativeTurnRef: turn.nativeTurnRef,
24302
24537
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
24303
24538
  };
@@ -24309,15 +24544,7 @@ var ExternalThreadRepository = class {
24309
24544
  });
24310
24545
  return {
24311
24546
  record: nextRecord,
24312
- turns: snapshot.turns.map((turn, index) => {
24313
- const mapping = mappings[index];
24314
- if (!mapping) throw new Error("Derived Snapshot mapping is incomplete");
24315
- return projectHistoricalTurn({
24316
- turnId: mapping.hostTurnId,
24317
- cwd: record3.cwd,
24318
- snapshot: turn
24319
- });
24320
- })
24547
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot)
24321
24548
  };
24322
24549
  }
24323
24550
  async commitForkRollback(derived, source, nativeSessionRef, snapshot) {
@@ -24351,6 +24578,8 @@ var ExternalThreadRepository = class {
24351
24578
  });
24352
24579
  const nextRecord = await this.store.replaceReadySession({
24353
24580
  hostThreadId: derived.hostThreadId,
24581
+ expectedRevision: derived.revision,
24582
+ expectedNativeSessionRef: derived.nativeSessionRef,
24354
24583
  nativeSessionRef,
24355
24584
  turnMappings: mappings,
24356
24585
  forkSource: {
@@ -24360,15 +24589,7 @@ var ExternalThreadRepository = class {
24360
24589
  });
24361
24590
  return {
24362
24591
  record: nextRecord,
24363
- turns: snapshot.turns.map((turn, index) => {
24364
- const mapping = mappings[index];
24365
- if (!mapping) throw new Error("External rollback Snapshot mapping is incomplete");
24366
- return projectHistoricalTurn({
24367
- turnId: mapping.hostTurnId,
24368
- cwd: derived.cwd,
24369
- snapshot: turn
24370
- });
24371
- })
24592
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot, derived)
24372
24593
  };
24373
24594
  }
24374
24595
  async commitLastTurnRollback(current, nativeSessionRef, snapshot) {
@@ -24388,30 +24609,26 @@ var ExternalThreadRepository = class {
24388
24609
  });
24389
24610
  const nextRecord = await this.store.replaceReadySessionAfterLastTurn({
24390
24611
  hostThreadId: current.hostThreadId,
24612
+ expectedRevision: current.revision,
24613
+ expectedNativeSessionRef: current.nativeSessionRef,
24391
24614
  nativeSessionRef,
24392
24615
  turnMappings: mappings
24393
24616
  });
24394
24617
  return {
24395
24618
  record: nextRecord,
24396
- turns: snapshot.turns.map((turn, index) => {
24397
- const mapping = mappings[index];
24398
- if (!mapping) throw new Error("Last-Turn rollback Snapshot mapping is incomplete");
24399
- return projectHistoricalTurn({
24400
- turnId: mapping.hostTurnId,
24401
- cwd: current.cwd,
24402
- snapshot: turn
24403
- });
24404
- })
24619
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot, current)
24405
24620
  };
24406
24621
  }
24407
24622
  async sessionTreeId(record3) {
24408
24623
  let current = record3;
24409
24624
  const visited = /* @__PURE__ */ new Set();
24410
- while (current.forkSource) {
24625
+ while (current.subagent || current.forkSource) {
24411
24626
  if (visited.has(current.hostThreadId))
24412
24627
  throw new Error("External Thread Fork tree contains a cycle");
24413
24628
  visited.add(current.hostThreadId);
24414
- const source = await this.find(current.forkSource.hostThreadId);
24629
+ const parentId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
24630
+ if (!parentId) break;
24631
+ const source = await this.find(parentId);
24415
24632
  if (!source) break;
24416
24633
  current = source;
24417
24634
  }
@@ -24435,7 +24652,7 @@ var ExternalThreadRepository = class {
24435
24652
  const aligned = snapshot.turns.map((turn) => {
24436
24653
  const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
24437
24654
  const mapping = existing ?? {
24438
- hostTurnId: hostTurnIdSchema.parse(randomUUID3()),
24655
+ hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
24439
24656
  nativeTurnRef: turn.nativeTurnRef,
24440
24657
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
24441
24658
  };
@@ -24456,16 +24673,14 @@ var ExternalThreadRepository = class {
24456
24673
  const nextRecord = mappingsChanged ? await this.store.reconcileTurnMappings(record3.hostThreadId, orderedMappings) : record3;
24457
24674
  return {
24458
24675
  record: nextRecord,
24459
- turns: aligned.map(
24460
- ({ mapping, snapshot: turn }) => projectHistoricalTurn({ turnId: mapping.hostTurnId, cwd: record3.cwd, snapshot: turn })
24461
- )
24676
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot)
24462
24677
  };
24463
24678
  }
24464
24679
  };
24465
24680
  function createExternalThreadRecordInput(input) {
24466
24681
  return {
24467
- hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID3()),
24468
- createRequestId: input.createRequestId ?? randomUUID3(),
24682
+ hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID4()),
24683
+ createRequestId: input.createRequestId ?? randomUUID4(),
24469
24684
  harnessId: input.harnessId,
24470
24685
  cwd: input.cwd,
24471
24686
  ...input.title ? { title: input.title } : {},
@@ -25112,13 +25327,14 @@ async function restoreCurrentConfiguration(session, configuration) {
25112
25327
  }
25113
25328
  async function executeCurrentLastTurnRollback(input) {
25114
25329
  const { current, adapters, repository, runtime } = input;
25115
- if (current.record.turnMappings.length === 0) {
25330
+ const currentRecord = current.record;
25331
+ if (currentRecord.turnMappings.length === 0) {
25116
25332
  return {
25117
25333
  ok: false,
25118
25334
  error: { code: -32076, message: "External Thread has no Turn to roll back" }
25119
25335
  };
25120
25336
  }
25121
- const currentNativeRef = current.record.nativeSessionRef;
25337
+ const currentNativeRef = currentRecord.nativeSessionRef;
25122
25338
  const adapter = adapters.get(current.harnessId);
25123
25339
  if (!currentNativeRef || !adapter) {
25124
25340
  return {
@@ -25166,7 +25382,7 @@ async function executeCurrentLastTurnRollback(input) {
25166
25382
  await session.close().catch(() => void 0);
25167
25383
  return { ok: false, error: mapExternalThreadHarnessError(snapshot.error, "read") };
25168
25384
  }
25169
- if (snapshot.value.turns.length !== current.record.turnMappings.length - 1) {
25385
+ if (snapshot.value.turns.length !== currentRecord.turnMappings.length - 1) {
25170
25386
  await session.close().catch(() => void 0);
25171
25387
  return {
25172
25388
  ok: false,
@@ -25184,7 +25400,7 @@ async function executeCurrentLastTurnRollback(input) {
25184
25400
  let aligned;
25185
25401
  try {
25186
25402
  aligned = await repository.commitLastTurnRollback(
25187
- current.record,
25403
+ currentRecord,
25188
25404
  finalNativeRef,
25189
25405
  snapshot.value
25190
25406
  );
@@ -25232,7 +25448,8 @@ async function executeExternalThreadRollback(input) {
25232
25448
  ...input.environment ? { environment: input.environment } : {}
25233
25449
  });
25234
25450
  }
25235
- const forkSource = derived.record.forkSource;
25451
+ const derivedRecord = derived.record;
25452
+ const forkSource = derivedRecord.forkSource;
25236
25453
  if (!forkSource) {
25237
25454
  return {
25238
25455
  ok: false,
@@ -25263,10 +25480,11 @@ async function executeExternalThreadRollback(input) {
25263
25480
  const sourceRefreshError = await runtime.refresh(source);
25264
25481
  if (sourceRefreshError) return { ok: false, error: sourceRefreshError };
25265
25482
  }
25266
- const sourceBoundaryIndex = source.record.turnMappings.findIndex(
25483
+ const sourceRecord = source.record;
25484
+ const sourceBoundaryIndex = sourceRecord.turnMappings.findIndex(
25267
25485
  ({ hostTurnId }) => hostTurnId === forkSource.hostTurnId
25268
25486
  );
25269
- if (sourceBoundaryIndex < 0 || derived.record.turnMappings.length !== sourceBoundaryIndex + 1) {
25487
+ if (sourceBoundaryIndex < 0 || derivedRecord.turnMappings.length !== sourceBoundaryIndex + 1) {
25270
25488
  return {
25271
25489
  ok: false,
25272
25490
  error: {
@@ -25275,19 +25493,19 @@ async function executeExternalThreadRollback(input) {
25275
25493
  }
25276
25494
  };
25277
25495
  }
25278
- const excludedActiveTurnCount = source.running || source.record.turnMappings.length > derived.record.turnMappings.length ? 1 : 0;
25279
- const retainedCount = derived.record.turnMappings.length - rollback.numTurns + excludedActiveTurnCount;
25280
- if (retainedCount === derived.record.turnMappings.length) {
25496
+ const excludedActiveTurnCount = source.running || sourceRecord.turnMappings.length > derivedRecord.turnMappings.length ? 1 : 0;
25497
+ const retainedCount = derivedRecord.turnMappings.length - rollback.numTurns + excludedActiveTurnCount;
25498
+ if (retainedCount === derivedRecord.turnMappings.length) {
25281
25499
  return { ok: true, thread: derived.thread };
25282
25500
  }
25283
- const boundary = source.record.turnMappings[retainedCount - 1];
25501
+ const boundary = sourceRecord.turnMappings[retainedCount - 1];
25284
25502
  if (retainedCount < 1 || !boundary?.nativeCheckpointRef) {
25285
25503
  return {
25286
25504
  ok: false,
25287
25505
  error: { code: -32080, message: "External Fork Checkpoint is unavailable" }
25288
25506
  };
25289
25507
  }
25290
- const sourceNativeRef = source.record.nativeSessionRef;
25508
+ const sourceNativeRef = sourceRecord.nativeSessionRef;
25291
25509
  const adapter = adapters.get(source.harnessId);
25292
25510
  if (!sourceNativeRef || !adapter) {
25293
25511
  return {
@@ -25315,7 +25533,7 @@ async function executeExternalThreadRollback(input) {
25315
25533
  }
25316
25534
  const session = opened.value;
25317
25535
  const finalNativeRef = session.initialState.nativeRef;
25318
- if (!finalNativeRef || finalNativeRef.nativeSessionId === sourceNativeRef.nativeSessionId || finalNativeRef.nativeSessionId === derived.record.nativeSessionRef?.nativeSessionId) {
25536
+ if (!finalNativeRef || finalNativeRef.nativeSessionId === sourceNativeRef.nativeSessionId || finalNativeRef.nativeSessionId === derivedRecord.nativeSessionRef?.nativeSessionId) {
25319
25537
  await session.close().catch(() => void 0);
25320
25538
  return {
25321
25539
  ok: false,
@@ -25337,8 +25555,8 @@ async function executeExternalThreadRollback(input) {
25337
25555
  let aligned;
25338
25556
  try {
25339
25557
  aligned = await repository.commitForkRollback(
25340
- derived.record,
25341
- source.record,
25558
+ derivedRecord,
25559
+ sourceRecord,
25342
25560
  finalNativeRef,
25343
25561
  snapshot.value
25344
25562
  );
@@ -25583,9 +25801,43 @@ var ExternalThreadRuntime = class {
25583
25801
  } catch (error51) {
25584
25802
  this.#diagnose(error51);
25585
25803
  }
25804
+ await this.#retireSubagents(current.id);
25586
25805
  this.#threads.delete(current.id);
25587
25806
  return this.register(input);
25588
25807
  }
25808
+ async #retireSubagents(parentId) {
25809
+ const ancestors = /* @__PURE__ */ new Map();
25810
+ const descendant = async (record3) => {
25811
+ const visited = /* @__PURE__ */ new Set();
25812
+ let ownerId = record3?.subagent?.parentHostThreadId;
25813
+ while (ownerId && !visited.has(ownerId)) {
25814
+ if (ownerId === parentId) return true;
25815
+ visited.add(ownerId);
25816
+ let ancestor = ancestors.get(ownerId);
25817
+ if (!ancestor) {
25818
+ ancestor = this.#repository.find(ownerId);
25819
+ ancestors.set(ownerId, ancestor);
25820
+ }
25821
+ ownerId = (await ancestor)?.subagent?.parentHostThreadId;
25822
+ }
25823
+ return false;
25824
+ };
25825
+ for (const [id2, restoring] of [...this.#restores]) {
25826
+ if (await descendant(await this.#repository.find(id2))) {
25827
+ await restoring.catch(this.#diagnose);
25828
+ }
25829
+ }
25830
+ for (const child of this.#threads.values()) {
25831
+ if (!await descendant(child.record)) continue;
25832
+ this.#threads.delete(child.id);
25833
+ try {
25834
+ await child.session.close();
25835
+ await child.outputTask;
25836
+ } catch (error51) {
25837
+ this.#diagnose(error51);
25838
+ }
25839
+ }
25840
+ }
25589
25841
  async locate(threadId3) {
25590
25842
  const loaded = this.#threads.get(threadId3);
25591
25843
  if (loaded) return { kind: "external", record: loaded.record, thread: loaded };
@@ -25696,6 +25948,10 @@ var ExternalThreadRuntime = class {
25696
25948
  nativeSubagentId: subagent.nativeSubagentId,
25697
25949
  cwd: record3.cwd
25698
25950
  });
25951
+ const latest = await this.#repository.find(record3.hostThreadId);
25952
+ if (latest?.state === "ready" && latest.nativeSessionRef && JSON.stringify(latest.nativeSessionRef) !== JSON.stringify(parent)) {
25953
+ return this.#restore(latest);
25954
+ }
25699
25955
  if (!snapshot.ok) {
25700
25956
  throw new ExternalThreadOpenError(mapExternalThreadHarnessError(snapshot.error, "read"));
25701
25957
  }
@@ -25972,11 +26228,11 @@ var ExternalTurnSteering = class {
25972
26228
  };
25973
26229
 
25974
26230
  // packages/host-runtime/src/harness-delegation-coordinator.ts
25975
- import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
25976
- import path6 from "node:path";
26231
+ import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
26232
+ import path7 from "node:path";
25977
26233
 
25978
26234
  // packages/host-runtime/src/delegation-snapshot.ts
25979
- import { createHash as createHash3 } from "node:crypto";
26235
+ import { createHash as createHash4 } from "node:crypto";
25980
26236
  var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
25981
26237
  var DEFAULT_MESSAGE_LIMIT = 25;
25982
26238
  var MAX_MESSAGE_LIMIT = 100;
@@ -26030,7 +26286,7 @@ function allVisibleMessages(turns) {
26030
26286
  return messages;
26031
26287
  }
26032
26288
  function cursorFingerprint(threadId3) {
26033
- return createHash3("sha256").update(threadId3).digest("hex");
26289
+ return createHash4("sha256").update(threadId3).digest("hex");
26034
26290
  }
26035
26291
  function encodeCursor(threadId3, offset) {
26036
26292
  const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId3), offset });
@@ -26125,10 +26381,10 @@ function terminal(status) {
26125
26381
  return status === "completed" || status === "failed" || status === "interrupted";
26126
26382
  }
26127
26383
  function taskDigest(input) {
26128
- return createHash4("sha256").update(
26384
+ return createHash5("sha256").update(
26129
26385
  JSON.stringify({
26130
26386
  task: input.task,
26131
- cwd: path6.resolve(input.cwd),
26387
+ cwd: path7.resolve(input.cwd),
26132
26388
  modelId: input.model?.id ?? null,
26133
26389
  thinkingOptionId: input.thinkingOptionId ?? null
26134
26390
  })
@@ -26199,7 +26455,7 @@ var HarnessDelegationCoordinator = class {
26199
26455
  return {
26200
26456
  harnessId: input.harnessId,
26201
26457
  inspection: await adapter.inspect({
26202
- ...input.cwd ? { cwd: path6.resolve(input.cwd) } : {},
26458
+ ...input.cwd ? { cwd: path7.resolve(input.cwd) } : {},
26203
26459
  ...input.refresh !== void 0 ? { refresh: input.refresh } : {}
26204
26460
  })
26205
26461
  };
@@ -26213,7 +26469,7 @@ var HarnessDelegationCoordinator = class {
26213
26469
  const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
26214
26470
  return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
26215
26471
  }
26216
- const startInput = { ...input, parentThreadId, cwd: path6.resolve(selectedCwd) };
26472
+ const startInput = { ...input, parentThreadId, cwd: path7.resolve(selectedCwd) };
26217
26473
  if (!this.#adapters.has(input.harnessId)) {
26218
26474
  throw new DelegationControlError(
26219
26475
  "HARNESS_NOT_FOUND",
@@ -26253,10 +26509,10 @@ var HarnessDelegationCoordinator = class {
26253
26509
  });
26254
26510
  this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
26255
26511
  }
26256
- const delegationId = hostThreadIdSchema.parse(randomUUID4());
26257
- const childThreadId = hostThreadIdSchema.parse(randomUUID4());
26258
- const turnId = hostTurnIdSchema.parse(randomUUID4());
26259
- const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID4();
26512
+ const delegationId = hostThreadIdSchema.parse(randomUUID5());
26513
+ const childThreadId = hostThreadIdSchema.parse(randomUUID5());
26514
+ const turnId = hostTurnIdSchema.parse(randomUUID5());
26515
+ const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID5();
26260
26516
  let record3 = await this.#repository.createProvisional(
26261
26517
  createExternalThreadRecordInput({
26262
26518
  hostThreadId: childThreadId,
@@ -26381,7 +26637,7 @@ var HarnessDelegationCoordinator = class {
26381
26637
  if (thread.running || thread.activeTurnId) {
26382
26638
  throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
26383
26639
  }
26384
- const turnId = hostTurnIdSchema.parse(randomUUID4());
26640
+ const turnId = hostTurnIdSchema.parse(randomUUID5());
26385
26641
  try {
26386
26642
  await this.#startExternalTurn(thread, input.message, turnId);
26387
26643
  } catch (error51) {
@@ -26626,7 +26882,7 @@ var HarnessDelegationCoordinator = class {
26626
26882
 
26627
26883
  // packages/host-runtime/src/harness-plugin-loader.ts
26628
26884
  import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
26629
- import path8 from "node:path";
26885
+ import path9 from "node:path";
26630
26886
  import { pathToFileURL } from "node:url";
26631
26887
 
26632
26888
  // packages/host-runtime/src/harness-plugin-registry.ts
@@ -26664,16 +26920,16 @@ var HarnessPluginRegistry = class {
26664
26920
 
26665
26921
  // packages/host-runtime/src/plugin-files.ts
26666
26922
  import { open as open4, realpath, stat as stat2 } from "node:fs/promises";
26667
- import path7 from "node:path";
26923
+ import path8 from "node:path";
26668
26924
  function inside(root, candidate) {
26669
- const relative = path7.relative(root, candidate);
26670
- return relative !== "" && !path7.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path7.sep}`);
26925
+ const relative = path8.relative(root, candidate);
26926
+ return relative !== "" && !path8.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path8.sep}`);
26671
26927
  }
26672
26928
  async function pluginResourcePath(root, relative) {
26673
- if (path7.isAbsolute(relative) || !inside(root, path7.resolve(root, relative))) {
26929
+ if (path8.isAbsolute(relative) || !inside(root, path8.resolve(root, relative))) {
26674
26930
  throw new Error("Plugin resource escapes its root");
26675
26931
  }
26676
- const resolved = await realpath(path7.resolve(root, relative));
26932
+ const resolved = await realpath(path8.resolve(root, relative));
26677
26933
  if (!inside(root, resolved) || !(await stat2(resolved)).isFile()) {
26678
26934
  throw new Error("Plugin resource must be a regular file inside its root");
26679
26935
  }
@@ -26818,7 +27074,7 @@ async function loadHarnessPlugins(options2) {
26818
27074
  const enabledIds = /* @__PURE__ */ new Set();
26819
27075
  const roots = /* @__PURE__ */ new Set();
26820
27076
  for (const configuredRoot of options2.roots) {
26821
- if (!path8.isAbsolute(configuredRoot)) {
27077
+ if (!path9.isAbsolute(configuredRoot)) {
26822
27078
  diagnose({ code: "invalidRoot" });
26823
27079
  continue;
26824
27080
  }
@@ -26848,7 +27104,7 @@ async function loadHarnessPlugins(options2) {
26848
27104
  for (const directory of directories) {
26849
27105
  try {
26850
27106
  const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
26851
- const pluginRoot = await realpath2(path8.join(root, directory.name));
27107
+ const pluginRoot = await realpath2(path9.join(root, directory.name));
26852
27108
  await pluginResourcePath(pluginRoot, "manifest.json");
26853
27109
  const manifest = harnessPluginManifestSchema.parse(
26854
27110
  JSON.parse(
@@ -26995,8 +27251,8 @@ function spawnOfficialAppServerConnection(input) {
26995
27251
 
26996
27252
  // packages/host-runtime/src/account/account-repository.ts
26997
27253
  import { mkdir as mkdir4, readFile as readFile5, rename as rename3, writeFile as writeFile3 } from "node:fs/promises";
26998
- import path9 from "node:path";
26999
- import { randomUUID as randomUUID5 } from "node:crypto";
27254
+ import path10 from "node:path";
27255
+ import { randomUUID as randomUUID6 } from "node:crypto";
27000
27256
  function validateAccountId(accountId) {
27001
27257
  if (!/^[A-Za-z0-9._~-]+$/u.test(accountId)) {
27002
27258
  throw new Error("Codex Account ID must be non-empty and filename-safe");
@@ -27014,19 +27270,19 @@ var AccountRepository = class {
27014
27270
  #mutationTail = Promise.resolve();
27015
27271
  #writeTail = Promise.resolve();
27016
27272
  constructor(input) {
27017
- this.#file = path9.join(path9.resolve(input.directory), "accounts.json");
27273
+ this.#file = path10.join(path10.resolve(input.directory), "accounts.json");
27018
27274
  this.#defaultAccount = {
27019
27275
  ...input.defaultAccount,
27020
27276
  label: input.defaultAccount.label ?? input.defaultAccount.accountId
27021
27277
  };
27022
27278
  validateAccountId(this.#defaultAccount.accountId);
27023
- if (!path9.isAbsolute(this.#defaultAccount.codexHome)) {
27279
+ if (!path10.isAbsolute(this.#defaultAccount.codexHome)) {
27024
27280
  throw new Error("Codex Account CODEX_HOME must be absolute");
27025
27281
  }
27026
27282
  }
27027
27283
  async initialize() {
27028
27284
  if (this.#initialized) return;
27029
- await mkdir4(path9.dirname(this.#file), { recursive: true });
27285
+ await mkdir4(path10.dirname(this.#file), { recursive: true });
27030
27286
  let stored = null;
27031
27287
  try {
27032
27288
  stored = JSON.parse(await readFile5(this.#file, "utf8"));
@@ -27094,7 +27350,7 @@ var AccountRepository = class {
27094
27350
  async upsert(input) {
27095
27351
  this.#requireInitialized();
27096
27352
  validateAccountId(input.accountId);
27097
- if (!path9.isAbsolute(input.codexHome))
27353
+ if (!path10.isAbsolute(input.codexHome))
27098
27354
  throw new Error("Codex Account CODEX_HOME must be absolute");
27099
27355
  return this.#mutate(async () => {
27100
27356
  const previous = this.#accounts.get(input.accountId);
@@ -27103,7 +27359,7 @@ var AccountRepository = class {
27103
27359
  const planType = input.planType === null ? void 0 : input.planType ?? previous?.planType;
27104
27360
  const account = {
27105
27361
  accountId: input.accountId,
27106
- codexHome: path9.normalize(input.codexHome),
27362
+ codexHome: path10.normalize(input.codexHome),
27107
27363
  ...email3 ? { email: email3 } : {},
27108
27364
  ...planType ? { planType } : {},
27109
27365
  label: input.label ?? previous?.label ?? input.accountId,
@@ -27117,7 +27373,7 @@ var AccountRepository = class {
27117
27373
  }
27118
27374
  #validateAccount(account) {
27119
27375
  validateAccountId(account.accountId);
27120
- if (!path9.isAbsolute(account.codexHome)) throw new Error("Stored CODEX_HOME must be absolute");
27376
+ if (!path10.isAbsolute(account.codexHome)) throw new Error("Stored CODEX_HOME must be absolute");
27121
27377
  if (account.email && (!account.email.includes("@") || account.email.length > 320)) {
27122
27378
  throw new Error("Stored Codex Account email is invalid");
27123
27379
  }
@@ -27138,7 +27394,7 @@ var AccountRepository = class {
27138
27394
  accounts: [...this.#accounts.values()]
27139
27395
  };
27140
27396
  const operation = this.#writeTail.then(async () => {
27141
- const temporary = `${this.#file}.${process.pid}.${randomUUID5()}.tmp`;
27397
+ const temporary = `${this.#file}.${process.pid}.${randomUUID6()}.tmp`;
27142
27398
  await writeFile3(temporary, `${JSON.stringify(value2, null, 2)}
27143
27399
  `, { mode: 384 });
27144
27400
  await rename3(temporary, this.#file);
@@ -27161,19 +27417,19 @@ function isMissingFile(error51) {
27161
27417
 
27162
27418
  // packages/host-runtime/src/account/thread-account-store.ts
27163
27419
  import { mkdir as mkdir5, readFile as readFile6, rename as rename4, writeFile as writeFile4 } from "node:fs/promises";
27164
- import { randomUUID as randomUUID6 } from "node:crypto";
27165
- import path10 from "node:path";
27420
+ import { randomUUID as randomUUID7 } from "node:crypto";
27421
+ import path11 from "node:path";
27166
27422
  var ThreadAccountStore = class {
27167
27423
  #file;
27168
27424
  #bindings = /* @__PURE__ */ new Map();
27169
27425
  #initialized = false;
27170
27426
  #writeTail = Promise.resolve();
27171
27427
  constructor(input) {
27172
- this.#file = path10.join(path10.resolve(input.directory), "thread-accounts.json");
27428
+ this.#file = path11.join(path11.resolve(input.directory), "thread-accounts.json");
27173
27429
  }
27174
27430
  async initialize() {
27175
27431
  if (this.#initialized) return;
27176
- await mkdir5(path10.dirname(this.#file), { recursive: true });
27432
+ await mkdir5(path11.dirname(this.#file), { recursive: true });
27177
27433
  try {
27178
27434
  const stored = JSON.parse(await readFile6(this.#file, "utf8"));
27179
27435
  if (stored.formatVersion !== 1 || !stored.bindings || typeof stored.bindings !== "object") {
@@ -27232,7 +27488,7 @@ var ThreadAccountStore = class {
27232
27488
  bindings: Object.fromEntries(this.#bindings)
27233
27489
  };
27234
27490
  const operation = this.#writeTail.then(async () => {
27235
- const temporary = `${this.#file}.${process.pid}.${randomUUID6()}.tmp`;
27491
+ const temporary = `${this.#file}.${process.pid}.${randomUUID7()}.tmp`;
27236
27492
  await writeFile4(temporary, `${JSON.stringify(value2, null, 2)}
27237
27493
  `, { mode: 384 });
27238
27494
  await rename4(temporary, this.#file);
@@ -27249,7 +27505,7 @@ function isMissingFile2(error51) {
27249
27505
  import { mkdir as mkdir6 } from "node:fs/promises";
27250
27506
 
27251
27507
  // packages/host-runtime/src/official-request-broker.ts
27252
- import { randomUUID as randomUUID7 } from "node:crypto";
27508
+ import { randomUUID as randomUUID8 } from "node:crypto";
27253
27509
  var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
27254
27510
  var MAX_RETIRED_IDS = 1024;
27255
27511
  function isRecord9(value2) {
@@ -27265,7 +27521,7 @@ var OfficialRequestBroker = class {
27265
27521
  constructor(input) {
27266
27522
  this.#send = input.send;
27267
27523
  this.#timeoutMs = input.timeoutMs ?? 3e4;
27268
- this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID7()}`);
27524
+ this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
27269
27525
  }
27270
27526
  get pendingCount() {
27271
27527
  return this.#pending.size;
@@ -27629,21 +27885,45 @@ function externalAnchor(entry) {
27629
27885
  if (entry.source !== "external") throw new Error("Expected an External Thread list entry");
27630
27886
  return { timestamp: entry.timestamp, threadId: threadId(entry.thread) };
27631
27887
  }
27632
- function includesExternalRecord(record3, query) {
27888
+ function includesExternalRecord(record3, query, byId) {
27633
27889
  if (record3.state !== "ready" || !record3.nativeSessionRef) return false;
27634
- if (record3.subagent) return false;
27890
+ let current = record3;
27891
+ const owners = /* @__PURE__ */ new Set();
27892
+ while (current.subagent) {
27893
+ if (owners.has(current.hostThreadId)) return false;
27894
+ owners.add(current.hostThreadId);
27895
+ const parent = byId.get(current.subagent.parentHostThreadId);
27896
+ if (!parent || parent.state !== "ready" || parent.harnessId !== current.harnessId || parent.nativeSessionRef?.nativeSessionId !== current.nativeSessionRef?.nativeSessionId)
27897
+ return false;
27898
+ current = parent;
27899
+ }
27900
+ const sourceKind = record3.subagent ? "subAgentThreadSpawn" : "vscode";
27901
+ const scoped = query.parentThreadId !== null || query.ancestorThreadId !== null;
27902
+ if (record3.subagent && !scoped && !query.sourceKinds?.some((kind) => kind === "subAgent" || kind === "subAgentThreadSpawn"))
27903
+ return false;
27904
+ if (query.parentThreadId !== null && record3.subagent?.parentHostThreadId !== query.parentThreadId)
27905
+ return false;
27906
+ if (query.ancestorThreadId !== null) {
27907
+ let parentId = record3.subagent?.parentHostThreadId;
27908
+ const visited = /* @__PURE__ */ new Set([record3.hostThreadId]);
27909
+ while (parentId && parentId !== query.ancestorThreadId && !visited.has(parentId)) {
27910
+ visited.add(parentId);
27911
+ parentId = byId.get(parentId)?.subagent?.parentHostThreadId;
27912
+ }
27913
+ if (record3.hostThreadId === query.ancestorThreadId || parentId !== query.ancestorThreadId)
27914
+ return false;
27915
+ }
27635
27916
  if (record3.archived !== query.archived) return false;
27636
27917
  if (query.cwd !== null && !query.cwd.includes(record3.cwd)) return false;
27637
27918
  if (query.modelProviders !== null && query.modelProviders.length > 0 && !query.modelProviders.includes("codexhost")) {
27638
27919
  return false;
27639
27920
  }
27640
- if (query.sourceKinds !== null && query.sourceKinds.length > 0 && !query.sourceKinds.includes("vscode")) {
27921
+ if (query.sourceKinds !== null && query.sourceKinds.length > 0 && !query.sourceKinds.includes(sourceKind) && !(record3.subagent && query.sourceKinds.includes("subAgent"))) {
27641
27922
  return false;
27642
27923
  }
27643
27924
  if (query.searchTerm !== null && !record3.title.toLowerCase().includes(query.searchTerm.toLowerCase())) {
27644
27925
  return false;
27645
27926
  }
27646
- if (query.parentThreadId !== null || query.ancestorThreadId !== null) return false;
27647
27927
  if (query.isPinned === true) return false;
27648
27928
  return true;
27649
27929
  }
@@ -27653,25 +27933,25 @@ function resolveExternalSessionTreeIds(records) {
27653
27933
  const resolve = (start) => {
27654
27934
  const cached2 = resolved.get(start.hostThreadId);
27655
27935
  if (cached2) return cached2;
27656
- const path25 = [];
27936
+ const path26 = [];
27657
27937
  const visited = /* @__PURE__ */ new Set();
27658
27938
  let current = start;
27659
27939
  while (true) {
27660
27940
  const known = resolved.get(current.hostThreadId);
27661
27941
  if (known) {
27662
- for (const record3 of path25) resolved.set(record3.hostThreadId, known);
27942
+ for (const record3 of path26) resolved.set(record3.hostThreadId, known);
27663
27943
  return known;
27664
27944
  }
27665
27945
  if (visited.has(current.hostThreadId)) {
27666
27946
  throw new Error("External Thread Fork tree contains a cycle");
27667
27947
  }
27668
27948
  visited.add(current.hostThreadId);
27669
- path25.push(current);
27670
- const sourceId = current.forkSource?.hostThreadId;
27949
+ path26.push(current);
27950
+ const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
27671
27951
  const source = sourceId ? byId.get(sourceId) : void 0;
27672
27952
  if (!source) {
27673
27953
  const root = current.hostThreadId;
27674
- for (const record3 of path25) resolved.set(record3.hostThreadId, root);
27954
+ for (const record3 of path26) resolved.set(record3.hostThreadId, root);
27675
27955
  return root;
27676
27956
  }
27677
27957
  current = source;
@@ -27683,7 +27963,8 @@ function resolveExternalSessionTreeIds(records) {
27683
27963
  function listExternalThreadMetadata(input) {
27684
27964
  if (!input.query.supportsExternal) return { data: [], hasMore: false };
27685
27965
  const sessionIds = resolveExternalSessionTreeIds(input.records);
27686
- const entries = input.records.filter((record3) => includesExternalRecord(record3, input.query)).map((record3) => {
27966
+ const byId = new Map(input.records.map((record3) => [record3.hostThreadId, record3]));
27967
+ const entries = input.records.filter((record3) => includesExternalRecord(record3, input.query, byId)).map((record3) => {
27687
27968
  const runtime = input.runtimeFor(record3.hostThreadId);
27688
27969
  const sessionId = sessionIds.get(record3.hostThreadId);
27689
27970
  if (!sessionId) throw new Error("External Thread Session tree could not be resolved");
@@ -27765,6 +28046,7 @@ function threadId2(entry) {
27765
28046
  return entry.thread.id;
27766
28047
  }
27767
28048
  async function aggregateOfficialAccountThreadListPage(input) {
28049
+ const pageLimit = typeof input.params.limit === "number" ? input.params.limit : input.query.limit;
27768
28050
  const cursorValue2 = typeof input.params.cursor === "string" ? input.params.cursor : null;
27769
28051
  const cursor = cursorValue2 ? decodeCursor2(cursorValue2) : { accounts: initialAccounts(input.accountIds) };
27770
28052
  const sources = Object.entries(cursor.accounts).map(([accountId, state]) => ({
@@ -27801,7 +28083,7 @@ async function aggregateOfficialAccountThreadListPage(input) {
27801
28083
  if (source.done) return null;
27802
28084
  }
27803
28085
  source.batchStart = source.cursor;
27804
- const page = await request(source, source.cursor, Math.max(1, input.query.limit));
28086
+ const page = await request(source, source.cursor, Math.max(1, pageLimit));
27805
28087
  if (!source.requestedThisPage) {
27806
28088
  source.backwardsCursor = page.backwardsCursor;
27807
28089
  source.requestedThisPage = true;
@@ -27823,7 +28105,7 @@ async function aggregateOfficialAccountThreadListPage(input) {
27823
28105
  };
27824
28106
  const output = [];
27825
28107
  const emitted = /* @__PURE__ */ new Set();
27826
- while (output.length < input.query.limit) {
28108
+ while (output.length < pageLimit) {
27827
28109
  const candidates = await Promise.all(
27828
28110
  sources.map(async (source) => ({ source, entry: await ensure(source) }))
27829
28111
  );
@@ -28357,18 +28639,18 @@ var AppServerHost = class {
28357
28639
  };
28358
28640
  this.#writer = new OrderedWriter(this.#options.desktopOutput);
28359
28641
  const environment = this.#options.environment ?? process.env;
28360
- const dataDirectory = path11.resolve(
28361
- environment.CODEXHOST_DATA_DIR ?? path11.join(os2.homedir(), ".codexhost")
28642
+ const dataDirectory = path12.resolve(
28643
+ environment.CODEXHOST_DATA_DIR ?? path12.join(os2.homedir(), ".codexhost")
28362
28644
  );
28363
28645
  const accountRepository = options2.accountRepository ?? new AccountRepository({
28364
- directory: path11.join(dataDirectory, "codex-accounts"),
28646
+ directory: path12.join(dataDirectory, "codex-accounts"),
28365
28647
  defaultAccount: {
28366
28648
  accountId: "default",
28367
- codexHome: path11.resolve(environment.CODEX_HOME ?? path11.join(os2.homedir(), ".codex")),
28649
+ codexHome: path12.resolve(environment.CODEX_HOME ?? path12.join(os2.homedir(), ".codex")),
28368
28650
  label: "Default Codex Account"
28369
28651
  }
28370
28652
  });
28371
- const threadAccountStore = options2.threadAccountStore ?? new ThreadAccountStore({ directory: path11.join(dataDirectory, "codex-accounts") });
28653
+ const threadAccountStore = options2.threadAccountStore ?? new ThreadAccountStore({ directory: path12.join(dataDirectory, "codex-accounts") });
28372
28654
  this.#accountRepository = accountRepository;
28373
28655
  this.#threadAccountStore = threadAccountStore;
28374
28656
  this.#accountDataDirectory = dataDirectory;
@@ -29183,7 +29465,7 @@ var AppServerHost = class {
29183
29465
  throw new Error("Unknown Codex Account");
29184
29466
  const runtime = await this.#codexRuntimePool.get(params2.accountId);
29185
29467
  const response2 = await runtime.request("account/rateLimitResetCredit/consume", {
29186
- idempotencyKey: params2.idempotencyKey ?? randomUUID8()
29468
+ idempotencyKey: params2.idempotencyKey ?? randomUUID9()
29187
29469
  });
29188
29470
  if (isRecord12(response2.error)) {
29189
29471
  await this.#writer.json(rpcEnvelope(request, { error: response2.error }));
@@ -29230,10 +29512,10 @@ var AppServerHost = class {
29230
29512
  }
29231
29513
  if (request.method === "codexhost/account/create") {
29232
29514
  const params2 = codexAccountCreateParamsSchema.parse(requestObject(request));
29233
- const accountId = randomUUID8();
29515
+ const accountId = randomUUID9();
29234
29516
  const account = await this.#accountRepository.upsert({
29235
29517
  accountId,
29236
- codexHome: path11.join(this.#accountDataDirectory, "codex-homes", accountId),
29518
+ codexHome: path12.join(this.#accountDataDirectory, "codex-homes", accountId),
29237
29519
  label: params2.label ?? `Codex Account ${accountId.slice(0, 8)}`
29238
29520
  });
29239
29521
  const activeAccountId = await this.#accountRepository.getActiveAccountId();
@@ -29289,12 +29571,12 @@ var AppServerHost = class {
29289
29571
  for (const [key, session2] of this.#officialLoginSessions) {
29290
29572
  if (session2.accountId === params2.accountId) this.#officialLoginSessions.delete(key);
29291
29573
  }
29292
- const managedCodexHome = path11.join(
29574
+ const managedCodexHome = path12.join(
29293
29575
  this.#accountDataDirectory,
29294
29576
  "codex-homes",
29295
29577
  params2.accountId
29296
29578
  );
29297
- if (path11.resolve(account.codexHome) === path11.resolve(managedCodexHome)) {
29579
+ if (path12.resolve(account.codexHome) === path12.resolve(managedCodexHome)) {
29298
29580
  try {
29299
29581
  await rm4(managedCodexHome, { recursive: true, force: true });
29300
29582
  } catch (error51) {
@@ -29518,7 +29800,7 @@ var AppServerHost = class {
29518
29800
  throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
29519
29801
  }
29520
29802
  const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
29521
- const digest2 = createHash5("sha256").update(
29803
+ const digest2 = createHash6("sha256").update(
29522
29804
  JSON.stringify({
29523
29805
  task: input.task,
29524
29806
  cwd: input.cwd,
@@ -29621,7 +29903,7 @@ var AppServerHost = class {
29621
29903
  throw error51;
29622
29904
  }
29623
29905
  this.#activeOfficialTurns.set(threadId3, turnId);
29624
- const delegationId = hostThreadIdSchema.parse(randomUUID8());
29906
+ const delegationId = hostThreadIdSchema.parse(randomUUID9());
29625
29907
  try {
29626
29908
  const source = await this.#repository.find(input.parentThreadId);
29627
29909
  const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId3);
@@ -29785,7 +30067,7 @@ var AppServerHost = class {
29785
30067
  async #listDelegationThreads(input) {
29786
30068
  const [sortKey, sortDirection2] = input.sort.split("-");
29787
30069
  const request = {
29788
- id: `codexhost:delegation-list:${randomUUID8()}`,
30070
+ id: `codexhost:delegation-list:${randomUUID9()}`,
29789
30071
  method: "thread/list",
29790
30072
  params: {
29791
30073
  cwd: input.cwd ? [input.cwd] : null,
@@ -29848,6 +30130,8 @@ var AppServerHost = class {
29848
30130
  records,
29849
30131
  runtimeFor: (threadId3) => {
29850
30132
  const thread = this.#externalRuntime.get(threadId3);
30133
+ const subagentStatus = this.#subagentThreadStatuses.get(threadId3);
30134
+ if (subagentStatus) return { running: subagentStatus === "active" };
29851
30135
  return thread ? { running: thread.running } : null;
29852
30136
  },
29853
30137
  requestOfficialPage: (params) => aggregateOfficialAccountThreadListPage({
@@ -30261,7 +30545,7 @@ var AppServerHost = class {
30261
30545
  );
30262
30546
  return;
30263
30547
  }
30264
- const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID8());
30548
+ const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID9());
30265
30549
  const projection = {
30266
30550
  projector: new CodexTurnProjector({
30267
30551
  threadId: thread.id,
@@ -31120,7 +31404,7 @@ var AppServerHost = class {
31120
31404
  if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
31121
31405
  throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
31122
31406
  }
31123
- const turnId = hostTurnIdSchema.parse(randomUUID8());
31407
+ const turnId = hostTurnIdSchema.parse(randomUUID9());
31124
31408
  const startedAtMs = Date.now();
31125
31409
  const projection = {
31126
31410
  projector: new CodexTurnProjector({
@@ -31296,7 +31580,7 @@ var AppServerHost = class {
31296
31580
  if (event.type === "subagent.transcript.changed") {
31297
31581
  const nativeSubagentId = event.nativeSubagentId;
31298
31582
  const record3 = (await this.#repository.list()).find(
31299
- (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId
31583
+ (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId && candidate.nativeSessionRef?.nativeSessionId === thread.record.nativeSessionRef?.nativeSessionId
31300
31584
  );
31301
31585
  if (record3) await this.#refreshOpenSubagentThread(record3.hostThreadId, false);
31302
31586
  return;
@@ -31304,7 +31588,7 @@ var AppServerHost = class {
31304
31588
  if (event.type === "subagent.state.changed") {
31305
31589
  const nativeSubagentId = event.nativeSubagentId;
31306
31590
  const record3 = (await this.#repository.list()).find(
31307
- (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId
31591
+ (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId && candidate.nativeSessionRef?.nativeSessionId === thread.record.nativeSessionRef?.nativeSessionId
31308
31592
  );
31309
31593
  if (!record3) return;
31310
31594
  const status = event.status === "pending" || event.status === "running" ? "active" : "idle";
@@ -31408,33 +31692,13 @@ var AppServerHost = class {
31408
31692
  async #materializeSubagent(parent, subagent) {
31409
31693
  if (!subagent.nativeSubagentId || !parent.record.nativeSessionRef) return subagent;
31410
31694
  const status = subagent.status === "pending" || subagent.status === "running" ? "active" : "idle";
31411
- const records = await this.#repository.list();
31412
- const existing = records.find(
31413
- (record4) => record4.subagent?.parentHostThreadId === parent.id && record4.subagent.nativeSubagentId === subagent.nativeSubagentId
31414
- );
31415
- if (existing) {
31416
- this.#trackRunningSubagent(parent.id, existing.hostThreadId, status);
31417
- await this.#setSubagentThreadStatus(existing.hostThreadId, status);
31418
- return { ...subagent, subagentId: existing.hostThreadId };
31695
+ const record3 = await this.#repository.materializeSubagent(parent.record, subagent);
31696
+ if (!record3) return subagent;
31697
+ if (this.#subagentThreadStatuses.has(record3.hostThreadId)) {
31698
+ this.#trackRunningSubagent(parent.id, record3.hostThreadId, status);
31699
+ await this.#setSubagentThreadStatus(record3.hostThreadId, status);
31700
+ return { ...subagent, subagentId: record3.hostThreadId };
31419
31701
  }
31420
- const recordInput = createExternalThreadRecordInput({
31421
- harnessId: parent.record.harnessId,
31422
- cwd: parent.cwd,
31423
- title: subagent.description,
31424
- transportModelId: parent.transportModelId,
31425
- ephemeral: false,
31426
- historyMode: "paginated",
31427
- subagent: {
31428
- parentHostThreadId: parent.id,
31429
- nativeSubagentId: subagent.nativeSubagentId,
31430
- ...subagent.role ? { role: subagent.role } : {}
31431
- }
31432
- });
31433
- let record3 = await this.#repository.createProvisional(recordInput);
31434
- record3 = await this.#repository.commitNative(
31435
- record3.hostThreadId,
31436
- parent.record.nativeSessionRef
31437
- );
31438
31702
  const thread = externalThreadValue({
31439
31703
  record: record3,
31440
31704
  turns: [],
@@ -31678,7 +31942,7 @@ var AppServerHost = class {
31678
31942
  try {
31679
31943
  result = projection.projector.projectQuestion(
31680
31944
  interaction,
31681
- hostItemIdSchema.parse(randomUUID8())
31945
+ hostItemIdSchema.parse(randomUUID9())
31682
31946
  );
31683
31947
  } catch (error51) {
31684
31948
  this.#diagnose(error51);
@@ -31834,7 +32098,7 @@ var AppServerHost = class {
31834
32098
  };
31835
32099
 
31836
32100
  // packages/host-runtime/src/codex-runtime/account-official-listeners.ts
31837
- import path12 from "node:path";
32101
+ import path13 from "node:path";
31838
32102
  var AccountOfficialListeners = class {
31839
32103
  constructor(createListener) {
31840
32104
  this.createListener = createListener;
@@ -31845,7 +32109,7 @@ var AccountOfficialListeners = class {
31845
32109
  #closed = false;
31846
32110
  async endpoint(account) {
31847
32111
  if (this.#closed) throw new Error("Account official listeners are closed");
31848
- const key = path12.resolve(account.codexHome);
32112
+ const key = path13.resolve(account.codexHome);
31849
32113
  const existing = this.#starting.get(key);
31850
32114
  if (existing) return existing;
31851
32115
  const listener = this.createListener(account);
@@ -31981,17 +32245,17 @@ var DelegationControlRegistry = class {
31981
32245
 
31982
32246
  // packages/host-runtime/src/installed-harness-plugins.ts
31983
32247
  import os3 from "node:os";
31984
- import path14 from "node:path";
32248
+ import path15 from "node:path";
31985
32249
  import { fileURLToPath } from "node:url";
31986
32250
 
31987
32251
  // packages/host-runtime/src/launcher-url-opener.ts
31988
32252
  import { spawn as spawn3 } from "node:child_process";
31989
- import path13 from "node:path";
32253
+ import path14 from "node:path";
31990
32254
  var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
31991
32255
  var OPEN_TIMEOUT_MS = 1e4;
31992
32256
  function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn3(command, arguments_2, options2)) {
31993
32257
  const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
31994
- if (!launcher || !path13.isAbsolute(launcher)) return void 0;
32258
+ if (!launcher || !path14.isAbsolute(launcher)) return void 0;
31995
32259
  const launcherEnvironment = Object.fromEntries(
31996
32260
  Object.entries(environment).filter(([name]) => {
31997
32261
  const normalized = name.toUpperCase();
@@ -32049,9 +32313,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
32049
32313
  const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
32050
32314
  return {
32051
32315
  pluginRoots: [
32052
- path14.join(path14.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
32053
- environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path14.join(
32054
- environment.CODEXHOST_DATA_DIR ? path14.resolve(environment.CODEXHOST_DATA_DIR) : path14.join(os3.homedir(), ".codexhost"),
32316
+ path15.join(path15.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
32317
+ environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path15.join(
32318
+ environment.CODEXHOST_DATA_DIR ? path15.resolve(environment.CODEXHOST_DATA_DIR) : path15.join(os3.homedir(), ".codexhost"),
32055
32319
  "plugins"
32056
32320
  )
32057
32321
  ],
@@ -32176,12 +32440,12 @@ async function startDelegationControlServer(input) {
32176
32440
  }
32177
32441
 
32178
32442
  // packages/host-runtime/src/delegation-skill.ts
32179
- import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
32443
+ import { createHash as createHash7, randomUUID as randomUUID10 } from "node:crypto";
32180
32444
  import { mkdir as mkdir7, open as open5, readFile as readFile7, rename as rename5, rm as rm5, stat as stat3 } from "node:fs/promises";
32181
32445
  import os4 from "node:os";
32182
- import path15 from "node:path";
32446
+ import path16 from "node:path";
32183
32447
  var SKILL_VERSION = 7;
32184
- var SKILL_RELATIVE_PATH = path15.join("skills", "codexhost-delegation", "SKILL.md");
32448
+ var SKILL_RELATIVE_PATH = path16.join("skills", "codexhost-delegation", "SKILL.md");
32185
32449
  var PREVIOUS_MANAGED_DIGESTS = [
32186
32450
  "9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
32187
32451
  "2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
@@ -32236,9 +32500,9 @@ user’s request and the task:
32236
32500
  Report the result returned by read or a completed wait, together with the target
32237
32501
  agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
32238
32502
  `;
32239
- var CURRENT_DIGEST = createHash6("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
32503
+ var CURRENT_DIGEST = createHash7("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
32240
32504
  function digest(value2) {
32241
- return createHash6("sha256").update(value2).digest("hex");
32505
+ return createHash7("sha256").update(value2).digest("hex");
32242
32506
  }
32243
32507
  function managedVersion(value2) {
32244
32508
  const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
@@ -32253,8 +32517,8 @@ async function readOptional(filePath) {
32253
32517
  }
32254
32518
  }
32255
32519
  async function atomicWrite(filePath, content) {
32256
- await mkdir7(path15.dirname(filePath), { recursive: true, mode: 448 });
32257
- const temporaryPath = path15.join(path15.dirname(filePath), `.SKILL.md.${randomUUID9()}.tmp`);
32520
+ await mkdir7(path16.dirname(filePath), { recursive: true, mode: 448 });
32521
+ const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID10()}.tmp`);
32258
32522
  const handle = await open5(temporaryPath, "wx", 384);
32259
32523
  try {
32260
32524
  await handle.writeFile(content, "utf8");
@@ -32271,8 +32535,8 @@ async function atomicWrite(filePath, content) {
32271
32535
  async function installDelegationSkills(input = {}) {
32272
32536
  const home = input.homeDirectory ?? os4.homedir();
32273
32537
  const destinations = [
32274
- path15.join(home, ".agents", SKILL_RELATIVE_PATH),
32275
- path15.join(home, ".claude", SKILL_RELATIVE_PATH)
32538
+ path16.join(home, ".agents", SKILL_RELATIVE_PATH),
32539
+ path16.join(home, ".claude", SKILL_RELATIVE_PATH)
32276
32540
  ];
32277
32541
  const knownDigests = /* @__PURE__ */ new Set([
32278
32542
  CURRENT_DIGEST,
@@ -32337,9 +32601,9 @@ async function installDelegationSkills(input = {}) {
32337
32601
  }
32338
32602
 
32339
32603
  // packages/host-runtime/src/remote-control-app-server.ts
32340
- import { randomUUID as randomUUID10 } from "node:crypto";
32604
+ import { randomUUID as randomUUID11 } from "node:crypto";
32341
32605
  import { mkdir as mkdir8, open as open6, rename as rename6, rm as rm6 } from "node:fs/promises";
32342
- import path16 from "node:path";
32606
+ import path17 from "node:path";
32343
32607
 
32344
32608
  // packages/host-runtime/src/remote-official-connection.ts
32345
32609
  import net from "node:net";
@@ -32529,30 +32793,30 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
32529
32793
  function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
32530
32794
  const value2 = environment[name] ?? fallback;
32531
32795
  if (!value2) return null;
32532
- if (path16.isAbsolute(value2)) return path16.normalize(value2);
32533
- return platform === "win32" && path16.win32.isAbsolute(value2) ? path16.win32.normalize(value2) : null;
32796
+ if (path17.isAbsolute(value2)) return path17.normalize(value2);
32797
+ return platform === "win32" && path17.win32.isAbsolute(value2) ? path17.win32.normalize(value2) : null;
32534
32798
  }
32535
32799
  function nodeCompatibleWindowsPath(value2) {
32536
32800
  if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
32537
32801
  if (value2.startsWith("\\\\?\\")) return value2.slice(4);
32538
32802
  return value2;
32539
32803
  }
32540
- function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID10()) {
32804
+ function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID11()) {
32541
32805
  const safeInstance = instanceId.replaceAll(/[^a-zA-Z0-9-]/gu, "");
32542
32806
  if (!safeInstance) throw new Error("Remote Control bridge instance ID is invalid");
32543
32807
  return `\\\\.\\pipe\\codexhost-remote-control-${processId}-${safeInstance}`;
32544
32808
  }
32545
32809
  function remoteControlBridgeDescriptorPath(environment) {
32546
32810
  const root = environment.LOCALAPPDATA;
32547
- if (!root || !path16.isAbsolute(root)) return null;
32548
- return path16.join(path16.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
32811
+ if (!root || !path17.isAbsolute(root)) return null;
32812
+ return path17.join(path17.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
32549
32813
  }
32550
32814
  async function publishRemoteControlAppServerDescriptor(plan) {
32551
- const directory = path16.dirname(plan.descriptorPath);
32815
+ const directory = path17.dirname(plan.descriptorPath);
32552
32816
  await mkdir8(directory, { recursive: true, mode: 448 });
32553
- const temporaryPath = path16.join(
32817
+ const temporaryPath = path17.join(
32554
32818
  directory,
32555
- `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID10()}.tmp`
32819
+ `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID11()}.tmp`
32556
32820
  );
32557
32821
  const handle = await open6(temporaryPath, "wx", 384);
32558
32822
  try {
@@ -32643,14 +32907,14 @@ async function runRemoteControlAppServerBridge(input = {}) {
32643
32907
  import { createServer as createServer2 } from "node:http";
32644
32908
  import net2 from "node:net";
32645
32909
  import { chmod as chmod3, lstat as lstat6, mkdir as mkdir10, rm as rm8 } from "node:fs/promises";
32646
- import path18 from "node:path";
32910
+ import path19 from "node:path";
32647
32911
  import { PassThrough as PassThrough2 } from "node:stream";
32648
32912
 
32649
32913
  // packages/host-runtime/src/remote-socket-lock.ts
32650
- import { randomUUID as randomUUID11 } from "node:crypto";
32914
+ import { randomUUID as randomUUID12 } from "node:crypto";
32651
32915
  import { chmod as chmod2, lstat as lstat5, mkdir as mkdir9, open as open7, readFile as readFile8, readdir as readdir4, rename as rename7, rm as rm7 } from "node:fs/promises";
32652
32916
  import { uptime } from "node:os";
32653
- import path17 from "node:path";
32917
+ import path18 from "node:path";
32654
32918
  import { setTimeout as delay4 } from "node:timers/promises";
32655
32919
  var LOCK_RETRY_COUNT = 200;
32656
32920
  var LOCK_RETRY_DELAY_MS = 25;
@@ -32724,7 +32988,7 @@ async function readLockEntrySnapshot(filePath) {
32724
32988
  source,
32725
32989
  identity: { dev: metadata.dev, ino: metadata.ino },
32726
32990
  mtimeMs: metadata.mtimeMs,
32727
- record: record3 && path17.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
32991
+ record: record3 && path18.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
32728
32992
  };
32729
32993
  }
32730
32994
  function lockEntryIsAbandoned(snapshot) {
@@ -32745,7 +33009,7 @@ async function readLockEntryCatalog(lockDirectory) {
32745
33009
  let unsettled = false;
32746
33010
  for (const name of names) {
32747
33011
  if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
32748
- const snapshot = await readLockEntrySnapshot(path17.join(lockDirectory, name));
33012
+ const snapshot = await readLockEntrySnapshot(path18.join(lockDirectory, name));
32749
33013
  if (snapshot === null) continue;
32750
33014
  if (lockEntryIsAbandoned(snapshot)) {
32751
33015
  if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
@@ -32773,7 +33037,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
32773
33037
  await chmod2(lockDirectory, 448);
32774
33038
  }
32775
33039
  async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
32776
- const temporary = path17.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID11()}`);
33040
+ const temporary = path18.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID12()}`);
32777
33041
  const handle = await open7(temporary, "wx", 384);
32778
33042
  try {
32779
33043
  await handle.writeFile(`${JSON.stringify(record3)}
@@ -32848,8 +33112,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
32848
33112
  const legacyPath = `${socketPath}.initializing`;
32849
33113
  const lockDirectory = `${socketPath}.initializers`;
32850
33114
  await preparePrivateLockDirectory(lockDirectory);
32851
- const ownerToken = randomUUID11();
32852
- const entryPath = path17.join(lockDirectory, lockEntryName(ownerToken));
33115
+ const ownerToken = randomUUID12();
33116
+ const entryPath = path18.join(lockDirectory, lockEntryName(ownerToken));
32853
33117
  const baseRecord = {
32854
33118
  version: 2,
32855
33119
  ownerToken,
@@ -33023,14 +33287,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
33023
33287
  throw new Error("Remote app-server listener must use a Unix URL");
33024
33288
  }
33025
33289
  const explicit = listenUrl.slice("unix://".length);
33026
- if (explicit.length > 0) return path18.posix.resolve(decodeURIComponent(explicit));
33027
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path18.posix.join(environment.HOME, ".codex") : void 0);
33290
+ if (explicit.length > 0) return path19.posix.resolve(decodeURIComponent(explicit));
33291
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path19.posix.join(environment.HOME, ".codex") : void 0);
33028
33292
  if (!codexHome)
33029
33293
  throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
33030
- return path18.posix.join(codexHome, "app-server-control", "app-server-control.sock");
33294
+ return path19.posix.join(codexHome, "app-server-control", "app-server-control.sock");
33031
33295
  }
33032
33296
  function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
33033
- if (!path18.posix.isAbsolute(socketPath)) {
33297
+ if (!path19.posix.isAbsolute(socketPath)) {
33034
33298
  throw new Error("Shared official app-server socket path must be absolute");
33035
33299
  }
33036
33300
  if (remoteUnixListenerUrl(arguments_2) === null) {
@@ -33141,7 +33405,7 @@ async function removeStaleSocket(socketPath) {
33141
33405
  await rm8(socketPath, { force: true });
33142
33406
  }
33143
33407
  async function prepareRemoteAppServerSocketDirectory(socketPath) {
33144
- const socketDirectory = path18.dirname(socketPath);
33408
+ const socketDirectory = path19.dirname(socketPath);
33145
33409
  const existing = await lstat6(socketDirectory).catch((error51) => {
33146
33410
  if (error51.code === "ENOENT") return null;
33147
33411
  throw error51;
@@ -33346,20 +33610,20 @@ function createRemoteAppServerWebSocketListener(input) {
33346
33610
 
33347
33611
  // packages/host-runtime/src/remote-official-app-server.ts
33348
33612
  import { spawn as spawn4 } from "node:child_process";
33349
- import { randomUUID as randomUUID12 } from "node:crypto";
33613
+ import { randomUUID as randomUUID13 } from "node:crypto";
33350
33614
  import { lstat as lstat7, rm as rm9 } from "node:fs/promises";
33351
- import path19 from "node:path";
33615
+ import path20 from "node:path";
33352
33616
  var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
33353
33617
  var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
33354
- function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID12()) {
33355
- if (!path19.posix.isAbsolute(desktopControlSocketPath)) {
33618
+ function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID13()) {
33619
+ if (!path20.posix.isAbsolute(desktopControlSocketPath)) {
33356
33620
  throw new Error("Desktop control socket path must be absolute");
33357
33621
  }
33358
33622
  if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
33359
33623
  throw new Error("Shared official app-server socket token is invalid");
33360
33624
  }
33361
33625
  const compactToken = token.replaceAll("-", "").slice(0, 15);
33362
- return path19.posix.join(path19.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
33626
+ return path20.posix.join(path20.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
33363
33627
  }
33364
33628
  function errorMessage5(error51) {
33365
33629
  return error51 instanceof Error ? error51.message : String(error51);
@@ -33650,7 +33914,16 @@ function createHostUpdateCoordinator(options2) {
33650
33914
  });
33651
33915
  return contextPromise;
33652
33916
  };
33653
- const fetchLatest = options2.fetchLatest ?? ((signal) => fetchLatestGitHubRelease({ signal: signal ?? AbortSignal.timeout(15e3) }));
33917
+ const fetchLatest = options2.fetchLatest ?? (async (signal) => {
33918
+ const timeoutSignal = AbortSignal.timeout(15e3);
33919
+ const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
33920
+ const authenticated = await fetchLatestGitHubReleaseWithGitHubCli({
33921
+ ...options2.environment ? { environment: options2.environment } : {},
33922
+ platform,
33923
+ signal: requestSignal
33924
+ });
33925
+ return authenticated ?? fetchLatestGitHubRelease({ signal: requestSignal });
33926
+ });
33654
33927
  let candidate = null;
33655
33928
  async function latestStatus(context) {
33656
33929
  const discovered = await discoverLatestUpdateStatus(context.common.stateDirectory);
@@ -33826,9 +34099,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
33826
34099
  if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
33827
34100
  const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
33828
34101
  if (!npmPackageRoot || !hostRuntimePath) return true;
33829
- if (!path20.isAbsolute(npmPackageRoot) || !path20.isAbsolute(hostRuntimePath)) return false;
33830
- const runtimePackageRoot = path20.dirname(path20.dirname(path20.normalize(hostRuntimePath)));
33831
- return path20.relative(path20.normalize(npmPackageRoot), runtimePackageRoot) === "";
34102
+ if (!path21.isAbsolute(npmPackageRoot) || !path21.isAbsolute(hostRuntimePath)) return false;
34103
+ const runtimePackageRoot = path21.dirname(path21.dirname(path21.normalize(hostRuntimePath)));
34104
+ return path21.relative(path21.normalize(npmPackageRoot), runtimePackageRoot) === "";
33832
34105
  }
33833
34106
  function requiredRuntimeConfiguration(environment) {
33834
34107
  const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
@@ -33955,8 +34228,8 @@ async function runHostRuntime(input) {
33955
34228
  });
33956
34229
  try {
33957
34230
  await officialListeners.endpoint({
33958
- codexHome: path20.resolve(
33959
- delegationEnvironment.CODEX_HOME ?? path20.join(homedir(), ".codex")
34231
+ codexHome: path21.resolve(
34232
+ delegationEnvironment.CODEX_HOME ?? path21.join(homedir(), ".codex")
33960
34233
  )
33961
34234
  });
33962
34235
  await listener.listen();
@@ -34057,7 +34330,7 @@ async function runHostRuntime(input) {
34057
34330
  }
34058
34331
 
34059
34332
  // packages/host-runtime/src/remote-host-install.ts
34060
- import { createHash as createHash7, randomUUID as randomUUID13 } from "node:crypto";
34333
+ import { createHash as createHash8, randomUUID as randomUUID14 } from "node:crypto";
34061
34334
  import { constants as fsConstants } from "node:fs";
34062
34335
  import {
34063
34336
  access,
@@ -34072,7 +34345,7 @@ import {
34072
34345
  stat as stat4,
34073
34346
  writeFile as writeFile5
34074
34347
  } from "node:fs/promises";
34075
- import path21 from "node:path";
34348
+ import path22 from "node:path";
34076
34349
  var MANIFEST_FORMAT = 1;
34077
34350
  var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
34078
34351
  var PROFILE_START = "# >>> codexhost remote SSH >>>";
@@ -34083,25 +34356,25 @@ function resolvePaths(options2) {
34083
34356
  if (!configuredHome) {
34084
34357
  throw new Error("A non-root HOME is required for remote Host installation");
34085
34358
  }
34086
- const home = path21.resolve(configuredHome);
34087
- if (!home || home === path21.parse(home).root) {
34359
+ const home = path22.resolve(configuredHome);
34360
+ if (!home || home === path22.parse(home).root) {
34088
34361
  throw new Error("A non-root HOME is required for remote Host installation");
34089
34362
  }
34090
- const installRoot = path21.resolve(options2.installRoot ?? path21.join(home, ".codexhost", "remote"));
34091
- const profilePath = path21.resolve(
34092
- options2.profilePath ?? path21.join(
34363
+ const installRoot = path22.resolve(options2.installRoot ?? path22.join(home, ".codexhost", "remote"));
34364
+ const profilePath = path22.resolve(
34365
+ options2.profilePath ?? path22.join(
34093
34366
  home,
34094
- path21.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path21.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
34367
+ path22.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path22.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
34095
34368
  )
34096
34369
  );
34097
- const binDirectory = path21.join(installRoot, "bin");
34370
+ const binDirectory = path22.join(installRoot, "bin");
34098
34371
  return {
34099
34372
  home,
34100
34373
  installRoot,
34101
34374
  binDirectory,
34102
- wrapperPath: path21.join(binDirectory, "codex"),
34103
- manifestPath: path21.join(installRoot, "manifest.json"),
34104
- dataDirectory: path21.join(installRoot, "data"),
34375
+ wrapperPath: path22.join(binDirectory, "codex"),
34376
+ manifestPath: path22.join(installRoot, "manifest.json"),
34377
+ dataDirectory: path22.join(installRoot, "data"),
34105
34378
  profilePath
34106
34379
  };
34107
34380
  }
@@ -34117,10 +34390,10 @@ async function existingText(filePath) {
34117
34390
  }
34118
34391
  }
34119
34392
  async function fileSha256(filePath) {
34120
- return createHash7("sha256").update(await readFile9(filePath)).digest("hex");
34393
+ return createHash8("sha256").update(await readFile9(filePath)).digest("hex");
34121
34394
  }
34122
34395
  async function executable(filePath, label) {
34123
- const absolute = path21.resolve(filePath);
34396
+ const absolute = path22.resolve(filePath);
34124
34397
  try {
34125
34398
  if (!(await stat4(absolute)).isFile()) throw new Error("not a regular file");
34126
34399
  await access(absolute, fsConstants.X_OK);
@@ -34130,7 +34403,7 @@ async function executable(filePath, label) {
34130
34403
  return absolute;
34131
34404
  }
34132
34405
  async function existingFile(filePath, label) {
34133
- const absolute = path21.resolve(filePath);
34406
+ const absolute = path22.resolve(filePath);
34134
34407
  try {
34135
34408
  const metadata = await stat4(absolute);
34136
34409
  if (!metadata.isFile()) throw new Error("not a regular file");
@@ -34140,9 +34413,9 @@ async function existingFile(filePath, label) {
34140
34413
  return absolute;
34141
34414
  }
34142
34415
  async function discoverExecutable(name, environment) {
34143
- for (const directory of (environment.PATH ?? "").split(path21.delimiter)) {
34416
+ for (const directory of (environment.PATH ?? "").split(path22.delimiter)) {
34144
34417
  if (!directory) continue;
34145
- const candidate = path21.resolve(directory, name);
34418
+ const candidate = path22.resolve(directory, name);
34146
34419
  try {
34147
34420
  await access(candidate, fsConstants.X_OK);
34148
34421
  return candidate;
@@ -34153,10 +34426,10 @@ async function discoverExecutable(name, environment) {
34153
34426
  return null;
34154
34427
  }
34155
34428
  async function writeAtomic(filePath, contents, mode) {
34156
- await mkdir11(path21.dirname(filePath), { recursive: true, mode: 448 });
34157
- const temporary = path21.join(
34158
- path21.dirname(filePath),
34159
- `.${path21.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
34429
+ await mkdir11(path22.dirname(filePath), { recursive: true, mode: 448 });
34430
+ const temporary = path22.join(
34431
+ path22.dirname(filePath),
34432
+ `.${path22.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
34160
34433
  );
34161
34434
  try {
34162
34435
  if (typeof contents === "string") {
@@ -34177,10 +34450,10 @@ async function writeAtomic(filePath, contents, mode) {
34177
34450
  }
34178
34451
  }
34179
34452
  async function writeAtomicExecutable(filePath, sourcePath) {
34180
- await mkdir11(path21.dirname(filePath), { recursive: true, mode: 448 });
34181
- const temporary = path21.join(
34182
- path21.dirname(filePath),
34183
- `.${path21.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
34453
+ await mkdir11(path22.dirname(filePath), { recursive: true, mode: 448 });
34454
+ const temporary = path22.join(
34455
+ path22.dirname(filePath),
34456
+ `.${path22.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
34184
34457
  );
34185
34458
  try {
34186
34459
  await copyFile3(sourcePath, temporary);
@@ -34221,8 +34494,8 @@ function removeManagedProfileBlock(contents) {
34221
34494
  function installManagedProfileBlock(contents, manifest) {
34222
34495
  const base = removeManagedProfileBlock(contents);
34223
34496
  const environment = [
34224
- `export CODEX_INSTALL_DIR=${shellQuote(path21.dirname(manifest.wrapperPath))}`,
34225
- `export PATH=${shellQuote(path21.dirname(manifest.wrapperPath))}:${shellQuote(path21.dirname(manifest.nodePath))}:${shellQuote(path21.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
34497
+ `export CODEX_INSTALL_DIR=${shellQuote(path22.dirname(manifest.wrapperPath))}`,
34498
+ `export PATH=${shellQuote(path22.dirname(manifest.wrapperPath))}:${shellQuote(path22.dirname(manifest.nodePath))}:${shellQuote(path22.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
34226
34499
  `export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
34227
34500
  `export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
34228
34501
  `export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
@@ -34239,7 +34512,7 @@ function installManagedProfileBlock(contents, manifest) {
34239
34512
  PROFILE_END,
34240
34513
  ""
34241
34514
  ].join("\n");
34242
- if (path21.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
34515
+ if (path22.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
34243
34516
  const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
34244
34517
  return `${base}${separator}${block}`;
34245
34518
  }
@@ -34258,7 +34531,7 @@ ${WRAPPER_MARKER}
34258
34531
  return "legacy-wrapper";
34259
34532
  }
34260
34533
  if (manifest.entrypointSha256 !== void 0) {
34261
- return createHash7("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
34534
+ return createHash8("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
34262
34535
  }
34263
34536
  const shim = await readFile9(manifest.shimPath).catch((error51) => {
34264
34537
  if (error51.code === "ENOENT") return null;
@@ -34304,9 +34577,9 @@ async function readManifest(filePath) {
34304
34577
  ];
34305
34578
  const optionalPaths = ["claudeCommand", "profileBackupPath"];
34306
34579
  if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
34307
- (key) => typeof manifest[key] !== "string" || !path21.isAbsolute(manifest[key])
34580
+ (key) => typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key])
34308
34581
  ) || optionalPaths.some(
34309
- (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path21.isAbsolute(manifest[key]))
34582
+ (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key]))
34310
34583
  ) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
34311
34584
  throw new Error("Remote Host manifest has an unsupported format");
34312
34585
  }
@@ -34535,7 +34808,7 @@ async function uninstallRemoteHost(options2) {
34535
34808
  import { spawn as spawn5 } from "node:child_process";
34536
34809
  import { stat as stat5 } from "node:fs/promises";
34537
34810
  import net3 from "node:net";
34538
- import path22 from "node:path";
34811
+ import path23 from "node:path";
34539
34812
  import { Duplex } from "node:stream";
34540
34813
  var CODEXHOST_STATUS_METHOD = "codexhost/update/status";
34541
34814
  var DIRECT_PROBE_TIMEOUT_MS = 5e3;
@@ -34554,9 +34827,9 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
34554
34827
  }
34555
34828
  var lifecycleDependencyOverrides = {};
34556
34829
  function socketPathFor(environment) {
34557
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path22.join(environment.HOME, ".codex") : void 0);
34830
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path23.join(environment.HOME, ".codex") : void 0);
34558
34831
  if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
34559
- return path22.join(codexHome, "app-server-control", "app-server-control.sock");
34832
+ return path23.join(codexHome, "app-server-control", "app-server-control.sock");
34560
34833
  }
34561
34834
  async function defaultSocketExists(socketPath) {
34562
34835
  const metadata = await stat5(socketPath).catch((error51) => {
@@ -34683,7 +34956,7 @@ function installedManifest(status) {
34683
34956
  function managedEnvironment(manifest, environment) {
34684
34957
  return {
34685
34958
  ...environment,
34686
- CODEX_INSTALL_DIR: path22.dirname(manifest.wrapperPath),
34959
+ CODEX_INSTALL_DIR: path23.dirname(manifest.wrapperPath),
34687
34960
  CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
34688
34961
  CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
34689
34962
  CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
@@ -34691,7 +34964,7 @@ function managedEnvironment(manifest, environment) {
34691
34964
  CODEXHOST_DEFAULT_AGENT: "codex",
34692
34965
  CODEXHOST_REMOTE_SSH_MANAGED: "1",
34693
34966
  ...manifest.claudeCommand ? { CODEXHOST_CLAUDE_COMMAND: manifest.claudeCommand } : {},
34694
- PATH: `${path22.dirname(manifest.wrapperPath)}${path22.delimiter}${path22.dirname(manifest.stockCodexPath)}${path22.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
34967
+ PATH: `${path23.dirname(manifest.wrapperPath)}${path23.delimiter}${path23.dirname(manifest.stockCodexPath)}${path23.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
34695
34968
  };
34696
34969
  }
34697
34970
  async function defaultRunTerminator(manifest, socketPath, role, environment) {
@@ -34979,7 +35252,7 @@ var harnessBrokerServerFrameSchema = external_exports.union([
34979
35252
  var harnessBrokerDescriptorSchema = external_exports.object({
34980
35253
  schemaVersion: external_exports.literal(1),
34981
35254
  protocolVersion: external_exports.literal(HARNESS_BROKER_PROTOCOL_VERSION),
34982
- harnessId: external_exports.literal("claude-code"),
35255
+ harnessId: harnessPluginIdSchema,
34983
35256
  generation: external_exports.string().uuid(),
34984
35257
  ownerPid: external_exports.number().int().positive(),
34985
35258
  socketPath: external_exports.string().min(1).max(512),
@@ -35030,33 +35303,48 @@ function consumeBrokerFrames(socket, onFrame, onError) {
35030
35303
 
35031
35304
  // packages/harness-broker/dist/paths.js
35032
35305
  import os5 from "node:os";
35033
- import path23 from "node:path";
35306
+ import path24 from "node:path";
35034
35307
  var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
35035
35308
  var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
35036
35309
  var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
35037
35310
  function defaultHarnessBrokerDirectory(environment = process.env) {
35038
35311
  const home = environment.HOME || os5.homedir();
35039
- return path23.join(home, ".codexhost", "harness-broker");
35312
+ return path24.join(home, ".codexhost", "harness-broker");
35040
35313
  }
35041
- function defaultHarnessBrokerDescriptorPath(environment = process.env) {
35042
- return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path23.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
35314
+ function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
35315
+ harnessPluginIdSchema.parse(harnessId);
35316
+ if (harnessId !== "claude-code")
35317
+ return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
35318
+ return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
35043
35319
  }
35044
- function defaultHarnessBrokerSocketPath(environment = process.env) {
35045
- return path23.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
35320
+ function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
35321
+ harnessPluginIdSchema.parse(harnessId);
35322
+ if (harnessId !== "claude-code")
35323
+ return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
35324
+ return path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
35046
35325
  }
35047
35326
 
35048
35327
  // packages/harness-broker/dist/validation.js
35049
35328
  var cwdSchema = external_exports.string().min(1).max(16384);
35329
+ var brokerEnvironmentSchema = external_exports.object({
35330
+ CODEXHOST_CLI_PATH: external_exports.string().max(16384).optional(),
35331
+ CODEXHOST_RUNTIME_ENDPOINT: external_exports.string().max(16384).optional(),
35332
+ CODEXHOST_RUNTIME_TOKEN: external_exports.string().max(16384).optional(),
35333
+ CODEXHOST_THREAD_ID: external_exports.string().max(256).optional()
35334
+ }).strict();
35050
35335
  var createSchema = external_exports.object({
35051
35336
  kind: external_exports.literal("create"),
35052
35337
  cwd: cwdSchema,
35053
35338
  executionPolicy: external_exports.enum(["default", "unattended-full-access"]).optional(),
35339
+ environment: brokerEnvironmentSchema.optional(),
35054
35340
  model: harnessModelRefSchema.optional(),
35055
35341
  thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
35056
35342
  permissionModeId: harnessPermissionModeIdSchema.optional()
35057
35343
  }).strict();
35058
35344
  var resumeSchema = external_exports.object({
35059
35345
  kind: external_exports.literal("resume"),
35346
+ environment: brokerEnvironmentSchema.optional(),
35347
+ permissionModeId: harnessPermissionModeIdSchema.optional(),
35060
35348
  model: harnessModelRefSchema.optional(),
35061
35349
  thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
35062
35350
  nativeRef: nativeSessionRefSchema,
@@ -35065,12 +35353,14 @@ var resumeSchema = external_exports.object({
35065
35353
  }).strict();
35066
35354
  var forkSchema = external_exports.object({
35067
35355
  kind: external_exports.literal("fork"),
35356
+ environment: brokerEnvironmentSchema.optional(),
35068
35357
  sourceRef: nativeSessionRefSchema,
35069
35358
  checkpoint: nativeCheckpointRefSchema,
35070
35359
  cwd: cwdSchema
35071
35360
  }).strict();
35072
35361
  var rollbackSchema = external_exports.object({
35073
35362
  kind: external_exports.literal("rollbackLastTurn"),
35363
+ environment: brokerEnvironmentSchema.optional(),
35074
35364
  model: harnessModelRefSchema.optional(),
35075
35365
  thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
35076
35366
  permissionModeId: harnessPermissionModeIdSchema.optional(),
@@ -35244,10 +35534,10 @@ var harnessOutputSchema = external_exports.custom((value2) => {
35244
35534
  });
35245
35535
 
35246
35536
  // packages/harness-broker/dist/server.js
35247
- import { randomBytes as randomBytes2, randomUUID as randomUUID14 } from "node:crypto";
35537
+ import { randomBytes as randomBytes2, randomUUID as randomUUID15 } from "node:crypto";
35248
35538
  import { chmod as chmod5, lstat as lstat9, mkdir as mkdir12, open as open8, readFile as readFile10, rename as rename9, rm as rm11 } from "node:fs/promises";
35249
35539
  import net4, {} from "node:net";
35250
- import path24 from "node:path";
35540
+ import path25 from "node:path";
35251
35541
  function harnessError(message, retryable = true) {
35252
35542
  return { code: "unavailable", message, retryable, stage: "harnessBroker" };
35253
35543
  }
@@ -35303,7 +35593,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
35303
35593
  }
35304
35594
  }
35305
35595
  async function publishDescriptor(descriptorPath, descriptor) {
35306
- const temporary = `${descriptorPath}.${process.pid}.${randomUUID14()}.tmp`;
35596
+ const temporary = `${descriptorPath}.${process.pid}.${randomUUID15()}.tmp`;
35307
35597
  const handle = await open8(temporary, "wx", 384);
35308
35598
  try {
35309
35599
  await handle.writeFile(`${JSON.stringify(descriptor)}
@@ -35369,25 +35659,23 @@ async function prepareUnixSocketPath(socketPath) {
35369
35659
  }
35370
35660
  }
35371
35661
  async function startHarnessBrokerServer(input) {
35372
- if (input.adapter.harnessId !== "claude-code") {
35373
- throw new Error("Harness broker accepts only the claude-code adapter");
35374
- }
35375
- if (process.platform !== "win32" && path24.dirname(input.descriptorPath) !== path24.dirname(input.socketPath)) {
35662
+ harnessPluginIdSchema.parse(input.adapter.harnessId);
35663
+ if (process.platform !== "win32" && path25.dirname(input.descriptorPath) !== path25.dirname(input.socketPath)) {
35376
35664
  throw new Error("Harness broker descriptor and socket must share one private directory");
35377
35665
  }
35378
35666
  if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
35379
35667
  throw new Error("Harness broker Unix socket path is too long for macOS");
35380
35668
  }
35381
- await privateDirectory(path24.dirname(input.descriptorPath));
35669
+ await privateDirectory(path25.dirname(input.descriptorPath));
35382
35670
  await assertNoLiveDescriptor(input.descriptorPath);
35383
35671
  if (process.platform !== "win32")
35384
35672
  await prepareUnixSocketPath(input.socketPath);
35385
- const generation = input.generation ?? randomUUID14();
35673
+ const generation = input.generation ?? randomUUID15();
35386
35674
  const token = input.token ?? randomBytes2(32).toString("hex");
35387
35675
  const descriptor = {
35388
35676
  schemaVersion: 1,
35389
35677
  protocolVersion: HARNESS_BROKER_PROTOCOL_VERSION,
35390
- harnessId: "claude-code",
35678
+ harnessId: input.adapter.harnessId,
35391
35679
  generation,
35392
35680
  ownerPid: process.pid,
35393
35681
  socketPath: input.socketPath,
@@ -35400,7 +35688,7 @@ async function startHarnessBrokerServer(input) {
35400
35688
  let closed = false;
35401
35689
  const server = net4.createServer((socket) => {
35402
35690
  const state = {
35403
- id: randomUUID14(),
35691
+ id: randomUUID15(),
35404
35692
  socket,
35405
35693
  authenticated: false,
35406
35694
  inputSequence: 0,
@@ -35443,8 +35731,9 @@ async function startHarnessBrokerServer(input) {
35443
35731
  if (output.kind === "event" && output.event.type === "session.state.changed") {
35444
35732
  const state2 = output.event.state;
35445
35733
  const observedNativeId = state2.nativeRef?.nativeSessionId;
35446
- if (state2.nativeRef && record3.nativeRef && (record3.nativeRef.harnessId !== state2.nativeRef.harnessId || record3.nativeRef.nativeSessionId !== state2.nativeRef.nativeSessionId || record3.nativeRef.formatVersion !== state2.nativeRef.formatVersion)) {
35734
+ if (state2.nativeRef && (state2.nativeRef.harnessId !== input.adapter.harnessId || record3.nativeRef && (record3.nativeRef.harnessId !== state2.nativeRef.harnessId || record3.nativeRef.nativeSessionId !== state2.nativeRef.nativeSessionId || record3.nativeRef.formatVersion !== state2.nativeRef.formatVersion))) {
35447
35735
  record3.faulted = true;
35736
+ releaseProvisionalWriter(record3);
35448
35737
  await send({
35449
35738
  kind: "output",
35450
35739
  sessionId: record3.id,
@@ -35455,7 +35744,7 @@ async function startHarnessBrokerServer(input) {
35455
35744
  type: "session.faulted",
35456
35745
  error: {
35457
35746
  code: "protocolError",
35458
- message: "Native Claude Session identity changed after open",
35747
+ message: "Native Harness Session identity changed after open",
35459
35748
  retryable: false,
35460
35749
  stage: "harnessBroker.identity"
35461
35750
  }
@@ -35481,7 +35770,7 @@ async function startHarnessBrokerServer(input) {
35481
35770
  type: "session.faulted",
35482
35771
  error: {
35483
35772
  code: "sessionBusy",
35484
- message: "Native Claude Session already has an active writer",
35773
+ message: "Native Harness Session already has an active writer",
35485
35774
  retryable: true,
35486
35775
  stage: "harnessBroker.identity"
35487
35776
  }
@@ -35579,20 +35868,25 @@ async function startHarnessBrokerServer(input) {
35579
35868
  if (request.method === "adapter.subagent.readSnapshot") {
35580
35869
  const subagents = input.adapter.subagents;
35581
35870
  if (!subagents)
35582
- return { ok: false, error: harnessError("Claude subagents are unavailable", false) };
35583
- return subagents.readSnapshot(subagentReadSnapshotSchema.parse(request.params));
35871
+ return { ok: false, error: harnessError("Harness subagents are unavailable", false) };
35872
+ const params = subagentReadSnapshotSchema.parse(request.params);
35873
+ if (params.parent.harnessId !== input.adapter.harnessId)
35874
+ return { ok: false, error: protocolError("Subagent parent belongs to another Harness") };
35875
+ return subagents.readSnapshot(params);
35584
35876
  }
35585
35877
  if (request.method === "adapter.open") {
35586
35878
  const openInput = brokerOpenInputSchema.parse(request.params);
35587
35879
  const sourceRef = openInput.kind === "create" ? void 0 : openInput.kind === "resume" ? openInput.nativeRef : openInput.sourceRef;
35588
35880
  const sourceNativeId = sourceRef?.nativeSessionId;
35881
+ if (sourceRef && sourceRef.harnessId !== input.adapter.harnessId)
35882
+ return { ok: false, error: protocolError("Native Session belongs to another Harness") };
35589
35883
  const sourceKey = sourceNativeId ? nativeWriterKey(sourceNativeId) : void 0;
35590
35884
  if (sourceKey && nativeWriters.has(sourceKey)) {
35591
35885
  return {
35592
35886
  ok: false,
35593
35887
  error: {
35594
35888
  code: "sessionBusy",
35595
- message: "Native Claude Session already has an active writer",
35889
+ message: "Native Harness Session already has an active writer",
35596
35890
  retryable: true,
35597
35891
  stage: "harnessBroker.open"
35598
35892
  }
@@ -35603,13 +35897,13 @@ async function startHarnessBrokerServer(input) {
35603
35897
  ok: false,
35604
35898
  error: {
35605
35899
  code: "sessionBusy",
35606
- message: "Native Claude Session identity claim is already pending",
35900
+ message: "Native Harness Session identity claim is already pending",
35607
35901
  retryable: true,
35608
35902
  stage: "harnessBroker.open"
35609
35903
  }
35610
35904
  };
35611
35905
  }
35612
- const openReservation = randomUUID14();
35906
+ const openReservation = randomUUID15();
35613
35907
  if (sourceKey)
35614
35908
  nativeWriters.set(sourceKey, openReservation);
35615
35909
  const provisionalReservation = openInput.kind === "create" ? openReservation : void 0;
@@ -35637,6 +35931,14 @@ async function startHarnessBrokerServer(input) {
35637
35931
  return { ok: false, error: harnessError("Harness broker connection closed") };
35638
35932
  }
35639
35933
  const openedRef = opened.value.initialState.nativeRef;
35934
+ if (openedRef && openedRef.harnessId !== input.adapter.harnessId) {
35935
+ releaseOpenReservations();
35936
+ await opened.value.close().catch(() => void 0);
35937
+ return {
35938
+ ok: false,
35939
+ error: protocolError("Adapter opened a Session for another Harness")
35940
+ };
35941
+ }
35640
35942
  if (sourceRef && (!openedRef || openedRef.harnessId !== sourceRef.harnessId || openedRef.formatVersion !== sourceRef.formatVersion || openInput.kind === "resume" && openedRef.nativeSessionId !== sourceRef.nativeSessionId)) {
35641
35943
  releaseOpenReservations();
35642
35944
  await opened.value.close().catch(() => void 0);
@@ -35644,7 +35946,7 @@ async function startHarnessBrokerServer(input) {
35644
35946
  ok: false,
35645
35947
  error: {
35646
35948
  code: "protocolError",
35647
- message: "Native Claude Session identity did not match the requested open",
35949
+ message: "Native Harness Session identity did not match the requested open",
35648
35950
  retryable: false,
35649
35951
  stage: "harnessBroker.open"
35650
35952
  }
@@ -35660,7 +35962,7 @@ async function startHarnessBrokerServer(input) {
35660
35962
  ok: false,
35661
35963
  error: {
35662
35964
  code: "sessionBusy",
35663
- message: "Native Claude Session already has an active writer",
35965
+ message: "Native Harness Session already has an active writer",
35664
35966
  retryable: true,
35665
35967
  stage: "harnessBroker.open"
35666
35968
  }
@@ -35672,6 +35974,7 @@ async function startHarnessBrokerServer(input) {
35672
35974
  generation: 1,
35673
35975
  owner: state.id,
35674
35976
  cwd: openInput.cwd,
35977
+ ...openInput.environment ? { environment: openInput.environment } : {},
35675
35978
  ...nativeId ? { nativeId } : {},
35676
35979
  ...opened.value.initialState.nativeRef ? { nativeRef: opened.value.initialState.nativeRef } : {},
35677
35980
  ...nativeKey ? { writerKey: nativeKey } : {},
@@ -35712,7 +36015,7 @@ async function startHarnessBrokerServer(input) {
35712
36015
  ok: false,
35713
36016
  error: {
35714
36017
  code: "sessionBusy",
35715
- message: "Native Claude Session identity has not been claimed yet",
36018
+ message: "Native Harness Session identity has not been claimed yet",
35716
36019
  retryable: true,
35717
36020
  stage: "harnessBroker.identity"
35718
36021
  }
@@ -35789,7 +36092,7 @@ async function startHarnessBrokerServer(input) {
35789
36092
  ok: false,
35790
36093
  error: {
35791
36094
  code: "sessionBusy",
35792
- message: "Faulted Claude Session has no authoritative native identity",
36095
+ message: "Faulted Harness Session has no authoritative native identity",
35793
36096
  retryable: false,
35794
36097
  stage: "harnessBroker.reopen"
35795
36098
  }
@@ -35801,7 +36104,12 @@ async function startHarnessBrokerServer(input) {
35801
36104
  record4.forwarderEpoch += 1;
35802
36105
  await oldSession.close().catch(() => void 0);
35803
36106
  await oldOutputTask.catch(() => void 0);
35804
- const reopened = await input.adapter.open({ kind: "resume", cwd: record4.cwd, nativeRef });
36107
+ const reopened = await input.adapter.open({
36108
+ kind: "resume",
36109
+ cwd: record4.cwd,
36110
+ nativeRef,
36111
+ ...record4.environment ? { environment: record4.environment } : {}
36112
+ });
35805
36113
  if (!reopened.ok)
35806
36114
  return reopened;
35807
36115
  const reopenedRef = reopened.value.initialState.nativeRef;
@@ -35811,7 +36119,7 @@ async function startHarnessBrokerServer(input) {
35811
36119
  ok: false,
35812
36120
  error: {
35813
36121
  code: "protocolError",
35814
- message: "Claude Aqua broker reopen changed the native Session identity",
36122
+ message: "Aqua Harness broker reopen changed the native Session identity",
35815
36123
  retryable: false,
35816
36124
  stage: "harnessBroker.reopen"
35817
36125
  }
@@ -35875,7 +36183,7 @@ async function startHarnessBrokerServer(input) {
35875
36183
  }
35876
36184
  state.authenticated = true;
35877
36185
  state.inputSequence = 1;
35878
- await send({ kind: "response", id: randomUUID14(), ok: true, value: { ready: true } });
36186
+ await send({ kind: "response", id: randomUUID15(), ok: true, value: { ready: true } });
35879
36187
  return;
35880
36188
  }
35881
36189
  const parsed = harnessBrokerRequestSchema.safeParse(raw);
@@ -35948,15 +36256,16 @@ async function startHarnessBrokerServer(input) {
35948
36256
  }
35949
36257
 
35950
36258
  // packages/host-runtime/src/aqua-harness-broker.ts
35951
- async function runClaudeAquaHarnessBroker(environment = process.env) {
36259
+ async function runClaudeAquaHarnessBroker(environment = process.env, requestedHarnessId = "claude-code") {
36260
+ const harnessId = harnessPluginIdSchema.parse(requestedHarnessId);
35952
36261
  if (process.platform !== "darwin") {
35953
- throw new Error("Claude Aqua Harness broker is available only on macOS");
36262
+ throw new Error("Aqua Harness broker is available only on macOS");
35954
36263
  }
35955
36264
  const { pluginRoots, pluginContext } = installedHarnessPluginOptions(environment);
35956
36265
  const plugins = await loadHarnessPlugins({
35957
36266
  roots: pluginRoots,
35958
36267
  context: pluginContext,
35959
- onlyIds: /* @__PURE__ */ new Set(["claude-code"]),
36268
+ onlyIds: /* @__PURE__ */ new Set([harnessId]),
35960
36269
  warmup: false,
35961
36270
  diagnose: (diagnostic) => process.stderr.write(`Harness plugin: ${JSON.stringify(diagnostic)}
35962
36271
  `)
@@ -35969,19 +36278,19 @@ async function runClaudeAquaHarnessBroker(environment = process.env) {
35969
36278
  let server;
35970
36279
  try {
35971
36280
  server = await startHarnessBrokerServer({
35972
- descriptorPath: defaultHarnessBrokerDescriptorPath(environment),
35973
- socketPath: defaultHarnessBrokerSocketPath(environment),
36281
+ descriptorPath: defaultHarnessBrokerDescriptorPath(environment, harnessId),
36282
+ socketPath: defaultHarnessBrokerSocketPath(environment, harnessId),
35974
36283
  adapter
35975
36284
  });
35976
36285
  } catch (error51) {
35977
36286
  await adapter.close().catch(() => void 0);
35978
36287
  throw error51;
35979
36288
  }
35980
- process.title = "codexhost claude-code Aqua harness broker";
36289
+ process.title = `codexhost ${harnessId} Aqua harness broker`;
35981
36290
  process.stdout.write(
35982
36291
  `${JSON.stringify({
35983
36292
  method: "codexhost/harness-broker/ready",
35984
- params: { protocolVersion: 1, harnessId: "claude-code" }
36293
+ params: { protocolVersion: 1, harnessId }
35985
36294
  })}
35986
36295
  `
35987
36296
  );
@@ -36004,7 +36313,7 @@ async function runClaudeAquaHarnessBroker(environment = process.env) {
36004
36313
 
36005
36314
  // packages/host-runtime/src/release-main.ts
36006
36315
  var arguments_ = process.argv.slice(2);
36007
- process.exitCode = arguments_[0] === "--codexhost-delegation-cli" ? await runDelegationCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-harness-broker" ? await runClaudeAquaHarnessBroker(process.env) : arguments_[0] === "--codexhost-remote" ? await runRemoteHostCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-remote-control-bridge" ? await runRemoteControlAppServerBridge() : await runHostRuntime({
36316
+ process.exitCode = arguments_[0] === "--codexhost-delegation-cli" ? await runDelegationCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-harness-broker" ? await runClaudeAquaHarnessBroker(process.env, arguments_[1] ?? "claude-code") : arguments_[0] === "--codexhost-remote" ? await runRemoteHostCli({ arguments: arguments_.slice(1), environment: process.env }) : arguments_[0] === "--codexhost-remote-control-bridge" ? await runRemoteControlAppServerBridge() : await runHostRuntime({
36008
36317
  arguments: arguments_,
36009
36318
  environment: process.env,
36010
36319
  hostRuntimeUrl: import.meta.url