@liberseek/boft-cli-win32-arm64 0.6.6 → 0.6.8

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",
@@ -4283,7 +4283,7 @@ async function runDelegationCli(input) {
4283
4283
 
4284
4284
  // packages/host-runtime/src/run-host-runtime.ts
4285
4285
  import { randomBytes } from "node:crypto";
4286
- import path21 from "node:path";
4286
+ import path22 from "node:path";
4287
4287
  import { homedir } from "node:os";
4288
4288
  import { fileURLToPath as fileURLToPath2 } from "node:url";
4289
4289
 
@@ -4629,9 +4629,85 @@ function selectInstallerReleaseArtifact(release, target) {
4629
4629
  });
4630
4630
  }
4631
4631
 
4632
+ // packages/update-manager/dist/github-cli-release.js
4633
+ import { execFile } from "node:child_process";
4634
+ import path2 from "node:path";
4635
+ var GITHUB_LATEST_RELEASE_ENDPOINT = "repos/BytePioneer-AI/codex-host/releases/latest";
4636
+ var MAX_RELEASE_RESPONSE_BYTES = 1024 * 1024;
4637
+ var GITHUB_CLI_TIMEOUT_MS = 5e3;
4638
+ function defaultExecutableCandidates(environment, platform) {
4639
+ if (environment.CODEXHOST_GH_COMMAND)
4640
+ return [environment.CODEXHOST_GH_COMMAND];
4641
+ const candidates = ["gh"];
4642
+ if (platform === "darwin") {
4643
+ candidates.push("/opt/homebrew/bin/gh", "/usr/local/bin/gh");
4644
+ } else if (platform === "win32") {
4645
+ const programFiles = environment.ProgramFiles ?? environment.PROGRAMFILES;
4646
+ const localAppData = environment.LOCALAPPDATA;
4647
+ if (programFiles)
4648
+ candidates.push(path2.win32.join(programFiles, "GitHub CLI", "gh.exe"));
4649
+ if (localAppData) {
4650
+ candidates.push(path2.win32.join(localAppData, "Programs", "GitHub CLI", "gh.exe"));
4651
+ }
4652
+ } else {
4653
+ candidates.push("/usr/local/bin/gh", "/usr/bin/gh", "/snap/bin/gh");
4654
+ }
4655
+ return [...new Set(candidates.filter((candidate) => Boolean(candidate)))];
4656
+ }
4657
+ function runGitHubCli(executable2, arguments_2, options2) {
4658
+ return new Promise((resolve, reject) => {
4659
+ execFile(executable2, [...arguments_2], {
4660
+ encoding: "utf8",
4661
+ env: options2.environment,
4662
+ maxBuffer: MAX_RELEASE_RESPONSE_BYTES,
4663
+ timeout: GITHUB_CLI_TIMEOUT_MS,
4664
+ windowsHide: true,
4665
+ ...options2.signal ? { signal: options2.signal } : {}
4666
+ }, (error51, stdout) => {
4667
+ if (error51)
4668
+ reject(error51);
4669
+ else
4670
+ resolve(stdout);
4671
+ });
4672
+ });
4673
+ }
4674
+ async function fetchLatestGitHubReleaseWithGitHubCli(options2 = {}) {
4675
+ const environment = options2.environment ?? process.env;
4676
+ const platform = options2.platform ?? process.platform;
4677
+ const candidates = options2.executableCandidates ?? defaultExecutableCandidates(environment, platform);
4678
+ const run = options2.run ?? runGitHubCli;
4679
+ const arguments_2 = [
4680
+ "api",
4681
+ "--hostname",
4682
+ "github.com",
4683
+ "--method",
4684
+ "GET",
4685
+ "--header",
4686
+ "Accept: application/vnd.github+json",
4687
+ "--header",
4688
+ "X-GitHub-Api-Version: 2022-11-28",
4689
+ GITHUB_LATEST_RELEASE_ENDPOINT
4690
+ ];
4691
+ for (const executable2 of candidates) {
4692
+ options2.signal?.throwIfAborted();
4693
+ try {
4694
+ return parseLatestGitHubRelease(JSON.parse(await run(executable2, arguments_2, {
4695
+ environment,
4696
+ ...options2.signal ? { signal: options2.signal } : {}
4697
+ })));
4698
+ } catch (error51) {
4699
+ options2.signal?.throwIfAborted();
4700
+ const code = error51?.code;
4701
+ if (code !== "ENOENT" && code !== "EACCES")
4702
+ return null;
4703
+ }
4704
+ }
4705
+ return null;
4706
+ }
4707
+
4632
4708
  // packages/update-manager/dist/operation-state.js
4633
4709
  import { lstat as lstat2, mkdir, open, readFile as readFile2, readdir, rm, writeFile } from "node:fs/promises";
4634
- import path2 from "node:path";
4710
+ import path3 from "node:path";
4635
4711
  var LOCK_FILE = "active-update-v1.lock";
4636
4712
  var STATUS_FILE = "status-v1.json";
4637
4713
  var TERMINAL_PHASES = /* @__PURE__ */ new Set(["succeeded", "failed"]);
@@ -4646,12 +4722,12 @@ async function regularFile(filePath) {
4646
4722
  }
4647
4723
  }
4648
4724
  async function isUpdateOperationActive(stateDirectory) {
4649
- if (!path2.isAbsolute(stateDirectory))
4725
+ if (!path3.isAbsolute(stateDirectory))
4650
4726
  throw new Error("update state directory must be absolute");
4651
- return regularFile(path2.join(stateDirectory, LOCK_FILE));
4727
+ return regularFile(path3.join(stateDirectory, LOCK_FILE));
4652
4728
  }
4653
4729
  async function discoverLatestUpdateStatus(stateDirectory) {
4654
- if (!path2.isAbsolute(stateDirectory))
4730
+ if (!path3.isAbsolute(stateDirectory))
4655
4731
  throw new Error("update state directory must be absolute");
4656
4732
  let entries;
4657
4733
  try {
@@ -4665,7 +4741,7 @@ async function discoverLatestUpdateStatus(stateDirectory) {
4665
4741
  for (const entry of entries) {
4666
4742
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
4667
4743
  continue;
4668
- const statusPath = path2.join(stateDirectory, entry.name, STATUS_FILE);
4744
+ const statusPath = path3.join(stateDirectory, entry.name, STATUS_FILE);
4669
4745
  if (!await regularFile(statusPath))
4670
4746
  continue;
4671
4747
  try {
@@ -4693,8 +4769,8 @@ async function cleanupTerminalUpdateState(stateDirectory, options2 = {}) {
4693
4769
  for (const entry of entries) {
4694
4770
  if (!entry.isDirectory() || entry.isSymbolicLink() || !entry.name.startsWith("update-"))
4695
4771
  continue;
4696
- const directory = path2.join(stateDirectory, entry.name);
4697
- const statusPath = path2.join(directory, STATUS_FILE);
4772
+ const directory = path3.join(stateDirectory, entry.name);
4773
+ const statusPath = path3.join(directory, STATUS_FILE);
4698
4774
  try {
4699
4775
  const status = parseUpdateStatus(JSON.parse(await readFile2(statusPath, "utf8")));
4700
4776
  if (TERMINAL_PHASES.has(status.phase) && now - status.updatedAt > retentionSeconds) {
@@ -4705,10 +4781,10 @@ async function cleanupTerminalUpdateState(stateDirectory, options2 = {}) {
4705
4781
  }
4706
4782
  }
4707
4783
  async function acquireUpdateOperationLock(stateDirectory) {
4708
- if (!path2.isAbsolute(stateDirectory))
4784
+ if (!path3.isAbsolute(stateDirectory))
4709
4785
  throw new Error("update state directory must be absolute");
4710
4786
  await mkdir(stateDirectory, { recursive: true, mode: 448 });
4711
- const lockPath = path2.join(stateDirectory, LOCK_FILE);
4787
+ const lockPath = path3.join(stateDirectory, LOCK_FILE);
4712
4788
  let handle;
4713
4789
  try {
4714
4790
  handle = await open(lockPath, "wx", 384);
@@ -4727,9 +4803,9 @@ async function acquireUpdateOperationLock(stateDirectory) {
4727
4803
  async setStatusPath(statusPath) {
4728
4804
  if (released)
4729
4805
  throw new Error("update operation lock is released");
4730
- if (!path2.isAbsolute(statusPath))
4806
+ if (!path3.isAbsolute(statusPath))
4731
4807
  throw new Error("update status path must be absolute");
4732
- await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path2.normalize(statusPath) })}
4808
+ await writeFile(lockPath, `${JSON.stringify({ ownerPid: process.pid, statusPath: path3.normalize(statusPath) })}
4733
4809
  `, { encoding: "utf8", mode: 384 });
4734
4810
  },
4735
4811
  async release() {
@@ -4751,7 +4827,7 @@ function processIsAlive(processId) {
4751
4827
  }
4752
4828
  }
4753
4829
  async function recoverUpdateOperationLock(stateDirectory) {
4754
- const lockPath = path2.join(stateDirectory, LOCK_FILE);
4830
+ const lockPath = path3.join(stateDirectory, LOCK_FILE);
4755
4831
  if (!await regularFile(lockPath))
4756
4832
  return;
4757
4833
  let ownerPid;
@@ -4763,7 +4839,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
4763
4839
  } catch {
4764
4840
  return;
4765
4841
  }
4766
- if (typeof statusPath !== "string" || !path2.isAbsolute(statusPath))
4842
+ if (typeof statusPath !== "string" || !path3.isAbsolute(statusPath))
4767
4843
  return;
4768
4844
  try {
4769
4845
  const status = parseUpdateStatus(JSON.parse(await readFile2(statusPath, "utf8")));
@@ -4778,7 +4854,7 @@ async function recoverUpdateOperationLock(stateDirectory) {
4778
4854
  import { spawn } from "node:child_process";
4779
4855
  import { randomUUID } from "node:crypto";
4780
4856
  import { chmod, copyFile, lstat as lstat4, mkdir as mkdir2, readFile as readFile3, rename, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
4781
- import path3 from "node:path";
4857
+ import path4 from "node:path";
4782
4858
 
4783
4859
  // packages/update-manager/dist/artifact.js
4784
4860
  import { createHash } from "node:crypto";
@@ -4899,9 +4975,9 @@ async function replaceStatusFile(temporaryPath, statusPath) {
4899
4975
  }
4900
4976
  }
4901
4977
  function requireAbsolutePath(value2, label) {
4902
- if (!path3.isAbsolute(value2))
4978
+ if (!path4.isAbsolute(value2))
4903
4979
  throw new Error(`${label} must be an absolute path`);
4904
- return path3.normalize(value2);
4980
+ return path4.normalize(value2);
4905
4981
  }
4906
4982
  async function requireRegularFile(value2, label) {
4907
4983
  const filePath = requireAbsolutePath(value2, label);
@@ -4944,7 +5020,7 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
4944
5020
  const now = dependencies2.now ?? Date.now;
4945
5021
  const preparedRequests = /* @__PURE__ */ new Set();
4946
5022
  async function writeStatusSnapshot(statusPath, status) {
4947
- const temporaryPath = path3.join(path3.dirname(statusPath), `.update-status-${randomId()}.tmp`);
5023
+ const temporaryPath = path4.join(path4.dirname(statusPath), `.update-status-${randomId()}.tmp`);
4948
5024
  try {
4949
5025
  await writeFile2(temporaryPath, `${JSON.stringify(status)}
4950
5026
  `, {
@@ -5004,15 +5080,15 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
5004
5080
  const updaterExecutable = await requireRegularFile(options2.updaterExecutable, "Updater executable");
5005
5081
  const stateDirectory = requireAbsolutePath(options2.stateDirectory, "update state directory");
5006
5082
  await mkdir2(stateDirectory, { recursive: true, mode: 448 });
5007
- const workDirectory = path3.join(stateDirectory, `update-${version2}-${randomId()}`);
5083
+ const workDirectory = path4.join(stateDirectory, `update-${version2}-${randomId()}`);
5008
5084
  await mkdir2(workDirectory, { recursive: false, mode: 448 });
5009
5085
  const executableSuffix = platform === "win32" ? ".exe" : "";
5010
- const helperPath = path3.join(workDirectory, `boft-updater${executableSuffix}`);
5086
+ const helperPath = path4.join(workDirectory, `boft-updater${executableSuffix}`);
5011
5087
  await copyFile(updaterExecutable, helperPath);
5012
5088
  if (platform !== "win32")
5013
5089
  await chmod(helperPath, 448);
5014
- const requestPath = path3.join(workDirectory, "request-v1.json");
5015
- const statusPath = path3.join(workDirectory, "status-v1.json");
5090
+ const requestPath = path4.join(workDirectory, "request-v1.json");
5091
+ const statusPath = path4.join(workDirectory, "status-v1.json");
5016
5092
  await writePrivateJson(statusPath, preparedStatus(version2, installation, now()));
5017
5093
  await options2.onPrepared?.({ version: version2, installation, statusPath });
5018
5094
  return {
@@ -5028,8 +5104,8 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
5028
5104
  }
5029
5105
  async function prepareArtifact(common, installation, sourceValue, fileName) {
5030
5106
  const source = validateArtifact(sourceValue);
5031
- const temporaryPath = path3.join(common.workDirectory, `.${fileName}.download`);
5032
- const artifactPath = path3.join(common.workDirectory, fileName);
5107
+ const temporaryPath = path4.join(common.workDirectory, `.${fileName}.download`);
5108
+ const artifactPath = path4.join(common.workDirectory, fileName);
5033
5109
  const progress = progressReporter(common.statusPath, common.version, installation, source.size);
5034
5110
  try {
5035
5111
  const result = await download(source, temporaryPath, progress.update);
@@ -5103,7 +5179,7 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
5103
5179
  throw new Error("macOS DMG updates require macOS");
5104
5180
  const common = await prepareCommon(options2, "macos-dmg");
5105
5181
  const appPath = requireAbsolutePath(options2.appPath, "macOS application path");
5106
- if (path3.extname(appPath) !== ".app") {
5182
+ if (path4.extname(appPath) !== ".app") {
5107
5183
  throw new Error("macOS application path must end in .app");
5108
5184
  }
5109
5185
  const artifact = await prepareArtifact(common, "macos-dmg", options2.artifact, "update.dmg");
@@ -5138,7 +5214,7 @@ function createBackgroundUpdateManager(dependencies2 = {}) {
5138
5214
 
5139
5215
  // packages/host-runtime/src/account/codex-home-auth.ts
5140
5216
  import { readFile as readFile4 } from "node:fs/promises";
5141
- import path4 from "node:path";
5217
+ import path5 from "node:path";
5142
5218
  var CODEX_API_AUTH_IDENTITY_FALLBACK = "BANK OF TOKEN";
5143
5219
  function tomlUnquote(value2) {
5144
5220
  const trimmed = value2.trim();
@@ -5284,10 +5360,10 @@ function inspectCodexApiUsageSource(input) {
5284
5360
  return { baseUrl, apiKey };
5285
5361
  }
5286
5362
  async function inspectCodexHomeAuth(codexHome) {
5287
- const root = path4.resolve(codexHome);
5363
+ const root = path5.resolve(codexHome);
5288
5364
  const [configToml, authJson] = await Promise.all([
5289
- readOptionalUtf8(path4.join(root, "config.toml")),
5290
- readOptionalUtf8(path4.join(root, "auth.json"))
5365
+ readOptionalUtf8(path5.join(root, "config.toml")),
5366
+ readOptionalUtf8(path5.join(root, "auth.json"))
5291
5367
  ]);
5292
5368
  return inspectCodexAuthDocuments({
5293
5369
  ...configToml ? { configToml } : {},
@@ -5295,10 +5371,10 @@ async function inspectCodexHomeAuth(codexHome) {
5295
5371
  });
5296
5372
  }
5297
5373
  async function inspectCodexHomeApiUsageSource(codexHome, env = process.env) {
5298
- const root = path4.resolve(codexHome);
5374
+ const root = path5.resolve(codexHome);
5299
5375
  const [configToml, authJson] = await Promise.all([
5300
- readOptionalUtf8(path4.join(root, "config.toml")),
5301
- readOptionalUtf8(path4.join(root, "auth.json"))
5376
+ readOptionalUtf8(path5.join(root, "config.toml")),
5377
+ readOptionalUtf8(path5.join(root, "auth.json"))
5302
5378
  ]);
5303
5379
  return inspectCodexApiUsageSource({
5304
5380
  ...configToml ? { configToml } : {},
@@ -6142,10 +6218,10 @@ function mergeDefs(...defs) {
6142
6218
  function cloneDef(schema) {
6143
6219
  return mergeDefs(schema._zod.def);
6144
6220
  }
6145
- function getElementAtPath(obj, path26) {
6146
- if (!path26)
6221
+ function getElementAtPath(obj, path27) {
6222
+ if (!path27)
6147
6223
  return obj;
6148
- return path26.reduce((acc, key) => acc?.[key], obj);
6224
+ return path27.reduce((acc, key) => acc?.[key], obj);
6149
6225
  }
6150
6226
  function promiseAllObject(promisesObj) {
6151
6227
  const keys = Object.keys(promisesObj);
@@ -6554,11 +6630,11 @@ function explicitlyAborted(x, startIndex = 0) {
6554
6630
  }
6555
6631
  return false;
6556
6632
  }
6557
- function prefixIssues(path26, issues) {
6633
+ function prefixIssues(path27, issues) {
6558
6634
  return issues.map((iss) => {
6559
6635
  var _a3;
6560
6636
  (_a3 = iss).path ?? (_a3.path = []);
6561
- iss.path.unshift(path26);
6637
+ iss.path.unshift(path27);
6562
6638
  return iss;
6563
6639
  });
6564
6640
  }
@@ -6705,16 +6781,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
6705
6781
  }
6706
6782
  function formatError(error51, mapper = (issue2) => issue2.message) {
6707
6783
  const fieldErrors = { _errors: [] };
6708
- const processError = (error52, path26 = []) => {
6784
+ const processError = (error52, path27 = []) => {
6709
6785
  for (const issue2 of error52.issues) {
6710
6786
  if (issue2.code === "invalid_union" && issue2.errors.length) {
6711
- issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
6787
+ issue2.errors.map((issues) => processError({ issues }, [...path27, ...issue2.path]));
6712
6788
  } else if (issue2.code === "invalid_key") {
6713
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6789
+ processError({ issues: issue2.issues }, [...path27, ...issue2.path]);
6714
6790
  } else if (issue2.code === "invalid_element") {
6715
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6791
+ processError({ issues: issue2.issues }, [...path27, ...issue2.path]);
6716
6792
  } else {
6717
- const fullpath = [...path26, ...issue2.path];
6793
+ const fullpath = [...path27, ...issue2.path];
6718
6794
  if (fullpath.length === 0) {
6719
6795
  fieldErrors._errors.push(mapper(issue2));
6720
6796
  } else {
@@ -6741,17 +6817,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
6741
6817
  }
6742
6818
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
6743
6819
  const result = { errors: [] };
6744
- const processError = (error52, path26 = []) => {
6820
+ const processError = (error52, path27 = []) => {
6745
6821
  var _a3, _b;
6746
6822
  for (const issue2 of error52.issues) {
6747
6823
  if (issue2.code === "invalid_union" && issue2.errors.length) {
6748
- issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
6824
+ issue2.errors.map((issues) => processError({ issues }, [...path27, ...issue2.path]));
6749
6825
  } else if (issue2.code === "invalid_key") {
6750
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6826
+ processError({ issues: issue2.issues }, [...path27, ...issue2.path]);
6751
6827
  } else if (issue2.code === "invalid_element") {
6752
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6828
+ processError({ issues: issue2.issues }, [...path27, ...issue2.path]);
6753
6829
  } else {
6754
- const fullpath = [...path26, ...issue2.path];
6830
+ const fullpath = [...path27, ...issue2.path];
6755
6831
  if (fullpath.length === 0) {
6756
6832
  result.errors.push(mapper(issue2));
6757
6833
  continue;
@@ -6783,8 +6859,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
6783
6859
  }
6784
6860
  function toDotPath(_path) {
6785
6861
  const segs = [];
6786
- const path26 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6787
- for (const seg of path26) {
6862
+ const path27 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6863
+ for (const seg of path27) {
6788
6864
  if (typeof seg === "number")
6789
6865
  segs.push(`[${seg}]`);
6790
6866
  else if (typeof seg === "symbol")
@@ -19476,13 +19552,13 @@ function resolveRef(ref, ctx) {
19476
19552
  if (!ref.startsWith("#")) {
19477
19553
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
19478
19554
  }
19479
- const path26 = ref.slice(1).split("/").filter(Boolean);
19480
- if (path26.length === 0) {
19555
+ const path27 = ref.slice(1).split("/").filter(Boolean);
19556
+ if (path27.length === 0) {
19481
19557
  return ctx.rootSchema;
19482
19558
  }
19483
19559
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
19484
- if (path26[0] === defsKey) {
19485
- const key = path26[1];
19560
+ if (path27[0] === defsKey) {
19561
+ const key = path27[1];
19486
19562
  if (!key || !ctx.defs[key]) {
19487
19563
  throw new Error(`Reference not found: ${ref}`);
19488
19564
  }
@@ -20935,7 +21011,7 @@ import { execFileSync } from "node:child_process";
20935
21011
  import { randomUUID as randomUUID2 } from "node:crypto";
20936
21012
  import { constants } from "node:fs";
20937
21013
  import { copyFile as copyFile2, mkdir as mkdir3, open as open3, readFile as readFile5, readdir as readdir2, rename as rename2, rm as rm3, stat } from "node:fs/promises";
20938
- import path5 from "node:path";
21014
+ import path6 from "node:path";
20939
21015
 
20940
21016
  // packages/mapping-store/dist/records.js
20941
21017
  var nonBlankTextSchema6 = external_exports.string().refine((value2) => value2.trim().length > 0, {
@@ -21188,12 +21264,12 @@ var MappingStore = class {
21188
21264
  #initialized = false;
21189
21265
  #lockHandle = null;
21190
21266
  constructor(options2) {
21191
- this.#directory = path5.resolve(options2.directory);
21192
- this.#threadsDirectory = path5.join(this.#directory, "threads");
21193
- this.#delegationsDirectory = path5.join(this.#directory, "delegations");
21194
- this.#backupsDirectory = path5.join(this.#directory, "backups");
21195
- this.#quarantineDirectory = path5.join(this.#directory, "quarantine");
21196
- this.#lockPath = path5.join(this.#directory, "store.lock");
21267
+ this.#directory = path6.resolve(options2.directory);
21268
+ this.#threadsDirectory = path6.join(this.#directory, "threads");
21269
+ this.#delegationsDirectory = path6.join(this.#directory, "delegations");
21270
+ this.#backupsDirectory = path6.join(this.#directory, "backups");
21271
+ this.#quarantineDirectory = path6.join(this.#directory, "quarantine");
21272
+ this.#lockPath = path6.join(this.#directory, "store.lock");
21197
21273
  this.#instanceId = options2.instanceId ?? randomUUID2();
21198
21274
  this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
21199
21275
  this.#beforeReplace = options2.beforeReplace;
@@ -21212,8 +21288,8 @@ var MappingStore = class {
21212
21288
  await this.#cleanupResidue();
21213
21289
  const names = (await readdir2(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
21214
21290
  for (const name of names) {
21215
- const primary = path5.join(this.#threadsDirectory, name);
21216
- const backup = path5.join(this.#backupsDirectory, name);
21291
+ const primary = path6.join(this.#threadsDirectory, name);
21292
+ const backup = path6.join(this.#backupsDirectory, name);
21217
21293
  let record3 = null;
21218
21294
  try {
21219
21295
  record3 = await this.#readRecord(primary, name);
@@ -21222,7 +21298,7 @@ var MappingStore = class {
21222
21298
  record3 = await this.#readRecord(backup, name);
21223
21299
  await this.#replaceFile(primary, record3, false);
21224
21300
  } catch (backupError) {
21225
- const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
21301
+ const quarantine = path6.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
21226
21302
  await rename2(primary, quarantine).catch(() => void 0);
21227
21303
  void primaryError;
21228
21304
  void backupError;
@@ -21238,14 +21314,14 @@ var MappingStore = class {
21238
21314
  }
21239
21315
  const delegationNames = (await readdir2(this.#delegationsDirectory)).filter((name) => name.endsWith(".json"));
21240
21316
  for (const name of delegationNames) {
21241
- const file2 = path5.join(this.#delegationsDirectory, name);
21317
+ const file2 = path6.join(this.#delegationsDirectory, name);
21242
21318
  try {
21243
21319
  const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile5(file2, "utf8")));
21244
21320
  if (`${parsed.delegationId}.json` !== name)
21245
21321
  throw new Error("filename mismatch");
21246
21322
  this.#delegations.set(parsed.delegationId, parsed);
21247
21323
  } catch {
21248
- const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
21324
+ const quarantine = path6.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
21249
21325
  await rename2(file2, quarantine).catch(() => void 0);
21250
21326
  }
21251
21327
  }
@@ -21404,10 +21480,35 @@ var MappingStore = class {
21404
21480
  turnMappings: this.#mergeMappings(current.turnMappings, input.turnMappings ?? [])
21405
21481
  }));
21406
21482
  }
21483
+ // Keep native ref, Turn mappings and the indexed create request in one serialized
21484
+ // record mutation; separate setters could leave a child pointing at mixed Sessions.
21485
+ async rebindSubagentSession(input) {
21486
+ return this.#update(input.hostThreadId, (current) => {
21487
+ const parent = this.#records.get(input.parentHostThreadId);
21488
+ 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))
21489
+ throw new MappingStoreError("MAPPING_CONFLICT", "Subagent replacement must belong to its current parent Session");
21490
+ if (sameJson(current.nativeSessionRef, input.nativeSessionRef) && current.createRequestId === input.createRequestId)
21491
+ return null;
21492
+ if (!sameJson(current.nativeSessionRef, input.previousNativeSessionRef)) {
21493
+ throw new MappingStoreError("MAPPING_CONFLICT", "Subagent replacement source Session is stale");
21494
+ }
21495
+ const nativeSessionId = input.nativeSessionRef.nativeSessionId;
21496
+ return {
21497
+ ...current,
21498
+ createRequestId: input.createRequestId,
21499
+ nativeSessionRef: input.nativeSessionRef,
21500
+ turnMappings: current.turnMappings.map((mapping) => ({
21501
+ ...mapping,
21502
+ nativeTurnRef: { ...mapping.nativeTurnRef, nativeSessionId },
21503
+ ...mapping.nativeCheckpointRef ? { nativeCheckpointRef: { ...mapping.nativeCheckpointRef, nativeSessionId } } : {}
21504
+ }))
21505
+ };
21506
+ });
21507
+ }
21407
21508
  async replaceReadySession(input) {
21408
21509
  return this.#update(input.hostThreadId, (current) => {
21409
- 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)) {
21410
- throw new MappingStoreError("MAPPING_CONFLICT", "Ready Session replacement must retain an exact shorter derived prefix");
21510
+ 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)) {
21511
+ throw new MappingStoreError("MAPPING_CONFLICT", "Ready Session replacement must match the expected record and retain an exact shorter derived prefix");
21411
21512
  }
21412
21513
  return {
21413
21514
  ...current,
@@ -21419,8 +21520,8 @@ var MappingStore = class {
21419
21520
  }
21420
21521
  async replaceReadySessionAfterLastTurn(input) {
21421
21522
  return this.#update(input.hostThreadId, (current) => {
21422
- if (current.state !== "ready" || !current.nativeSessionRef || input.turnMappings.length !== current.turnMappings.length - 1 || input.turnMappings.some(({ hostTurnId }, index) => hostTurnId !== current.turnMappings[index]?.hostTurnId)) {
21423
- throw new MappingStoreError("MAPPING_CONFLICT", "Last-Turn Session replacement must retain the exact shorter Host Turn prefix");
21523
+ 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)) {
21524
+ throw new MappingStoreError("MAPPING_CONFLICT", "Last-Turn Session replacement must match the expected record and retain the exact shorter Host Turn prefix");
21424
21525
  }
21425
21526
  return {
21426
21527
  ...current,
@@ -21648,10 +21749,10 @@ var MappingStore = class {
21648
21749
  readdir2(this.#directory)
21649
21750
  ]);
21650
21751
  await Promise.all([
21651
- ...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#threadsDirectory, name), { force: true })),
21652
- ...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#delegationsDirectory, name), { force: true })),
21752
+ ...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path6.join(this.#threadsDirectory, name), { force: true })),
21753
+ ...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path6.join(this.#delegationsDirectory, name), { force: true })),
21653
21754
  // Renamed aside by #acquireLock; nothing reads them back, and they accumulate one per run.
21654
- ...rootNames.filter((name) => name.startsWith(`${path5.basename(this.#lockPath)}.stale-`)).map((name) => rm3(path5.join(this.#directory, name), { force: true }))
21755
+ ...rootNames.filter((name) => name.startsWith(`${path6.basename(this.#lockPath)}.stale-`)).map((name) => rm3(path6.join(this.#directory, name), { force: true }))
21655
21756
  ]);
21656
21757
  }
21657
21758
  async #acquireLock() {
@@ -21752,13 +21853,13 @@ var MappingStore = class {
21752
21853
  await next;
21753
21854
  }
21754
21855
  #recordPath(hostThreadId) {
21755
- return path5.join(this.#threadsDirectory, `${hostThreadId}.json`);
21856
+ return path6.join(this.#threadsDirectory, `${hostThreadId}.json`);
21756
21857
  }
21757
21858
  #delegationPath(delegationId) {
21758
- return path5.join(this.#delegationsDirectory, `${delegationId}.json`);
21859
+ return path6.join(this.#delegationsDirectory, `${delegationId}.json`);
21759
21860
  }
21760
21861
  #backupPath(hostThreadId) {
21761
- return path5.join(this.#backupsDirectory, `${hostThreadId}.json`);
21862
+ return path6.join(this.#backupsDirectory, `${hostThreadId}.json`);
21762
21863
  }
21763
21864
  #requireInitialized() {
21764
21865
  if (!this.#initialized) {
@@ -22519,8 +22620,8 @@ function projectFileChangeKind(kind) {
22519
22620
  return { type: kind };
22520
22621
  }
22521
22622
  function projectFileChanges(changes) {
22522
- return changes.map(({ path: path26, kind, unifiedDiff }) => ({
22523
- path: path26,
22623
+ return changes.map(({ path: path27, kind, unifiedDiff }) => ({
22624
+ path: path27,
22524
22625
  kind: projectFileChangeKind(kind),
22525
22626
  diff: unifiedDiff
22526
22627
  }));
@@ -22843,9 +22944,9 @@ function projectHistoricalTurn(input) {
22843
22944
  return [];
22844
22945
  }
22845
22946
  return item.type === "reasoning" ? [
22846
- projectItem(item, outcome, cwd, true, ""),
22947
+ projectItem(item, outcome, cwd, true, input.threadId ?? ""),
22847
22948
  projectReasoningTranscriptItem(item, outcome, cwd, item.durationMs ?? null)
22848
- ] : [projectItem(item, outcome, cwd, true, "")];
22949
+ ] : [projectItem(item, outcome, cwd, true, input.threadId ?? "")];
22849
22950
  })
22850
22951
  ],
22851
22952
  error: error51,
@@ -23478,13 +23579,13 @@ function decodeThreadForkRequest(request) {
23478
23579
  if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
23479
23580
  throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
23480
23581
  }
23481
- const path26 = optionalText(params, "path", { allowEmpty: true });
23582
+ const path27 = optionalText(params, "path", { allowEmpty: true });
23482
23583
  const ephemeral = optionalBoolean(params, "ephemeral");
23483
23584
  return {
23484
23585
  threadId: threadId3,
23485
23586
  ...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
23486
23587
  ...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
23487
- ...path26 ? { path: path26 } : {},
23588
+ ...path27 ? { path: path27 } : {},
23488
23589
  ...optionalField(params, "model"),
23489
23590
  ...optionalField(params, "modelProvider"),
23490
23591
  ...optionalField(params, "cwd"),
@@ -24495,18 +24596,149 @@ async function inspectHarnessAccounts(adapters, descriptors, timeoutMs = 12e3) {
24495
24596
  }
24496
24597
 
24497
24598
  // packages/host-runtime/src/app-server-host.ts
24498
- import { createHash as createHash5, randomUUID as randomUUID8 } from "node:crypto";
24599
+ import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
24499
24600
  import { rm as rm4 } from "node:fs/promises";
24500
24601
  import os2 from "node:os";
24501
- import path12 from "node:path";
24602
+ import path13 from "node:path";
24502
24603
 
24503
24604
  // packages/host-runtime/src/external-thread-fork.ts
24504
24605
  import nodePath from "node:path";
24505
24606
 
24506
24607
  // packages/host-runtime/src/external-thread-repository.ts
24507
- import { randomUUID as randomUUID3 } from "node:crypto";
24608
+ import { randomUUID as randomUUID4 } from "node:crypto";
24508
24609
  import os from "node:os";
24509
- import path6 from "node:path";
24610
+ import path7 from "node:path";
24611
+
24612
+ // packages/host-runtime/src/external-subagent-threads.ts
24613
+ import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
24614
+ function childCreateRequest(parent, nativeRef, id2) {
24615
+ const key = createHash3("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
24616
+ return `subagent:${key}`;
24617
+ }
24618
+ function subagentMaterializer(store, parent, previousParent) {
24619
+ if (previousParent && (previousParent.hostThreadId !== parent.hostThreadId || previousParent.harnessId !== parent.harnessId)) {
24620
+ throw new Error("Subagent Session replacement must stay in the same Host Thread");
24621
+ }
24622
+ const previousRef = previousParent?.nativeSessionRef;
24623
+ let legacy;
24624
+ const legacyRecords = () => legacy ??= store.listThreads().then((records) => {
24625
+ const byRequest = /* @__PURE__ */ new Map();
24626
+ const children = /* @__PURE__ */ new Map();
24627
+ for (const record3 of records) {
24628
+ if (!record3.subagent || record3.harnessId !== parent.harnessId || !record3.nativeSessionRef)
24629
+ continue;
24630
+ const owner = {
24631
+ hostThreadId: record3.subagent.parentHostThreadId,
24632
+ harnessId: record3.harnessId
24633
+ };
24634
+ const key = childCreateRequest(
24635
+ owner,
24636
+ record3.nativeSessionRef,
24637
+ record3.subagent.nativeSubagentId
24638
+ );
24639
+ if (!byRequest.has(key) || record3.state === "ready") byRequest.set(key, record3);
24640
+ const siblings = children.get(owner.hostThreadId) ?? [];
24641
+ siblings.push(record3);
24642
+ children.set(owner.hostThreadId, siblings);
24643
+ }
24644
+ return { byRequest, children };
24645
+ });
24646
+ const rebind = async (existing, owner, visited = /* @__PURE__ */ new Set()) => {
24647
+ if (!previousRef || !owner.nativeSessionRef || !existing.subagent || visited.has(existing.hostThreadId)) {
24648
+ throw new Error("Invalid retained Subagent Session tree");
24649
+ }
24650
+ visited.add(existing.hostThreadId);
24651
+ const rebound = await store.rebindSubagentSession({
24652
+ hostThreadId: existing.hostThreadId,
24653
+ parentHostThreadId: owner.hostThreadId,
24654
+ previousNativeSessionRef: previousRef,
24655
+ nativeSessionRef: owner.nativeSessionRef,
24656
+ createRequestId: childCreateRequest(
24657
+ owner,
24658
+ owner.nativeSessionRef,
24659
+ existing.subagent.nativeSubagentId
24660
+ )
24661
+ });
24662
+ for (const descendant of (await legacyRecords()).children.get(existing.hostThreadId) ?? []) {
24663
+ if (descendant.state === "ready" && descendant.nativeSessionRef?.nativeSessionId === previousRef.nativeSessionId) {
24664
+ await rebind(descendant, rebound, visited);
24665
+ }
24666
+ }
24667
+ return rebound;
24668
+ };
24669
+ return async (child) => {
24670
+ if (!child.nativeSubagentId || !parent.nativeSessionRef || parent.state !== "ready")
24671
+ return null;
24672
+ const nativeRef = parent.nativeSessionRef;
24673
+ const createRequestId = childCreateRequest(parent, nativeRef, child.nativeSubagentId);
24674
+ const previousRequest = previousRef && previousRef.nativeSessionId !== nativeRef.nativeSessionId ? childCreateRequest(parent, previousRef, child.nativeSubagentId) : void 0;
24675
+ let existing = await store.getThreadByCreateRequest(createRequestId);
24676
+ if (!existing && previousRequest)
24677
+ existing = await store.getThreadByCreateRequest(previousRequest);
24678
+ if (!existing) {
24679
+ const { byRequest } = await legacyRecords();
24680
+ existing = byRequest.get(createRequestId) ?? (previousRequest ? byRequest.get(previousRequest) : void 0) ?? null;
24681
+ }
24682
+ if (existing?.state === "ready") {
24683
+ if (existing.nativeSessionRef?.nativeSessionId === nativeRef.nativeSessionId) return existing;
24684
+ if (!previousRef) throw new Error("Subagent belongs to a different Native Session");
24685
+ return rebind(existing, parent);
24686
+ }
24687
+ const provisional = existing ?? await store.createProvisional({
24688
+ hostThreadId: hostThreadIdSchema.parse(randomUUID3()),
24689
+ createRequestId,
24690
+ harnessId: parent.harnessId,
24691
+ cwd: parent.cwd,
24692
+ title: child.description,
24693
+ transportModelId: parent.transportModelId,
24694
+ ephemeral: parent.ephemeral,
24695
+ historyMode: "paginated",
24696
+ subagent: {
24697
+ parentHostThreadId: parent.hostThreadId,
24698
+ nativeSubagentId: child.nativeSubagentId,
24699
+ ...child.role ? { role: child.role } : {}
24700
+ }
24701
+ });
24702
+ return provisional.state === "ready" ? provisional : store.commitReady({
24703
+ hostThreadId: provisional.hostThreadId,
24704
+ nativeSessionRef: nativeRef
24705
+ });
24706
+ };
24707
+ }
24708
+ async function materializeExternalSubagent(store, parent, child) {
24709
+ return subagentMaterializer(store, parent)(child);
24710
+ }
24711
+ async function projectExternalSnapshot(store, record3, snapshot, previousParent) {
24712
+ const materialize = subagentMaterializer(store, record3, previousParent);
24713
+ const turns = [];
24714
+ for (const [index, turn] of snapshot.turns.entries()) {
24715
+ const mapping = record3.turnMappings[index];
24716
+ if (!mapping) throw new Error("External Snapshot mapping is incomplete");
24717
+ const items = await Promise.all(
24718
+ turn.items.map(async (entry) => {
24719
+ if (entry.item.type !== "subagentDelegation") return entry;
24720
+ const subagents = await Promise.all(
24721
+ entry.item.subagents.map(async (child) => {
24722
+ const stored = await materialize(child);
24723
+ return stored ? { ...child, subagentId: stored.hostThreadId } : child;
24724
+ })
24725
+ );
24726
+ return { ...entry, item: { ...entry.item, subagents } };
24727
+ })
24728
+ );
24729
+ turns.push(
24730
+ projectHistoricalTurn({
24731
+ threadId: record3.hostThreadId,
24732
+ turnId: mapping.hostTurnId,
24733
+ cwd: record3.cwd,
24734
+ snapshot: { ...turn, items }
24735
+ })
24736
+ );
24737
+ }
24738
+ return turns;
24739
+ }
24740
+
24741
+ // packages/host-runtime/src/external-thread-repository.ts
24510
24742
  function nativeTurnKey2(ref) {
24511
24743
  return `${ref.harnessId}\0${ref.nativeSessionId}\0${ref.nativeTurnKey}\0${ref.formatVersion}`;
24512
24744
  }
@@ -24515,8 +24747,8 @@ function sameMapping(left, right) {
24515
24747
  }
24516
24748
  function defaultMappingStoreDirectory(environment) {
24517
24749
  const dataDirectory = environment.CODEXHOST_DATA_DIR;
24518
- return path6.join(
24519
- dataDirectory ? path6.resolve(dataDirectory) : path6.join(os.homedir(), ".codexhost"),
24750
+ return path7.join(
24751
+ dataDirectory ? path7.resolve(dataDirectory) : path7.join(os.homedir(), ".codexhost"),
24520
24752
  "mapping-store"
24521
24753
  );
24522
24754
  }
@@ -24541,6 +24773,9 @@ var ExternalThreadRepository = class {
24541
24773
  list() {
24542
24774
  return this.store.listThreads();
24543
24775
  }
24776
+ materializeSubagent(parent, child) {
24777
+ return materializeExternalSubagent(this.store, parent, child);
24778
+ }
24544
24779
  findByCreateRequest(createRequestId) {
24545
24780
  return this.store.getThreadByCreateRequest(createRequestId);
24546
24781
  }
@@ -24617,7 +24852,7 @@ var ExternalThreadRepository = class {
24617
24852
  throw new Error("Derived Snapshot identity does not belong to its Native Session");
24618
24853
  }
24619
24854
  return {
24620
- hostTurnId: hostTurnIdSchema.parse(randomUUID3()),
24855
+ hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
24621
24856
  nativeTurnRef: turn.nativeTurnRef,
24622
24857
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
24623
24858
  };
@@ -24629,15 +24864,7 @@ var ExternalThreadRepository = class {
24629
24864
  });
24630
24865
  return {
24631
24866
  record: nextRecord,
24632
- turns: snapshot.turns.map((turn, index) => {
24633
- const mapping = mappings[index];
24634
- if (!mapping) throw new Error("Derived Snapshot mapping is incomplete");
24635
- return projectHistoricalTurn({
24636
- turnId: mapping.hostTurnId,
24637
- cwd: record3.cwd,
24638
- snapshot: turn
24639
- });
24640
- })
24867
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot)
24641
24868
  };
24642
24869
  }
24643
24870
  async commitForkRollback(derived, source, nativeSessionRef, snapshot) {
@@ -24671,6 +24898,8 @@ var ExternalThreadRepository = class {
24671
24898
  });
24672
24899
  const nextRecord = await this.store.replaceReadySession({
24673
24900
  hostThreadId: derived.hostThreadId,
24901
+ expectedRevision: derived.revision,
24902
+ expectedNativeSessionRef: derived.nativeSessionRef,
24674
24903
  nativeSessionRef,
24675
24904
  turnMappings: mappings,
24676
24905
  forkSource: {
@@ -24680,15 +24909,7 @@ var ExternalThreadRepository = class {
24680
24909
  });
24681
24910
  return {
24682
24911
  record: nextRecord,
24683
- turns: snapshot.turns.map((turn, index) => {
24684
- const mapping = mappings[index];
24685
- if (!mapping) throw new Error("External rollback Snapshot mapping is incomplete");
24686
- return projectHistoricalTurn({
24687
- turnId: mapping.hostTurnId,
24688
- cwd: derived.cwd,
24689
- snapshot: turn
24690
- });
24691
- })
24912
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot, derived)
24692
24913
  };
24693
24914
  }
24694
24915
  async commitLastTurnRollback(current, nativeSessionRef, snapshot) {
@@ -24708,30 +24929,26 @@ var ExternalThreadRepository = class {
24708
24929
  });
24709
24930
  const nextRecord = await this.store.replaceReadySessionAfterLastTurn({
24710
24931
  hostThreadId: current.hostThreadId,
24932
+ expectedRevision: current.revision,
24933
+ expectedNativeSessionRef: current.nativeSessionRef,
24711
24934
  nativeSessionRef,
24712
24935
  turnMappings: mappings
24713
24936
  });
24714
24937
  return {
24715
24938
  record: nextRecord,
24716
- turns: snapshot.turns.map((turn, index) => {
24717
- const mapping = mappings[index];
24718
- if (!mapping) throw new Error("Last-Turn rollback Snapshot mapping is incomplete");
24719
- return projectHistoricalTurn({
24720
- turnId: mapping.hostTurnId,
24721
- cwd: current.cwd,
24722
- snapshot: turn
24723
- });
24724
- })
24939
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot, current)
24725
24940
  };
24726
24941
  }
24727
24942
  async sessionTreeId(record3) {
24728
24943
  let current = record3;
24729
24944
  const visited = /* @__PURE__ */ new Set();
24730
- while (current.forkSource) {
24945
+ while (current.subagent || current.forkSource) {
24731
24946
  if (visited.has(current.hostThreadId))
24732
24947
  throw new Error("External Thread Fork tree contains a cycle");
24733
24948
  visited.add(current.hostThreadId);
24734
- const source = await this.find(current.forkSource.hostThreadId);
24949
+ const parentId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
24950
+ if (!parentId) break;
24951
+ const source = await this.find(parentId);
24735
24952
  if (!source) break;
24736
24953
  current = source;
24737
24954
  }
@@ -24755,7 +24972,7 @@ var ExternalThreadRepository = class {
24755
24972
  const aligned = snapshot.turns.map((turn) => {
24756
24973
  const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
24757
24974
  const mapping = existing ?? {
24758
- hostTurnId: hostTurnIdSchema.parse(randomUUID3()),
24975
+ hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
24759
24976
  nativeTurnRef: turn.nativeTurnRef,
24760
24977
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
24761
24978
  };
@@ -24776,16 +24993,14 @@ var ExternalThreadRepository = class {
24776
24993
  const nextRecord = mappingsChanged ? await this.store.reconcileTurnMappings(record3.hostThreadId, orderedMappings) : record3;
24777
24994
  return {
24778
24995
  record: nextRecord,
24779
- turns: aligned.map(
24780
- ({ mapping, snapshot: turn }) => projectHistoricalTurn({ turnId: mapping.hostTurnId, cwd: record3.cwd, snapshot: turn })
24781
- )
24996
+ turns: await projectExternalSnapshot(this.store, nextRecord, snapshot)
24782
24997
  };
24783
24998
  }
24784
24999
  };
24785
25000
  function createExternalThreadRecordInput(input) {
24786
25001
  return {
24787
- hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID3()),
24788
- createRequestId: input.createRequestId ?? randomUUID3(),
25002
+ hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID4()),
25003
+ createRequestId: input.createRequestId ?? randomUUID4(),
24789
25004
  harnessId: input.harnessId,
24790
25005
  cwd: input.cwd,
24791
25006
  ...input.title ? { title: input.title } : {},
@@ -25463,13 +25678,14 @@ async function restoreCurrentConfiguration(session, configuration) {
25463
25678
  }
25464
25679
  async function executeCurrentLastTurnRollback(input) {
25465
25680
  const { current, adapters, repository, runtime } = input;
25466
- if (current.record.turnMappings.length === 0) {
25681
+ const currentRecord = current.record;
25682
+ if (currentRecord.turnMappings.length === 0) {
25467
25683
  return {
25468
25684
  ok: false,
25469
25685
  error: { code: -32076, message: "External Thread has no Turn to roll back" }
25470
25686
  };
25471
25687
  }
25472
- const currentNativeRef = current.record.nativeSessionRef;
25688
+ const currentNativeRef = currentRecord.nativeSessionRef;
25473
25689
  const adapter = adapters.get(current.harnessId);
25474
25690
  if (!currentNativeRef || !adapter) {
25475
25691
  return {
@@ -25517,7 +25733,7 @@ async function executeCurrentLastTurnRollback(input) {
25517
25733
  await session.close().catch(() => void 0);
25518
25734
  return { ok: false, error: mapExternalThreadHarnessError(snapshot.error, "read") };
25519
25735
  }
25520
- if (snapshot.value.turns.length !== current.record.turnMappings.length - 1) {
25736
+ if (snapshot.value.turns.length !== currentRecord.turnMappings.length - 1) {
25521
25737
  await session.close().catch(() => void 0);
25522
25738
  return {
25523
25739
  ok: false,
@@ -25535,7 +25751,7 @@ async function executeCurrentLastTurnRollback(input) {
25535
25751
  let aligned;
25536
25752
  try {
25537
25753
  aligned = await repository.commitLastTurnRollback(
25538
- current.record,
25754
+ currentRecord,
25539
25755
  finalNativeRef,
25540
25756
  snapshot.value
25541
25757
  );
@@ -25583,7 +25799,8 @@ async function executeExternalThreadRollback(input) {
25583
25799
  ...input.environment ? { environment: input.environment } : {}
25584
25800
  });
25585
25801
  }
25586
- const forkSource = derived.record.forkSource;
25802
+ const derivedRecord = derived.record;
25803
+ const forkSource = derivedRecord.forkSource;
25587
25804
  if (!forkSource) {
25588
25805
  return {
25589
25806
  ok: false,
@@ -25614,10 +25831,11 @@ async function executeExternalThreadRollback(input) {
25614
25831
  const sourceRefreshError = await runtime.refresh(source);
25615
25832
  if (sourceRefreshError) return { ok: false, error: sourceRefreshError };
25616
25833
  }
25617
- const sourceBoundaryIndex = source.record.turnMappings.findIndex(
25834
+ const sourceRecord = source.record;
25835
+ const sourceBoundaryIndex = sourceRecord.turnMappings.findIndex(
25618
25836
  ({ hostTurnId }) => hostTurnId === forkSource.hostTurnId
25619
25837
  );
25620
- if (sourceBoundaryIndex < 0 || derived.record.turnMappings.length !== sourceBoundaryIndex + 1) {
25838
+ if (sourceBoundaryIndex < 0 || derivedRecord.turnMappings.length !== sourceBoundaryIndex + 1) {
25621
25839
  return {
25622
25840
  ok: false,
25623
25841
  error: {
@@ -25626,19 +25844,19 @@ async function executeExternalThreadRollback(input) {
25626
25844
  }
25627
25845
  };
25628
25846
  }
25629
- const excludedActiveTurnCount = source.running || source.record.turnMappings.length > derived.record.turnMappings.length ? 1 : 0;
25630
- const retainedCount = derived.record.turnMappings.length - rollback.numTurns + excludedActiveTurnCount;
25631
- if (retainedCount === derived.record.turnMappings.length) {
25847
+ const excludedActiveTurnCount = source.running || sourceRecord.turnMappings.length > derivedRecord.turnMappings.length ? 1 : 0;
25848
+ const retainedCount = derivedRecord.turnMappings.length - rollback.numTurns + excludedActiveTurnCount;
25849
+ if (retainedCount === derivedRecord.turnMappings.length) {
25632
25850
  return { ok: true, thread: derived.thread };
25633
25851
  }
25634
- const boundary = source.record.turnMappings[retainedCount - 1];
25852
+ const boundary = sourceRecord.turnMappings[retainedCount - 1];
25635
25853
  if (retainedCount < 1 || !boundary?.nativeCheckpointRef) {
25636
25854
  return {
25637
25855
  ok: false,
25638
25856
  error: { code: -32080, message: "External Fork Checkpoint is unavailable" }
25639
25857
  };
25640
25858
  }
25641
- const sourceNativeRef = source.record.nativeSessionRef;
25859
+ const sourceNativeRef = sourceRecord.nativeSessionRef;
25642
25860
  const adapter = adapters.get(source.harnessId);
25643
25861
  if (!sourceNativeRef || !adapter) {
25644
25862
  return {
@@ -25666,7 +25884,7 @@ async function executeExternalThreadRollback(input) {
25666
25884
  }
25667
25885
  const session = opened.value;
25668
25886
  const finalNativeRef = session.initialState.nativeRef;
25669
- if (!finalNativeRef || finalNativeRef.nativeSessionId === sourceNativeRef.nativeSessionId || finalNativeRef.nativeSessionId === derived.record.nativeSessionRef?.nativeSessionId) {
25887
+ if (!finalNativeRef || finalNativeRef.nativeSessionId === sourceNativeRef.nativeSessionId || finalNativeRef.nativeSessionId === derivedRecord.nativeSessionRef?.nativeSessionId) {
25670
25888
  await session.close().catch(() => void 0);
25671
25889
  return {
25672
25890
  ok: false,
@@ -25688,8 +25906,8 @@ async function executeExternalThreadRollback(input) {
25688
25906
  let aligned;
25689
25907
  try {
25690
25908
  aligned = await repository.commitForkRollback(
25691
- derived.record,
25692
- source.record,
25909
+ derivedRecord,
25910
+ sourceRecord,
25693
25911
  finalNativeRef,
25694
25912
  snapshot.value
25695
25913
  );
@@ -25934,9 +26152,43 @@ var ExternalThreadRuntime = class {
25934
26152
  } catch (error51) {
25935
26153
  this.#diagnose(error51);
25936
26154
  }
26155
+ await this.#retireSubagents(current.id);
25937
26156
  this.#threads.delete(current.id);
25938
26157
  return this.register(input);
25939
26158
  }
26159
+ async #retireSubagents(parentId) {
26160
+ const ancestors = /* @__PURE__ */ new Map();
26161
+ const descendant = async (record3) => {
26162
+ const visited = /* @__PURE__ */ new Set();
26163
+ let ownerId = record3?.subagent?.parentHostThreadId;
26164
+ while (ownerId && !visited.has(ownerId)) {
26165
+ if (ownerId === parentId) return true;
26166
+ visited.add(ownerId);
26167
+ let ancestor = ancestors.get(ownerId);
26168
+ if (!ancestor) {
26169
+ ancestor = this.#repository.find(ownerId);
26170
+ ancestors.set(ownerId, ancestor);
26171
+ }
26172
+ ownerId = (await ancestor)?.subagent?.parentHostThreadId;
26173
+ }
26174
+ return false;
26175
+ };
26176
+ for (const [id2, restoring] of [...this.#restores]) {
26177
+ if (await descendant(await this.#repository.find(id2))) {
26178
+ await restoring.catch(this.#diagnose);
26179
+ }
26180
+ }
26181
+ for (const child of this.#threads.values()) {
26182
+ if (!await descendant(child.record)) continue;
26183
+ this.#threads.delete(child.id);
26184
+ try {
26185
+ await child.session.close();
26186
+ await child.outputTask;
26187
+ } catch (error51) {
26188
+ this.#diagnose(error51);
26189
+ }
26190
+ }
26191
+ }
25940
26192
  async locate(threadId3) {
25941
26193
  const loaded = this.#threads.get(threadId3);
25942
26194
  if (loaded) return { kind: "external", record: loaded.record, thread: loaded };
@@ -26047,6 +26299,10 @@ var ExternalThreadRuntime = class {
26047
26299
  nativeSubagentId: subagent.nativeSubagentId,
26048
26300
  cwd: record3.cwd
26049
26301
  });
26302
+ const latest = await this.#repository.find(record3.hostThreadId);
26303
+ if (latest?.state === "ready" && latest.nativeSessionRef && JSON.stringify(latest.nativeSessionRef) !== JSON.stringify(parent)) {
26304
+ return this.#restore(latest);
26305
+ }
26050
26306
  if (!snapshot.ok) {
26051
26307
  throw new ExternalThreadOpenError(mapExternalThreadHarnessError(snapshot.error, "read"));
26052
26308
  }
@@ -26323,11 +26579,11 @@ var ExternalTurnSteering = class {
26323
26579
  };
26324
26580
 
26325
26581
  // packages/host-runtime/src/harness-delegation-coordinator.ts
26326
- import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
26327
- import path7 from "node:path";
26582
+ import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
26583
+ import path8 from "node:path";
26328
26584
 
26329
26585
  // packages/host-runtime/src/delegation-snapshot.ts
26330
- import { createHash as createHash3 } from "node:crypto";
26586
+ import { createHash as createHash4 } from "node:crypto";
26331
26587
  var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
26332
26588
  var DEFAULT_MESSAGE_LIMIT = 25;
26333
26589
  var MAX_MESSAGE_LIMIT = 100;
@@ -26381,7 +26637,7 @@ function allVisibleMessages(turns) {
26381
26637
  return messages;
26382
26638
  }
26383
26639
  function cursorFingerprint(threadId3) {
26384
- return createHash3("sha256").update(threadId3).digest("hex");
26640
+ return createHash4("sha256").update(threadId3).digest("hex");
26385
26641
  }
26386
26642
  function encodeCursor(threadId3, offset) {
26387
26643
  const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId3), offset });
@@ -26492,10 +26748,10 @@ function terminal(status) {
26492
26748
  return status === "completed" || status === "failed" || status === "interrupted";
26493
26749
  }
26494
26750
  function taskDigest(input) {
26495
- return createHash4("sha256").update(
26751
+ return createHash5("sha256").update(
26496
26752
  JSON.stringify({
26497
26753
  task: input.task,
26498
- cwd: path7.resolve(input.cwd),
26754
+ cwd: path8.resolve(input.cwd),
26499
26755
  modelId: input.model?.id ?? null,
26500
26756
  thinkingOptionId: input.thinkingOptionId ?? null
26501
26757
  })
@@ -26566,7 +26822,7 @@ var HarnessDelegationCoordinator = class {
26566
26822
  return {
26567
26823
  harnessId: input.harnessId,
26568
26824
  inspection: await adapter.inspect({
26569
- ...input.cwd ? { cwd: path7.resolve(input.cwd) } : {},
26825
+ ...input.cwd ? { cwd: path8.resolve(input.cwd) } : {},
26570
26826
  ...input.refresh !== void 0 ? { refresh: input.refresh } : {}
26571
26827
  })
26572
26828
  };
@@ -26580,7 +26836,7 @@ var HarnessDelegationCoordinator = class {
26580
26836
  const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
26581
26837
  return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
26582
26838
  }
26583
- const startInput = { ...input, parentThreadId, cwd: path7.resolve(selectedCwd) };
26839
+ const startInput = { ...input, parentThreadId, cwd: path8.resolve(selectedCwd) };
26584
26840
  if (!this.#adapters.has(input.harnessId)) {
26585
26841
  throw new DelegationControlError(
26586
26842
  "HARNESS_NOT_FOUND",
@@ -26620,10 +26876,10 @@ var HarnessDelegationCoordinator = class {
26620
26876
  });
26621
26877
  this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
26622
26878
  }
26623
- const delegationId = hostThreadIdSchema.parse(randomUUID4());
26624
- const childThreadId = hostThreadIdSchema.parse(randomUUID4());
26625
- const turnId = hostTurnIdSchema.parse(randomUUID4());
26626
- const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID4();
26879
+ const delegationId = hostThreadIdSchema.parse(randomUUID5());
26880
+ const childThreadId = hostThreadIdSchema.parse(randomUUID5());
26881
+ const turnId = hostTurnIdSchema.parse(randomUUID5());
26882
+ const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID5();
26627
26883
  let record3 = await this.#repository.createProvisional(
26628
26884
  createExternalThreadRecordInput({
26629
26885
  hostThreadId: childThreadId,
@@ -26748,7 +27004,7 @@ var HarnessDelegationCoordinator = class {
26748
27004
  if (thread.running || thread.activeTurnId) {
26749
27005
  throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
26750
27006
  }
26751
- const turnId = hostTurnIdSchema.parse(randomUUID4());
27007
+ const turnId = hostTurnIdSchema.parse(randomUUID5());
26752
27008
  try {
26753
27009
  await this.#startExternalTurn(thread, input.message, turnId);
26754
27010
  } catch (error51) {
@@ -26993,7 +27249,7 @@ var HarnessDelegationCoordinator = class {
26993
27249
 
26994
27250
  // packages/host-runtime/src/harness-plugin-loader.ts
26995
27251
  import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
26996
- import path9 from "node:path";
27252
+ import path10 from "node:path";
26997
27253
  import { pathToFileURL } from "node:url";
26998
27254
 
26999
27255
  // packages/host-runtime/src/harness-plugin-registry.ts
@@ -27031,16 +27287,16 @@ var HarnessPluginRegistry = class {
27031
27287
 
27032
27288
  // packages/host-runtime/src/plugin-files.ts
27033
27289
  import { open as open4, realpath, stat as stat2 } from "node:fs/promises";
27034
- import path8 from "node:path";
27290
+ import path9 from "node:path";
27035
27291
  function inside(root, candidate) {
27036
- const relative = path8.relative(root, candidate);
27037
- return relative !== "" && !path8.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path8.sep}`);
27292
+ const relative = path9.relative(root, candidate);
27293
+ return relative !== "" && !path9.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path9.sep}`);
27038
27294
  }
27039
27295
  async function pluginResourcePath(root, relative) {
27040
- if (path8.isAbsolute(relative) || !inside(root, path8.resolve(root, relative))) {
27296
+ if (path9.isAbsolute(relative) || !inside(root, path9.resolve(root, relative))) {
27041
27297
  throw new Error("Plugin resource escapes its root");
27042
27298
  }
27043
- const resolved = await realpath(path8.resolve(root, relative));
27299
+ const resolved = await realpath(path9.resolve(root, relative));
27044
27300
  if (!inside(root, resolved) || !(await stat2(resolved)).isFile()) {
27045
27301
  throw new Error("Plugin resource must be a regular file inside its root");
27046
27302
  }
@@ -27185,7 +27441,7 @@ async function loadHarnessPlugins(options2) {
27185
27441
  const enabledIds = /* @__PURE__ */ new Set();
27186
27442
  const roots = /* @__PURE__ */ new Set();
27187
27443
  for (const configuredRoot of options2.roots) {
27188
- if (!path9.isAbsolute(configuredRoot)) {
27444
+ if (!path10.isAbsolute(configuredRoot)) {
27189
27445
  diagnose({ code: "invalidRoot" });
27190
27446
  continue;
27191
27447
  }
@@ -27215,7 +27471,7 @@ async function loadHarnessPlugins(options2) {
27215
27471
  for (const directory of directories) {
27216
27472
  try {
27217
27473
  const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
27218
- const pluginRoot = await realpath2(path9.join(root, directory.name));
27474
+ const pluginRoot = await realpath2(path10.join(root, directory.name));
27219
27475
  await pluginResourcePath(pluginRoot, "manifest.json");
27220
27476
  const manifest = harnessPluginManifestSchema.parse(
27221
27477
  JSON.parse(
@@ -27362,8 +27618,8 @@ function spawnOfficialAppServerConnection(input) {
27362
27618
 
27363
27619
  // packages/host-runtime/src/account/account-repository.ts
27364
27620
  import { mkdir as mkdir4, readFile as readFile6, rename as rename3, writeFile as writeFile3 } from "node:fs/promises";
27365
- import path10 from "node:path";
27366
- import { randomUUID as randomUUID5 } from "node:crypto";
27621
+ import path11 from "node:path";
27622
+ import { randomUUID as randomUUID6 } from "node:crypto";
27367
27623
  function validateAccountId(accountId) {
27368
27624
  if (!/^[A-Za-z0-9._~-]+$/u.test(accountId)) {
27369
27625
  throw new Error("Codex Account ID must be non-empty and filename-safe");
@@ -27381,19 +27637,19 @@ var AccountRepository = class {
27381
27637
  #mutationTail = Promise.resolve();
27382
27638
  #writeTail = Promise.resolve();
27383
27639
  constructor(input) {
27384
- this.#file = path10.join(path10.resolve(input.directory), "accounts.json");
27640
+ this.#file = path11.join(path11.resolve(input.directory), "accounts.json");
27385
27641
  this.#defaultAccount = {
27386
27642
  ...input.defaultAccount,
27387
27643
  label: input.defaultAccount.label ?? input.defaultAccount.accountId
27388
27644
  };
27389
27645
  validateAccountId(this.#defaultAccount.accountId);
27390
- if (!path10.isAbsolute(this.#defaultAccount.codexHome)) {
27646
+ if (!path11.isAbsolute(this.#defaultAccount.codexHome)) {
27391
27647
  throw new Error("Codex Account CODEX_HOME must be absolute");
27392
27648
  }
27393
27649
  }
27394
27650
  async initialize() {
27395
27651
  if (this.#initialized) return;
27396
- await mkdir4(path10.dirname(this.#file), { recursive: true });
27652
+ await mkdir4(path11.dirname(this.#file), { recursive: true });
27397
27653
  let stored = null;
27398
27654
  try {
27399
27655
  stored = JSON.parse(await readFile6(this.#file, "utf8"));
@@ -27461,7 +27717,7 @@ var AccountRepository = class {
27461
27717
  async upsert(input) {
27462
27718
  this.#requireInitialized();
27463
27719
  validateAccountId(input.accountId);
27464
- if (!path10.isAbsolute(input.codexHome))
27720
+ if (!path11.isAbsolute(input.codexHome))
27465
27721
  throw new Error("Codex Account CODEX_HOME must be absolute");
27466
27722
  return this.#mutate(async () => {
27467
27723
  const previous = this.#accounts.get(input.accountId);
@@ -27470,7 +27726,7 @@ var AccountRepository = class {
27470
27726
  const planType = input.planType === null ? void 0 : input.planType ?? previous?.planType;
27471
27727
  const account = {
27472
27728
  accountId: input.accountId,
27473
- codexHome: path10.normalize(input.codexHome),
27729
+ codexHome: path11.normalize(input.codexHome),
27474
27730
  ...email3 ? { email: email3 } : {},
27475
27731
  ...planType ? { planType } : {},
27476
27732
  label: input.label ?? previous?.label ?? input.accountId,
@@ -27484,7 +27740,7 @@ var AccountRepository = class {
27484
27740
  }
27485
27741
  #validateAccount(account) {
27486
27742
  validateAccountId(account.accountId);
27487
- if (!path10.isAbsolute(account.codexHome)) throw new Error("Stored CODEX_HOME must be absolute");
27743
+ if (!path11.isAbsolute(account.codexHome)) throw new Error("Stored CODEX_HOME must be absolute");
27488
27744
  if (account.email && (!account.email.includes("@") || account.email.length > 320)) {
27489
27745
  throw new Error("Stored Codex Account email is invalid");
27490
27746
  }
@@ -27505,7 +27761,7 @@ var AccountRepository = class {
27505
27761
  accounts: [...this.#accounts.values()]
27506
27762
  };
27507
27763
  const operation = this.#writeTail.then(async () => {
27508
- const temporary = `${this.#file}.${process.pid}.${randomUUID5()}.tmp`;
27764
+ const temporary = `${this.#file}.${process.pid}.${randomUUID6()}.tmp`;
27509
27765
  await writeFile3(temporary, `${JSON.stringify(value2, null, 2)}
27510
27766
  `, { mode: 384 });
27511
27767
  await rename3(temporary, this.#file);
@@ -27528,19 +27784,19 @@ function isMissingFile(error51) {
27528
27784
 
27529
27785
  // packages/host-runtime/src/account/thread-account-store.ts
27530
27786
  import { mkdir as mkdir5, readFile as readFile7, rename as rename4, writeFile as writeFile4 } from "node:fs/promises";
27531
- import { randomUUID as randomUUID6 } from "node:crypto";
27532
- import path11 from "node:path";
27787
+ import { randomUUID as randomUUID7 } from "node:crypto";
27788
+ import path12 from "node:path";
27533
27789
  var ThreadAccountStore = class {
27534
27790
  #file;
27535
27791
  #bindings = /* @__PURE__ */ new Map();
27536
27792
  #initialized = false;
27537
27793
  #writeTail = Promise.resolve();
27538
27794
  constructor(input) {
27539
- this.#file = path11.join(path11.resolve(input.directory), "thread-accounts.json");
27795
+ this.#file = path12.join(path12.resolve(input.directory), "thread-accounts.json");
27540
27796
  }
27541
27797
  async initialize() {
27542
27798
  if (this.#initialized) return;
27543
- await mkdir5(path11.dirname(this.#file), { recursive: true });
27799
+ await mkdir5(path12.dirname(this.#file), { recursive: true });
27544
27800
  try {
27545
27801
  const stored = JSON.parse(await readFile7(this.#file, "utf8"));
27546
27802
  if (stored.formatVersion !== 1 || !stored.bindings || typeof stored.bindings !== "object") {
@@ -27599,7 +27855,7 @@ var ThreadAccountStore = class {
27599
27855
  bindings: Object.fromEntries(this.#bindings)
27600
27856
  };
27601
27857
  const operation = this.#writeTail.then(async () => {
27602
- const temporary = `${this.#file}.${process.pid}.${randomUUID6()}.tmp`;
27858
+ const temporary = `${this.#file}.${process.pid}.${randomUUID7()}.tmp`;
27603
27859
  await writeFile4(temporary, `${JSON.stringify(value2, null, 2)}
27604
27860
  `, { mode: 384 });
27605
27861
  await rename4(temporary, this.#file);
@@ -27616,7 +27872,7 @@ function isMissingFile2(error51) {
27616
27872
  import { mkdir as mkdir6 } from "node:fs/promises";
27617
27873
 
27618
27874
  // packages/host-runtime/src/official-request-broker.ts
27619
- import { randomUUID as randomUUID7 } from "node:crypto";
27875
+ import { randomUUID as randomUUID8 } from "node:crypto";
27620
27876
  var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
27621
27877
  var MAX_RETIRED_IDS = 1024;
27622
27878
  function isRecord10(value2) {
@@ -27632,7 +27888,7 @@ var OfficialRequestBroker = class {
27632
27888
  constructor(input) {
27633
27889
  this.#send = input.send;
27634
27890
  this.#timeoutMs = input.timeoutMs ?? 3e4;
27635
- this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID7()}`);
27891
+ this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
27636
27892
  }
27637
27893
  get pendingCount() {
27638
27894
  return this.#pending.size;
@@ -27996,21 +28252,45 @@ function externalAnchor(entry) {
27996
28252
  if (entry.source !== "external") throw new Error("Expected an External Thread list entry");
27997
28253
  return { timestamp: entry.timestamp, threadId: threadId(entry.thread) };
27998
28254
  }
27999
- function includesExternalRecord(record3, query) {
28255
+ function includesExternalRecord(record3, query, byId) {
28000
28256
  if (record3.state !== "ready" || !record3.nativeSessionRef) return false;
28001
- if (record3.subagent) return false;
28257
+ let current = record3;
28258
+ const owners = /* @__PURE__ */ new Set();
28259
+ while (current.subagent) {
28260
+ if (owners.has(current.hostThreadId)) return false;
28261
+ owners.add(current.hostThreadId);
28262
+ const parent = byId.get(current.subagent.parentHostThreadId);
28263
+ if (!parent || parent.state !== "ready" || parent.harnessId !== current.harnessId || parent.nativeSessionRef?.nativeSessionId !== current.nativeSessionRef?.nativeSessionId)
28264
+ return false;
28265
+ current = parent;
28266
+ }
28267
+ const sourceKind = record3.subagent ? "subAgentThreadSpawn" : "vscode";
28268
+ const scoped = query.parentThreadId !== null || query.ancestorThreadId !== null;
28269
+ if (record3.subagent && !scoped && !query.sourceKinds?.some((kind) => kind === "subAgent" || kind === "subAgentThreadSpawn"))
28270
+ return false;
28271
+ if (query.parentThreadId !== null && record3.subagent?.parentHostThreadId !== query.parentThreadId)
28272
+ return false;
28273
+ if (query.ancestorThreadId !== null) {
28274
+ let parentId = record3.subagent?.parentHostThreadId;
28275
+ const visited = /* @__PURE__ */ new Set([record3.hostThreadId]);
28276
+ while (parentId && parentId !== query.ancestorThreadId && !visited.has(parentId)) {
28277
+ visited.add(parentId);
28278
+ parentId = byId.get(parentId)?.subagent?.parentHostThreadId;
28279
+ }
28280
+ if (record3.hostThreadId === query.ancestorThreadId || parentId !== query.ancestorThreadId)
28281
+ return false;
28282
+ }
28002
28283
  if (record3.archived !== query.archived) return false;
28003
28284
  if (query.cwd !== null && !query.cwd.includes(record3.cwd)) return false;
28004
28285
  if (query.modelProviders !== null && query.modelProviders.length > 0 && !query.modelProviders.includes("codexhost")) {
28005
28286
  return false;
28006
28287
  }
28007
- if (query.sourceKinds !== null && query.sourceKinds.length > 0 && !query.sourceKinds.includes("vscode")) {
28288
+ if (query.sourceKinds !== null && query.sourceKinds.length > 0 && !query.sourceKinds.includes(sourceKind) && !(record3.subagent && query.sourceKinds.includes("subAgent"))) {
28008
28289
  return false;
28009
28290
  }
28010
28291
  if (query.searchTerm !== null && !record3.title.toLowerCase().includes(query.searchTerm.toLowerCase())) {
28011
28292
  return false;
28012
28293
  }
28013
- if (query.parentThreadId !== null || query.ancestorThreadId !== null) return false;
28014
28294
  if (query.isPinned !== null && record3.isPinned !== query.isPinned) return false;
28015
28295
  return true;
28016
28296
  }
@@ -28020,25 +28300,25 @@ function resolveExternalSessionTreeIds(records) {
28020
28300
  const resolve = (start) => {
28021
28301
  const cached2 = resolved.get(start.hostThreadId);
28022
28302
  if (cached2) return cached2;
28023
- const path26 = [];
28303
+ const path27 = [];
28024
28304
  const visited = /* @__PURE__ */ new Set();
28025
28305
  let current = start;
28026
28306
  while (true) {
28027
28307
  const known = resolved.get(current.hostThreadId);
28028
28308
  if (known) {
28029
- for (const record3 of path26) resolved.set(record3.hostThreadId, known);
28309
+ for (const record3 of path27) resolved.set(record3.hostThreadId, known);
28030
28310
  return known;
28031
28311
  }
28032
28312
  if (visited.has(current.hostThreadId)) {
28033
28313
  throw new Error("External Thread Fork tree contains a cycle");
28034
28314
  }
28035
28315
  visited.add(current.hostThreadId);
28036
- path26.push(current);
28037
- const sourceId = current.forkSource?.hostThreadId;
28316
+ path27.push(current);
28317
+ const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
28038
28318
  const source = sourceId ? byId.get(sourceId) : void 0;
28039
28319
  if (!source) {
28040
28320
  const root = current.hostThreadId;
28041
- for (const record3 of path26) resolved.set(record3.hostThreadId, root);
28321
+ for (const record3 of path27) resolved.set(record3.hostThreadId, root);
28042
28322
  return root;
28043
28323
  }
28044
28324
  current = source;
@@ -28050,7 +28330,8 @@ function resolveExternalSessionTreeIds(records) {
28050
28330
  function listExternalThreadMetadata(input) {
28051
28331
  if (!input.query.supportsExternal) return { data: [], hasMore: false };
28052
28332
  const sessionIds = resolveExternalSessionTreeIds(input.records);
28053
- const entries = input.records.filter((record3) => includesExternalRecord(record3, input.query)).map((record3) => {
28333
+ const byId = new Map(input.records.map((record3) => [record3.hostThreadId, record3]));
28334
+ const entries = input.records.filter((record3) => includesExternalRecord(record3, input.query, byId)).map((record3) => {
28054
28335
  const runtime = input.runtimeFor(record3.hostThreadId);
28055
28336
  const sessionId = sessionIds.get(record3.hostThreadId);
28056
28337
  if (!sessionId) throw new Error("External Thread Session tree could not be resolved");
@@ -28132,6 +28413,7 @@ function threadId2(entry) {
28132
28413
  return entry.thread.id;
28133
28414
  }
28134
28415
  async function aggregateOfficialAccountThreadListPage(input) {
28416
+ const pageLimit = typeof input.params.limit === "number" ? input.params.limit : input.query.limit;
28135
28417
  const cursorValue2 = typeof input.params.cursor === "string" ? input.params.cursor : null;
28136
28418
  const cursor = cursorValue2 ? decodeCursor2(cursorValue2) : { accounts: initialAccounts(input.accountIds) };
28137
28419
  const sources = Object.entries(cursor.accounts).map(([accountId, state]) => ({
@@ -28168,7 +28450,7 @@ async function aggregateOfficialAccountThreadListPage(input) {
28168
28450
  if (source.done) return null;
28169
28451
  }
28170
28452
  source.batchStart = source.cursor;
28171
- const page = await request(source, source.cursor, Math.max(1, input.query.limit));
28453
+ const page = await request(source, source.cursor, Math.max(1, pageLimit));
28172
28454
  if (!source.requestedThisPage) {
28173
28455
  source.backwardsCursor = page.backwardsCursor;
28174
28456
  source.requestedThisPage = true;
@@ -28190,7 +28472,7 @@ async function aggregateOfficialAccountThreadListPage(input) {
28190
28472
  };
28191
28473
  const output = [];
28192
28474
  const emitted = /* @__PURE__ */ new Set();
28193
- while (output.length < input.query.limit) {
28475
+ while (output.length < pageLimit) {
28194
28476
  const candidates = await Promise.all(
28195
28477
  sources.map(async (source) => ({ source, entry: await ensure(source) }))
28196
28478
  );
@@ -28728,18 +29010,18 @@ var AppServerHost = class {
28728
29010
  };
28729
29011
  this.#writer = new OrderedWriter(this.#options.desktopOutput);
28730
29012
  const environment = this.#options.environment ?? process.env;
28731
- const dataDirectory = path12.resolve(
28732
- environment.CODEXHOST_DATA_DIR ?? path12.join(os2.homedir(), ".codexhost")
29013
+ const dataDirectory = path13.resolve(
29014
+ environment.CODEXHOST_DATA_DIR ?? path13.join(os2.homedir(), ".codexhost")
28733
29015
  );
28734
29016
  const accountRepository = options2.accountRepository ?? new AccountRepository({
28735
- directory: path12.join(dataDirectory, "codex-accounts"),
29017
+ directory: path13.join(dataDirectory, "codex-accounts"),
28736
29018
  defaultAccount: {
28737
29019
  accountId: "default",
28738
- codexHome: path12.resolve(environment.CODEX_HOME ?? path12.join(os2.homedir(), ".codex")),
29020
+ codexHome: path13.resolve(environment.CODEX_HOME ?? path13.join(os2.homedir(), ".codex")),
28739
29021
  label: "Default Codex Account"
28740
29022
  }
28741
29023
  });
28742
- const threadAccountStore = options2.threadAccountStore ?? new ThreadAccountStore({ directory: path12.join(dataDirectory, "codex-accounts") });
29024
+ const threadAccountStore = options2.threadAccountStore ?? new ThreadAccountStore({ directory: path13.join(dataDirectory, "codex-accounts") });
28743
29025
  this.#accountRepository = accountRepository;
28744
29026
  this.#threadAccountStore = threadAccountStore;
28745
29027
  this.#accountDataDirectory = dataDirectory;
@@ -29572,7 +29854,7 @@ var AppServerHost = class {
29572
29854
  throw new Error("Unknown Codex Account");
29573
29855
  const runtime = await this.#codexRuntimePool.get(params2.accountId);
29574
29856
  const response2 = await runtime.request("account/rateLimitResetCredit/consume", {
29575
- idempotencyKey: params2.idempotencyKey ?? randomUUID8()
29857
+ idempotencyKey: params2.idempotencyKey ?? randomUUID9()
29576
29858
  });
29577
29859
  if (isRecord13(response2.error)) {
29578
29860
  await this.#writer.json(rpcEnvelope(request, { error: response2.error }));
@@ -29613,10 +29895,10 @@ var AppServerHost = class {
29613
29895
  }
29614
29896
  if (request.method === "codexhost/account/create") {
29615
29897
  const params2 = codexAccountCreateParamsSchema.parse(requestObject(request));
29616
- const accountId = randomUUID8();
29898
+ const accountId = randomUUID9();
29617
29899
  const account = await this.#accountRepository.upsert({
29618
29900
  accountId,
29619
- codexHome: path12.join(this.#accountDataDirectory, "codex-homes", accountId),
29901
+ codexHome: path13.join(this.#accountDataDirectory, "codex-homes", accountId),
29620
29902
  label: params2.label ?? `Codex Account ${accountId.slice(0, 8)}`
29621
29903
  });
29622
29904
  const activeAccountId = await this.#accountRepository.getActiveAccountId();
@@ -29656,12 +29938,12 @@ var AppServerHost = class {
29656
29938
  for (const [key, session2] of this.#officialLoginSessions) {
29657
29939
  if (session2.accountId === params2.accountId) this.#officialLoginSessions.delete(key);
29658
29940
  }
29659
- const managedCodexHome = path12.join(
29941
+ const managedCodexHome = path13.join(
29660
29942
  this.#accountDataDirectory,
29661
29943
  "codex-homes",
29662
29944
  params2.accountId
29663
29945
  );
29664
- if (path12.resolve(account.codexHome) === path12.resolve(managedCodexHome)) {
29946
+ if (path13.resolve(account.codexHome) === path13.resolve(managedCodexHome)) {
29665
29947
  try {
29666
29948
  await rm4(managedCodexHome, { recursive: true, force: true });
29667
29949
  } catch (error51) {
@@ -29900,7 +30182,7 @@ var AppServerHost = class {
29900
30182
  throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
29901
30183
  }
29902
30184
  const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
29903
- const digest2 = createHash5("sha256").update(
30185
+ const digest2 = createHash6("sha256").update(
29904
30186
  JSON.stringify({
29905
30187
  task: input.task,
29906
30188
  cwd: input.cwd,
@@ -30003,7 +30285,7 @@ var AppServerHost = class {
30003
30285
  throw error51;
30004
30286
  }
30005
30287
  this.#activeOfficialTurns.set(threadId3, turnId);
30006
- const delegationId = hostThreadIdSchema.parse(randomUUID8());
30288
+ const delegationId = hostThreadIdSchema.parse(randomUUID9());
30007
30289
  try {
30008
30290
  const source = await this.#repository.find(input.parentThreadId);
30009
30291
  const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId3);
@@ -30167,7 +30449,7 @@ var AppServerHost = class {
30167
30449
  async #listDelegationThreads(input) {
30168
30450
  const [sortKey, sortDirection2] = input.sort.split("-");
30169
30451
  const request = {
30170
- id: `codexhost:delegation-list:${randomUUID8()}`,
30452
+ id: `codexhost:delegation-list:${randomUUID9()}`,
30171
30453
  method: "thread/list",
30172
30454
  params: {
30173
30455
  cwd: input.cwd ? [input.cwd] : null,
@@ -30230,6 +30512,8 @@ var AppServerHost = class {
30230
30512
  records,
30231
30513
  runtimeFor: (threadId3) => {
30232
30514
  const thread = this.#externalRuntime.get(threadId3);
30515
+ const subagentStatus = this.#subagentThreadStatuses.get(threadId3);
30516
+ if (subagentStatus) return { running: subagentStatus === "active" };
30233
30517
  return thread ? { running: thread.running } : null;
30234
30518
  },
30235
30519
  requestOfficialPage: (params) => aggregateOfficialAccountThreadListPage({
@@ -30681,7 +30965,7 @@ var AppServerHost = class {
30681
30965
  );
30682
30966
  return;
30683
30967
  }
30684
- const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID8());
30968
+ const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID9());
30685
30969
  const projection = {
30686
30970
  projector: new CodexTurnProjector({
30687
30971
  threadId: thread.id,
@@ -31540,7 +31824,7 @@ var AppServerHost = class {
31540
31824
  if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
31541
31825
  throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
31542
31826
  }
31543
- const turnId = hostTurnIdSchema.parse(randomUUID8());
31827
+ const turnId = hostTurnIdSchema.parse(randomUUID9());
31544
31828
  const startedAtMs = Date.now();
31545
31829
  const projection = {
31546
31830
  projector: new CodexTurnProjector({
@@ -31800,7 +32084,7 @@ var AppServerHost = class {
31800
32084
  if (event.type === "subagent.transcript.changed") {
31801
32085
  const nativeSubagentId = event.nativeSubagentId;
31802
32086
  const record3 = (await this.#repository.list()).find(
31803
- (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId
32087
+ (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId && candidate.nativeSessionRef?.nativeSessionId === thread.record.nativeSessionRef?.nativeSessionId
31804
32088
  );
31805
32089
  if (record3) await this.#refreshOpenSubagentThread(record3.hostThreadId, false);
31806
32090
  return;
@@ -31808,7 +32092,7 @@ var AppServerHost = class {
31808
32092
  if (event.type === "subagent.state.changed") {
31809
32093
  const nativeSubagentId = event.nativeSubagentId;
31810
32094
  const record3 = (await this.#repository.list()).find(
31811
- (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId
32095
+ (candidate) => candidate.subagent?.parentHostThreadId === thread.id && candidate.subagent.nativeSubagentId === nativeSubagentId && candidate.nativeSessionRef?.nativeSessionId === thread.record.nativeSessionRef?.nativeSessionId
31812
32096
  );
31813
32097
  if (!record3) return;
31814
32098
  const status = event.status === "pending" || event.status === "running" ? "active" : "idle";
@@ -31914,33 +32198,13 @@ var AppServerHost = class {
31914
32198
  async #materializeSubagent(parent, subagent) {
31915
32199
  if (!subagent.nativeSubagentId || !parent.record.nativeSessionRef) return subagent;
31916
32200
  const status = subagent.status === "pending" || subagent.status === "running" ? "active" : "idle";
31917
- const records = await this.#repository.list();
31918
- const existing = records.find(
31919
- (record4) => record4.subagent?.parentHostThreadId === parent.id && record4.subagent.nativeSubagentId === subagent.nativeSubagentId
31920
- );
31921
- if (existing) {
31922
- this.#trackRunningSubagent(parent.id, existing.hostThreadId, status);
31923
- await this.#setSubagentThreadStatus(existing.hostThreadId, status);
31924
- return { ...subagent, subagentId: existing.hostThreadId };
32201
+ const record3 = await this.#repository.materializeSubagent(parent.record, subagent);
32202
+ if (!record3) return subagent;
32203
+ if (this.#subagentThreadStatuses.has(record3.hostThreadId)) {
32204
+ this.#trackRunningSubagent(parent.id, record3.hostThreadId, status);
32205
+ await this.#setSubagentThreadStatus(record3.hostThreadId, status);
32206
+ return { ...subagent, subagentId: record3.hostThreadId };
31925
32207
  }
31926
- const recordInput = createExternalThreadRecordInput({
31927
- harnessId: parent.record.harnessId,
31928
- cwd: parent.cwd,
31929
- title: subagent.description,
31930
- transportModelId: parent.transportModelId,
31931
- ephemeral: false,
31932
- historyMode: "paginated",
31933
- subagent: {
31934
- parentHostThreadId: parent.id,
31935
- nativeSubagentId: subagent.nativeSubagentId,
31936
- ...subagent.role ? { role: subagent.role } : {}
31937
- }
31938
- });
31939
- let record3 = await this.#repository.createProvisional(recordInput);
31940
- record3 = await this.#repository.commitNative(
31941
- record3.hostThreadId,
31942
- parent.record.nativeSessionRef
31943
- );
31944
32208
  const thread = externalThreadValue({
31945
32209
  record: record3,
31946
32210
  turns: [],
@@ -32186,7 +32450,7 @@ var AppServerHost = class {
32186
32450
  try {
32187
32451
  result = projection.projector.projectQuestion(
32188
32452
  interaction,
32189
- hostItemIdSchema.parse(randomUUID8())
32453
+ hostItemIdSchema.parse(randomUUID9())
32190
32454
  );
32191
32455
  } catch (error51) {
32192
32456
  this.#diagnose(error51);
@@ -32342,7 +32606,7 @@ var AppServerHost = class {
32342
32606
  };
32343
32607
 
32344
32608
  // packages/host-runtime/src/codex-runtime/account-official-listeners.ts
32345
- import path13 from "node:path";
32609
+ import path14 from "node:path";
32346
32610
  var AccountOfficialListeners = class {
32347
32611
  constructor(createListener) {
32348
32612
  this.createListener = createListener;
@@ -32353,7 +32617,7 @@ var AccountOfficialListeners = class {
32353
32617
  #closed = false;
32354
32618
  async endpoint(account) {
32355
32619
  if (this.#closed) throw new Error("Account official listeners are closed");
32356
- const key = path13.resolve(account.codexHome);
32620
+ const key = path14.resolve(account.codexHome);
32357
32621
  const existing = this.#starting.get(key);
32358
32622
  if (existing) return existing;
32359
32623
  const listener = this.createListener(account);
@@ -32489,17 +32753,17 @@ var DelegationControlRegistry = class {
32489
32753
 
32490
32754
  // packages/host-runtime/src/installed-harness-plugins.ts
32491
32755
  import os3 from "node:os";
32492
- import path15 from "node:path";
32756
+ import path16 from "node:path";
32493
32757
  import { fileURLToPath } from "node:url";
32494
32758
 
32495
32759
  // packages/host-runtime/src/launcher-url-opener.ts
32496
32760
  import { spawn as spawn3 } from "node:child_process";
32497
- import path14 from "node:path";
32761
+ import path15 from "node:path";
32498
32762
  var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
32499
32763
  var OPEN_TIMEOUT_MS = 1e4;
32500
32764
  function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn3(command, arguments_2, options2)) {
32501
32765
  const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
32502
- if (!launcher || !path14.isAbsolute(launcher)) return void 0;
32766
+ if (!launcher || !path15.isAbsolute(launcher)) return void 0;
32503
32767
  const launcherEnvironment = Object.fromEntries(
32504
32768
  Object.entries(environment).filter(([name]) => {
32505
32769
  const normalized = name.toUpperCase();
@@ -32557,9 +32821,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
32557
32821
  const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
32558
32822
  return {
32559
32823
  pluginRoots: [
32560
- path15.join(path15.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
32561
- environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path15.join(
32562
- environment.CODEXHOST_DATA_DIR ? path15.resolve(environment.CODEXHOST_DATA_DIR) : path15.join(os3.homedir(), ".codexhost"),
32824
+ path16.join(path16.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
32825
+ environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path16.join(
32826
+ environment.CODEXHOST_DATA_DIR ? path16.resolve(environment.CODEXHOST_DATA_DIR) : path16.join(os3.homedir(), ".codexhost"),
32563
32827
  "plugins"
32564
32828
  )
32565
32829
  ],
@@ -32684,12 +32948,12 @@ async function startDelegationControlServer(input) {
32684
32948
  }
32685
32949
 
32686
32950
  // packages/host-runtime/src/delegation-skill.ts
32687
- import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
32951
+ import { createHash as createHash7, randomUUID as randomUUID10 } from "node:crypto";
32688
32952
  import { mkdir as mkdir7, open as open5, readFile as readFile8, rename as rename5, rm as rm5, stat as stat3 } from "node:fs/promises";
32689
32953
  import os4 from "node:os";
32690
- import path16 from "node:path";
32954
+ import path17 from "node:path";
32691
32955
  var SKILL_VERSION = 7;
32692
- var SKILL_RELATIVE_PATH = path16.join("skills", "codexhost-delegation", "SKILL.md");
32956
+ var SKILL_RELATIVE_PATH = path17.join("skills", "codexhost-delegation", "SKILL.md");
32693
32957
  var PREVIOUS_MANAGED_DIGESTS = [
32694
32958
  "9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
32695
32959
  "2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
@@ -32745,9 +33009,9 @@ user’s request and the task:
32745
33009
  Report the result returned by read or a completed wait, together with the target
32746
33010
  agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
32747
33011
  `;
32748
- var CURRENT_DIGEST = createHash6("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
33012
+ var CURRENT_DIGEST = createHash7("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
32749
33013
  function digest(value2) {
32750
- return createHash6("sha256").update(value2).digest("hex");
33014
+ return createHash7("sha256").update(value2).digest("hex");
32751
33015
  }
32752
33016
  function managedVersion(value2) {
32753
33017
  const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
@@ -32762,8 +33026,8 @@ async function readOptional(filePath) {
32762
33026
  }
32763
33027
  }
32764
33028
  async function atomicWrite(filePath, content) {
32765
- await mkdir7(path16.dirname(filePath), { recursive: true, mode: 448 });
32766
- const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID9()}.tmp`);
33029
+ await mkdir7(path17.dirname(filePath), { recursive: true, mode: 448 });
33030
+ const temporaryPath = path17.join(path17.dirname(filePath), `.SKILL.md.${randomUUID10()}.tmp`);
32767
33031
  const handle = await open5(temporaryPath, "wx", 384);
32768
33032
  try {
32769
33033
  await handle.writeFile(content, "utf8");
@@ -32780,8 +33044,8 @@ async function atomicWrite(filePath, content) {
32780
33044
  async function installDelegationSkills(input = {}) {
32781
33045
  const home = input.homeDirectory ?? os4.homedir();
32782
33046
  const destinations = [
32783
- path16.join(home, ".agents", SKILL_RELATIVE_PATH),
32784
- path16.join(home, ".claude", SKILL_RELATIVE_PATH)
33047
+ path17.join(home, ".agents", SKILL_RELATIVE_PATH),
33048
+ path17.join(home, ".claude", SKILL_RELATIVE_PATH)
32785
33049
  ];
32786
33050
  const knownDigests = /* @__PURE__ */ new Set([
32787
33051
  CURRENT_DIGEST,
@@ -32846,9 +33110,9 @@ async function installDelegationSkills(input = {}) {
32846
33110
  }
32847
33111
 
32848
33112
  // packages/host-runtime/src/remote-control-app-server.ts
32849
- import { randomUUID as randomUUID10 } from "node:crypto";
33113
+ import { randomUUID as randomUUID11 } from "node:crypto";
32850
33114
  import { mkdir as mkdir8, open as open6, rename as rename6, rm as rm6 } from "node:fs/promises";
32851
- import path17 from "node:path";
33115
+ import path18 from "node:path";
32852
33116
 
32853
33117
  // packages/host-runtime/src/remote-official-connection.ts
32854
33118
  import net from "node:net";
@@ -33038,30 +33302,30 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
33038
33302
  function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
33039
33303
  const value2 = environment[name] ?? fallback;
33040
33304
  if (!value2) return null;
33041
- if (path17.isAbsolute(value2)) return path17.normalize(value2);
33042
- return platform === "win32" && path17.win32.isAbsolute(value2) ? path17.win32.normalize(value2) : null;
33305
+ if (path18.isAbsolute(value2)) return path18.normalize(value2);
33306
+ return platform === "win32" && path18.win32.isAbsolute(value2) ? path18.win32.normalize(value2) : null;
33043
33307
  }
33044
33308
  function nodeCompatibleWindowsPath(value2) {
33045
33309
  if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
33046
33310
  if (value2.startsWith("\\\\?\\")) return value2.slice(4);
33047
33311
  return value2;
33048
33312
  }
33049
- function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID10()) {
33313
+ function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID11()) {
33050
33314
  const safeInstance = instanceId.replaceAll(/[^a-zA-Z0-9-]/gu, "");
33051
33315
  if (!safeInstance) throw new Error("Remote Control bridge instance ID is invalid");
33052
33316
  return `\\\\.\\pipe\\codexhost-remote-control-${processId}-${safeInstance}`;
33053
33317
  }
33054
33318
  function remoteControlBridgeDescriptorPath(environment) {
33055
33319
  const root = environment.LOCALAPPDATA;
33056
- if (!root || !path17.isAbsolute(root)) return null;
33057
- return path17.join(path17.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
33320
+ if (!root || !path18.isAbsolute(root)) return null;
33321
+ return path18.join(path18.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
33058
33322
  }
33059
33323
  async function publishRemoteControlAppServerDescriptor(plan) {
33060
- const directory = path17.dirname(plan.descriptorPath);
33324
+ const directory = path18.dirname(plan.descriptorPath);
33061
33325
  await mkdir8(directory, { recursive: true, mode: 448 });
33062
- const temporaryPath = path17.join(
33326
+ const temporaryPath = path18.join(
33063
33327
  directory,
33064
- `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID10()}.tmp`
33328
+ `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID11()}.tmp`
33065
33329
  );
33066
33330
  const handle = await open6(temporaryPath, "wx", 384);
33067
33331
  try {
@@ -33152,14 +33416,14 @@ async function runRemoteControlAppServerBridge(input = {}) {
33152
33416
  import { createServer as createServer2 } from "node:http";
33153
33417
  import net2 from "node:net";
33154
33418
  import { chmod as chmod3, lstat as lstat6, mkdir as mkdir10, rm as rm8 } from "node:fs/promises";
33155
- import path19 from "node:path";
33419
+ import path20 from "node:path";
33156
33420
  import { PassThrough as PassThrough2 } from "node:stream";
33157
33421
 
33158
33422
  // packages/host-runtime/src/remote-socket-lock.ts
33159
- import { randomUUID as randomUUID11 } from "node:crypto";
33423
+ import { randomUUID as randomUUID12 } from "node:crypto";
33160
33424
  import { chmod as chmod2, lstat as lstat5, mkdir as mkdir9, open as open7, readFile as readFile9, readdir as readdir4, rename as rename7, rm as rm7 } from "node:fs/promises";
33161
33425
  import { uptime } from "node:os";
33162
- import path18 from "node:path";
33426
+ import path19 from "node:path";
33163
33427
  import { setTimeout as delay4 } from "node:timers/promises";
33164
33428
  var LOCK_RETRY_COUNT = 200;
33165
33429
  var LOCK_RETRY_DELAY_MS = 25;
@@ -33233,7 +33497,7 @@ async function readLockEntrySnapshot(filePath) {
33233
33497
  source,
33234
33498
  identity: { dev: metadata.dev, ino: metadata.ino },
33235
33499
  mtimeMs: metadata.mtimeMs,
33236
- record: record3 && path18.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
33500
+ record: record3 && path19.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
33237
33501
  };
33238
33502
  }
33239
33503
  function lockEntryIsAbandoned(snapshot) {
@@ -33254,7 +33518,7 @@ async function readLockEntryCatalog(lockDirectory) {
33254
33518
  let unsettled = false;
33255
33519
  for (const name of names) {
33256
33520
  if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
33257
- const snapshot = await readLockEntrySnapshot(path18.join(lockDirectory, name));
33521
+ const snapshot = await readLockEntrySnapshot(path19.join(lockDirectory, name));
33258
33522
  if (snapshot === null) continue;
33259
33523
  if (lockEntryIsAbandoned(snapshot)) {
33260
33524
  if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
@@ -33282,7 +33546,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
33282
33546
  await chmod2(lockDirectory, 448);
33283
33547
  }
33284
33548
  async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
33285
- const temporary = path18.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID11()}`);
33549
+ const temporary = path19.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID12()}`);
33286
33550
  const handle = await open7(temporary, "wx", 384);
33287
33551
  try {
33288
33552
  await handle.writeFile(`${JSON.stringify(record3)}
@@ -33357,8 +33621,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
33357
33621
  const legacyPath = `${socketPath}.initializing`;
33358
33622
  const lockDirectory = `${socketPath}.initializers`;
33359
33623
  await preparePrivateLockDirectory(lockDirectory);
33360
- const ownerToken = randomUUID11();
33361
- const entryPath = path18.join(lockDirectory, lockEntryName(ownerToken));
33624
+ const ownerToken = randomUUID12();
33625
+ const entryPath = path19.join(lockDirectory, lockEntryName(ownerToken));
33362
33626
  const baseRecord = {
33363
33627
  version: 2,
33364
33628
  ownerToken,
@@ -33532,14 +33796,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
33532
33796
  throw new Error("Remote app-server listener must use a Unix URL");
33533
33797
  }
33534
33798
  const explicit = listenUrl.slice("unix://".length);
33535
- if (explicit.length > 0) return path19.posix.resolve(decodeURIComponent(explicit));
33536
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path19.posix.join(environment.HOME, ".codex") : void 0);
33799
+ if (explicit.length > 0) return path20.posix.resolve(decodeURIComponent(explicit));
33800
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path20.posix.join(environment.HOME, ".codex") : void 0);
33537
33801
  if (!codexHome)
33538
33802
  throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
33539
- return path19.posix.join(codexHome, "app-server-control", "app-server-control.sock");
33803
+ return path20.posix.join(codexHome, "app-server-control", "app-server-control.sock");
33540
33804
  }
33541
33805
  function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
33542
- if (!path19.posix.isAbsolute(socketPath)) {
33806
+ if (!path20.posix.isAbsolute(socketPath)) {
33543
33807
  throw new Error("Shared official app-server socket path must be absolute");
33544
33808
  }
33545
33809
  if (remoteUnixListenerUrl(arguments_2) === null) {
@@ -33650,7 +33914,7 @@ async function removeStaleSocket(socketPath) {
33650
33914
  await rm8(socketPath, { force: true });
33651
33915
  }
33652
33916
  async function prepareRemoteAppServerSocketDirectory(socketPath) {
33653
- const socketDirectory = path19.dirname(socketPath);
33917
+ const socketDirectory = path20.dirname(socketPath);
33654
33918
  const existing = await lstat6(socketDirectory).catch((error51) => {
33655
33919
  if (error51.code === "ENOENT") return null;
33656
33920
  throw error51;
@@ -33855,20 +34119,20 @@ function createRemoteAppServerWebSocketListener(input) {
33855
34119
 
33856
34120
  // packages/host-runtime/src/remote-official-app-server.ts
33857
34121
  import { spawn as spawn4 } from "node:child_process";
33858
- import { randomUUID as randomUUID12 } from "node:crypto";
34122
+ import { randomUUID as randomUUID13 } from "node:crypto";
33859
34123
  import { lstat as lstat7, rm as rm9 } from "node:fs/promises";
33860
- import path20 from "node:path";
34124
+ import path21 from "node:path";
33861
34125
  var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
33862
34126
  var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
33863
- function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID12()) {
33864
- if (!path20.posix.isAbsolute(desktopControlSocketPath)) {
34127
+ function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID13()) {
34128
+ if (!path21.posix.isAbsolute(desktopControlSocketPath)) {
33865
34129
  throw new Error("Desktop control socket path must be absolute");
33866
34130
  }
33867
34131
  if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
33868
34132
  throw new Error("Shared official app-server socket token is invalid");
33869
34133
  }
33870
34134
  const compactToken = token.replaceAll("-", "").slice(0, 15);
33871
- return path20.posix.join(path20.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
34135
+ return path21.posix.join(path21.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
33872
34136
  }
33873
34137
  function errorMessage5(error51) {
33874
34138
  return error51 instanceof Error ? error51.message : String(error51);
@@ -34159,7 +34423,16 @@ function createHostUpdateCoordinator(options2) {
34159
34423
  });
34160
34424
  return contextPromise;
34161
34425
  };
34162
- const fetchLatest = options2.fetchLatest ?? ((signal) => fetchLatestGitHubRelease({ signal: signal ?? AbortSignal.timeout(15e3) }));
34426
+ const fetchLatest = options2.fetchLatest ?? (async (signal) => {
34427
+ const timeoutSignal = AbortSignal.timeout(15e3);
34428
+ const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
34429
+ const authenticated = await fetchLatestGitHubReleaseWithGitHubCli({
34430
+ ...options2.environment ? { environment: options2.environment } : {},
34431
+ platform,
34432
+ signal: requestSignal
34433
+ });
34434
+ return authenticated ?? fetchLatestGitHubRelease({ signal: requestSignal });
34435
+ });
34163
34436
  let candidate = null;
34164
34437
  async function latestStatus(context) {
34165
34438
  const discovered = await discoverLatestUpdateStatus(context.common.stateDirectory);
@@ -34335,9 +34608,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
34335
34608
  if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
34336
34609
  const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
34337
34610
  if (!npmPackageRoot || !hostRuntimePath) return true;
34338
- if (!path21.isAbsolute(npmPackageRoot) || !path21.isAbsolute(hostRuntimePath)) return false;
34339
- const runtimePackageRoot = path21.dirname(path21.dirname(path21.normalize(hostRuntimePath)));
34340
- return path21.relative(path21.normalize(npmPackageRoot), runtimePackageRoot) === "";
34611
+ if (!path22.isAbsolute(npmPackageRoot) || !path22.isAbsolute(hostRuntimePath)) return false;
34612
+ const runtimePackageRoot = path22.dirname(path22.dirname(path22.normalize(hostRuntimePath)));
34613
+ return path22.relative(path22.normalize(npmPackageRoot), runtimePackageRoot) === "";
34341
34614
  }
34342
34615
  function requiredRuntimeConfiguration(environment) {
34343
34616
  const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
@@ -34464,8 +34737,8 @@ async function runHostRuntime(input) {
34464
34737
  });
34465
34738
  try {
34466
34739
  await officialListeners.endpoint({
34467
- codexHome: path21.resolve(
34468
- delegationEnvironment.CODEX_HOME ?? path21.join(homedir(), ".codex")
34740
+ codexHome: path22.resolve(
34741
+ delegationEnvironment.CODEX_HOME ?? path22.join(homedir(), ".codex")
34469
34742
  )
34470
34743
  });
34471
34744
  await listener.listen();
@@ -34566,7 +34839,7 @@ async function runHostRuntime(input) {
34566
34839
  }
34567
34840
 
34568
34841
  // packages/host-runtime/src/remote-host-install.ts
34569
- import { createHash as createHash7, randomUUID as randomUUID13 } from "node:crypto";
34842
+ import { createHash as createHash8, randomUUID as randomUUID14 } from "node:crypto";
34570
34843
  import { constants as fsConstants } from "node:fs";
34571
34844
  import {
34572
34845
  access,
@@ -34581,7 +34854,7 @@ import {
34581
34854
  stat as stat4,
34582
34855
  writeFile as writeFile5
34583
34856
  } from "node:fs/promises";
34584
- import path22 from "node:path";
34857
+ import path23 from "node:path";
34585
34858
  var MANIFEST_FORMAT = 1;
34586
34859
  var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
34587
34860
  var PROFILE_START = "# >>> codexhost remote SSH >>>";
@@ -34592,25 +34865,25 @@ function resolvePaths(options2) {
34592
34865
  if (!configuredHome) {
34593
34866
  throw new Error("A non-root HOME is required for remote Host installation");
34594
34867
  }
34595
- const home = path22.resolve(configuredHome);
34596
- if (!home || home === path22.parse(home).root) {
34868
+ const home = path23.resolve(configuredHome);
34869
+ if (!home || home === path23.parse(home).root) {
34597
34870
  throw new Error("A non-root HOME is required for remote Host installation");
34598
34871
  }
34599
- const installRoot = path22.resolve(options2.installRoot ?? path22.join(home, ".codexhost", "remote"));
34600
- const profilePath = path22.resolve(
34601
- options2.profilePath ?? path22.join(
34872
+ const installRoot = path23.resolve(options2.installRoot ?? path23.join(home, ".codexhost", "remote"));
34873
+ const profilePath = path23.resolve(
34874
+ options2.profilePath ?? path23.join(
34602
34875
  home,
34603
- path22.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path22.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
34876
+ path23.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path23.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
34604
34877
  )
34605
34878
  );
34606
- const binDirectory = path22.join(installRoot, "bin");
34879
+ const binDirectory = path23.join(installRoot, "bin");
34607
34880
  return {
34608
34881
  home,
34609
34882
  installRoot,
34610
34883
  binDirectory,
34611
- wrapperPath: path22.join(binDirectory, "codex"),
34612
- manifestPath: path22.join(installRoot, "manifest.json"),
34613
- dataDirectory: path22.join(installRoot, "data"),
34884
+ wrapperPath: path23.join(binDirectory, "codex"),
34885
+ manifestPath: path23.join(installRoot, "manifest.json"),
34886
+ dataDirectory: path23.join(installRoot, "data"),
34614
34887
  profilePath
34615
34888
  };
34616
34889
  }
@@ -34626,10 +34899,10 @@ async function existingText(filePath) {
34626
34899
  }
34627
34900
  }
34628
34901
  async function fileSha256(filePath) {
34629
- return createHash7("sha256").update(await readFile10(filePath)).digest("hex");
34902
+ return createHash8("sha256").update(await readFile10(filePath)).digest("hex");
34630
34903
  }
34631
34904
  async function executable(filePath, label) {
34632
- const absolute = path22.resolve(filePath);
34905
+ const absolute = path23.resolve(filePath);
34633
34906
  try {
34634
34907
  if (!(await stat4(absolute)).isFile()) throw new Error("not a regular file");
34635
34908
  await access(absolute, fsConstants.X_OK);
@@ -34639,7 +34912,7 @@ async function executable(filePath, label) {
34639
34912
  return absolute;
34640
34913
  }
34641
34914
  async function existingFile(filePath, label) {
34642
- const absolute = path22.resolve(filePath);
34915
+ const absolute = path23.resolve(filePath);
34643
34916
  try {
34644
34917
  const metadata = await stat4(absolute);
34645
34918
  if (!metadata.isFile()) throw new Error("not a regular file");
@@ -34649,9 +34922,9 @@ async function existingFile(filePath, label) {
34649
34922
  return absolute;
34650
34923
  }
34651
34924
  async function discoverExecutable(name, environment) {
34652
- for (const directory of (environment.PATH ?? "").split(path22.delimiter)) {
34925
+ for (const directory of (environment.PATH ?? "").split(path23.delimiter)) {
34653
34926
  if (!directory) continue;
34654
- const candidate = path22.resolve(directory, name);
34927
+ const candidate = path23.resolve(directory, name);
34655
34928
  try {
34656
34929
  await access(candidate, fsConstants.X_OK);
34657
34930
  return candidate;
@@ -34662,10 +34935,10 @@ async function discoverExecutable(name, environment) {
34662
34935
  return null;
34663
34936
  }
34664
34937
  async function writeAtomic(filePath, contents, mode) {
34665
- await mkdir11(path22.dirname(filePath), { recursive: true, mode: 448 });
34666
- const temporary = path22.join(
34667
- path22.dirname(filePath),
34668
- `.${path22.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
34938
+ await mkdir11(path23.dirname(filePath), { recursive: true, mode: 448 });
34939
+ const temporary = path23.join(
34940
+ path23.dirname(filePath),
34941
+ `.${path23.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
34669
34942
  );
34670
34943
  try {
34671
34944
  if (typeof contents === "string") {
@@ -34686,10 +34959,10 @@ async function writeAtomic(filePath, contents, mode) {
34686
34959
  }
34687
34960
  }
34688
34961
  async function writeAtomicExecutable(filePath, sourcePath) {
34689
- await mkdir11(path22.dirname(filePath), { recursive: true, mode: 448 });
34690
- const temporary = path22.join(
34691
- path22.dirname(filePath),
34692
- `.${path22.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
34962
+ await mkdir11(path23.dirname(filePath), { recursive: true, mode: 448 });
34963
+ const temporary = path23.join(
34964
+ path23.dirname(filePath),
34965
+ `.${path23.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
34693
34966
  );
34694
34967
  try {
34695
34968
  await copyFile3(sourcePath, temporary);
@@ -34730,8 +35003,8 @@ function removeManagedProfileBlock(contents) {
34730
35003
  function installManagedProfileBlock(contents, manifest) {
34731
35004
  const base = removeManagedProfileBlock(contents);
34732
35005
  const environment = [
34733
- `export CODEX_INSTALL_DIR=${shellQuote(path22.dirname(manifest.wrapperPath))}`,
34734
- `export PATH=${shellQuote(path22.dirname(manifest.wrapperPath))}:${shellQuote(path22.dirname(manifest.nodePath))}:${shellQuote(path22.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
35006
+ `export CODEX_INSTALL_DIR=${shellQuote(path23.dirname(manifest.wrapperPath))}`,
35007
+ `export PATH=${shellQuote(path23.dirname(manifest.wrapperPath))}:${shellQuote(path23.dirname(manifest.nodePath))}:${shellQuote(path23.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
34735
35008
  `export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
34736
35009
  `export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
34737
35010
  `export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
@@ -34748,7 +35021,7 @@ function installManagedProfileBlock(contents, manifest) {
34748
35021
  PROFILE_END,
34749
35022
  ""
34750
35023
  ].join("\n");
34751
- if (path22.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
35024
+ if (path23.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
34752
35025
  const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
34753
35026
  return `${base}${separator}${block}`;
34754
35027
  }
@@ -34767,7 +35040,7 @@ ${WRAPPER_MARKER}
34767
35040
  return "legacy-wrapper";
34768
35041
  }
34769
35042
  if (manifest.entrypointSha256 !== void 0) {
34770
- return createHash7("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
35043
+ return createHash8("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
34771
35044
  }
34772
35045
  const shim = await readFile10(manifest.shimPath).catch((error51) => {
34773
35046
  if (error51.code === "ENOENT") return null;
@@ -34813,9 +35086,9 @@ async function readManifest(filePath) {
34813
35086
  ];
34814
35087
  const optionalPaths = ["claudeCommand", "profileBackupPath"];
34815
35088
  if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
34816
- (key) => typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key])
35089
+ (key) => typeof manifest[key] !== "string" || !path23.isAbsolute(manifest[key])
34817
35090
  ) || optionalPaths.some(
34818
- (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key]))
35091
+ (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path23.isAbsolute(manifest[key]))
34819
35092
  ) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
34820
35093
  throw new Error("Remote Host manifest has an unsupported format");
34821
35094
  }
@@ -35044,7 +35317,7 @@ async function uninstallRemoteHost(options2) {
35044
35317
  import { spawn as spawn5 } from "node:child_process";
35045
35318
  import { stat as stat5 } from "node:fs/promises";
35046
35319
  import net3 from "node:net";
35047
- import path23 from "node:path";
35320
+ import path24 from "node:path";
35048
35321
  import { Duplex } from "node:stream";
35049
35322
  var CODEXHOST_STATUS_METHOD = "codexhost/update/status";
35050
35323
  var DIRECT_PROBE_TIMEOUT_MS = 5e3;
@@ -35063,9 +35336,9 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
35063
35336
  }
35064
35337
  var lifecycleDependencyOverrides = {};
35065
35338
  function socketPathFor(environment) {
35066
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path23.join(environment.HOME, ".codex") : void 0);
35339
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path24.join(environment.HOME, ".codex") : void 0);
35067
35340
  if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
35068
- return path23.join(codexHome, "app-server-control", "app-server-control.sock");
35341
+ return path24.join(codexHome, "app-server-control", "app-server-control.sock");
35069
35342
  }
35070
35343
  async function defaultSocketExists(socketPath) {
35071
35344
  const metadata = await stat5(socketPath).catch((error51) => {
@@ -35195,7 +35468,7 @@ function installedManifest(status) {
35195
35468
  function managedEnvironment(manifest, environment) {
35196
35469
  return {
35197
35470
  ...environment,
35198
- CODEX_INSTALL_DIR: path23.dirname(manifest.wrapperPath),
35471
+ CODEX_INSTALL_DIR: path24.dirname(manifest.wrapperPath),
35199
35472
  CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
35200
35473
  CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
35201
35474
  CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
@@ -35203,7 +35476,7 @@ function managedEnvironment(manifest, environment) {
35203
35476
  CODEXHOST_DEFAULT_AGENT: "codex",
35204
35477
  CODEXHOST_REMOTE_SSH_MANAGED: "1",
35205
35478
  ...manifest.claudeCommand ? { CODEXHOST_CLAUDE_COMMAND: manifest.claudeCommand } : {},
35206
- PATH: `${path23.dirname(manifest.wrapperPath)}${path23.delimiter}${path23.dirname(manifest.stockCodexPath)}${path23.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
35479
+ PATH: `${path24.dirname(manifest.wrapperPath)}${path24.delimiter}${path24.dirname(manifest.stockCodexPath)}${path24.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
35207
35480
  };
35208
35481
  }
35209
35482
  async function defaultRunTerminator(manifest, socketPath, role, environment) {
@@ -35494,7 +35767,7 @@ var harnessBrokerServerFrameSchema = external_exports.union([
35494
35767
  var harnessBrokerDescriptorSchema = external_exports.object({
35495
35768
  schemaVersion: external_exports.literal(1),
35496
35769
  protocolVersion: external_exports.literal(HARNESS_BROKER_PROTOCOL_VERSION),
35497
- harnessId: external_exports.literal("claude-code"),
35770
+ harnessId: harnessPluginIdSchema,
35498
35771
  generation: external_exports.string().uuid(),
35499
35772
  ownerPid: external_exports.number().int().positive(),
35500
35773
  socketPath: external_exports.string().min(1).max(512),
@@ -35545,33 +35818,48 @@ function consumeBrokerFrames(socket, onFrame, onError) {
35545
35818
 
35546
35819
  // packages/harness-broker/dist/paths.js
35547
35820
  import os5 from "node:os";
35548
- import path24 from "node:path";
35821
+ import path25 from "node:path";
35549
35822
  var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
35550
35823
  var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
35551
35824
  var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
35552
35825
  function defaultHarnessBrokerDirectory(environment = process.env) {
35553
35826
  const home = environment.HOME || os5.homedir();
35554
- return path24.join(home, ".codexhost", "harness-broker");
35827
+ return path25.join(home, ".codexhost", "harness-broker");
35555
35828
  }
35556
- function defaultHarnessBrokerDescriptorPath(environment = process.env) {
35557
- return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
35829
+ function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
35830
+ harnessPluginIdSchema.parse(harnessId);
35831
+ if (harnessId !== "claude-code")
35832
+ return path25.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
35833
+ return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path25.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
35558
35834
  }
35559
- function defaultHarnessBrokerSocketPath(environment = process.env) {
35560
- return path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
35835
+ function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
35836
+ harnessPluginIdSchema.parse(harnessId);
35837
+ if (harnessId !== "claude-code")
35838
+ return path25.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
35839
+ return path25.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
35561
35840
  }
35562
35841
 
35563
35842
  // packages/harness-broker/dist/validation.js
35564
35843
  var cwdSchema = external_exports.string().min(1).max(16384);
35844
+ var brokerEnvironmentSchema = external_exports.object({
35845
+ CODEXHOST_CLI_PATH: external_exports.string().max(16384).optional(),
35846
+ CODEXHOST_RUNTIME_ENDPOINT: external_exports.string().max(16384).optional(),
35847
+ CODEXHOST_RUNTIME_TOKEN: external_exports.string().max(16384).optional(),
35848
+ CODEXHOST_THREAD_ID: external_exports.string().max(256).optional()
35849
+ }).strict();
35565
35850
  var createSchema = external_exports.object({
35566
35851
  kind: external_exports.literal("create"),
35567
35852
  cwd: cwdSchema,
35568
35853
  executionPolicy: external_exports.enum(["default", "unattended-full-access"]).optional(),
35854
+ environment: brokerEnvironmentSchema.optional(),
35569
35855
  model: harnessModelRefSchema.optional(),
35570
35856
  thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
35571
35857
  permissionModeId: harnessPermissionModeIdSchema.optional()
35572
35858
  }).strict();
35573
35859
  var resumeSchema = external_exports.object({
35574
35860
  kind: external_exports.literal("resume"),
35861
+ environment: brokerEnvironmentSchema.optional(),
35862
+ permissionModeId: harnessPermissionModeIdSchema.optional(),
35575
35863
  model: harnessModelRefSchema.optional(),
35576
35864
  thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
35577
35865
  nativeRef: nativeSessionRefSchema,
@@ -35580,12 +35868,14 @@ var resumeSchema = external_exports.object({
35580
35868
  }).strict();
35581
35869
  var forkSchema = external_exports.object({
35582
35870
  kind: external_exports.literal("fork"),
35871
+ environment: brokerEnvironmentSchema.optional(),
35583
35872
  sourceRef: nativeSessionRefSchema,
35584
35873
  checkpoint: nativeCheckpointRefSchema,
35585
35874
  cwd: cwdSchema
35586
35875
  }).strict();
35587
35876
  var rollbackSchema = external_exports.object({
35588
35877
  kind: external_exports.literal("rollbackLastTurn"),
35878
+ environment: brokerEnvironmentSchema.optional(),
35589
35879
  model: harnessModelRefSchema.optional(),
35590
35880
  thinkingOptionId: harnessThinkingOptionIdSchema.optional(),
35591
35881
  permissionModeId: harnessPermissionModeIdSchema.optional(),
@@ -35780,10 +36070,10 @@ var harnessOutputSchema = external_exports.custom((value2) => {
35780
36070
  });
35781
36071
 
35782
36072
  // packages/harness-broker/dist/server.js
35783
- import { randomBytes as randomBytes2, randomUUID as randomUUID14 } from "node:crypto";
36073
+ import { randomBytes as randomBytes2, randomUUID as randomUUID15 } from "node:crypto";
35784
36074
  import { chmod as chmod5, lstat as lstat9, mkdir as mkdir12, open as open8, readFile as readFile11, rename as rename9, rm as rm11 } from "node:fs/promises";
35785
36075
  import net4, {} from "node:net";
35786
- import path25 from "node:path";
36076
+ import path26 from "node:path";
35787
36077
  function harnessError(message, retryable = true) {
35788
36078
  return { code: "unavailable", message, retryable, stage: "harnessBroker" };
35789
36079
  }
@@ -35839,7 +36129,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
35839
36129
  }
35840
36130
  }
35841
36131
  async function publishDescriptor(descriptorPath, descriptor) {
35842
- const temporary = `${descriptorPath}.${process.pid}.${randomUUID14()}.tmp`;
36132
+ const temporary = `${descriptorPath}.${process.pid}.${randomUUID15()}.tmp`;
35843
36133
  const handle = await open8(temporary, "wx", 384);
35844
36134
  try {
35845
36135
  await handle.writeFile(`${JSON.stringify(descriptor)}
@@ -35905,25 +36195,23 @@ async function prepareUnixSocketPath(socketPath) {
35905
36195
  }
35906
36196
  }
35907
36197
  async function startHarnessBrokerServer(input) {
35908
- if (input.adapter.harnessId !== "claude-code") {
35909
- throw new Error("Harness broker accepts only the claude-code adapter");
35910
- }
35911
- if (process.platform !== "win32" && path25.dirname(input.descriptorPath) !== path25.dirname(input.socketPath)) {
36198
+ harnessPluginIdSchema.parse(input.adapter.harnessId);
36199
+ if (process.platform !== "win32" && path26.dirname(input.descriptorPath) !== path26.dirname(input.socketPath)) {
35912
36200
  throw new Error("Harness broker descriptor and socket must share one private directory");
35913
36201
  }
35914
36202
  if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
35915
36203
  throw new Error("Harness broker Unix socket path is too long for macOS");
35916
36204
  }
35917
- await privateDirectory(path25.dirname(input.descriptorPath));
36205
+ await privateDirectory(path26.dirname(input.descriptorPath));
35918
36206
  await assertNoLiveDescriptor(input.descriptorPath);
35919
36207
  if (process.platform !== "win32")
35920
36208
  await prepareUnixSocketPath(input.socketPath);
35921
- const generation = input.generation ?? randomUUID14();
36209
+ const generation = input.generation ?? randomUUID15();
35922
36210
  const token = input.token ?? randomBytes2(32).toString("hex");
35923
36211
  const descriptor = {
35924
36212
  schemaVersion: 1,
35925
36213
  protocolVersion: HARNESS_BROKER_PROTOCOL_VERSION,
35926
- harnessId: "claude-code",
36214
+ harnessId: input.adapter.harnessId,
35927
36215
  generation,
35928
36216
  ownerPid: process.pid,
35929
36217
  socketPath: input.socketPath,
@@ -35936,7 +36224,7 @@ async function startHarnessBrokerServer(input) {
35936
36224
  let closed = false;
35937
36225
  const server = net4.createServer((socket) => {
35938
36226
  const state = {
35939
- id: randomUUID14(),
36227
+ id: randomUUID15(),
35940
36228
  socket,
35941
36229
  authenticated: false,
35942
36230
  inputSequence: 0,
@@ -35979,8 +36267,9 @@ async function startHarnessBrokerServer(input) {
35979
36267
  if (output.kind === "event" && output.event.type === "session.state.changed") {
35980
36268
  const state2 = output.event.state;
35981
36269
  const observedNativeId = state2.nativeRef?.nativeSessionId;
35982
- if (state2.nativeRef && record3.nativeRef && (record3.nativeRef.harnessId !== state2.nativeRef.harnessId || record3.nativeRef.nativeSessionId !== state2.nativeRef.nativeSessionId || record3.nativeRef.formatVersion !== state2.nativeRef.formatVersion)) {
36270
+ 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))) {
35983
36271
  record3.faulted = true;
36272
+ releaseProvisionalWriter(record3);
35984
36273
  await send({
35985
36274
  kind: "output",
35986
36275
  sessionId: record3.id,
@@ -35991,7 +36280,7 @@ async function startHarnessBrokerServer(input) {
35991
36280
  type: "session.faulted",
35992
36281
  error: {
35993
36282
  code: "protocolError",
35994
- message: "Native Claude Session identity changed after open",
36283
+ message: "Native Harness Session identity changed after open",
35995
36284
  retryable: false,
35996
36285
  stage: "harnessBroker.identity"
35997
36286
  }
@@ -36017,7 +36306,7 @@ async function startHarnessBrokerServer(input) {
36017
36306
  type: "session.faulted",
36018
36307
  error: {
36019
36308
  code: "sessionBusy",
36020
- message: "Native Claude Session already has an active writer",
36309
+ message: "Native Harness Session already has an active writer",
36021
36310
  retryable: true,
36022
36311
  stage: "harnessBroker.identity"
36023
36312
  }
@@ -36115,8 +36404,11 @@ async function startHarnessBrokerServer(input) {
36115
36404
  if (request.method === "adapter.subagent.readSnapshot") {
36116
36405
  const subagents = input.adapter.subagents;
36117
36406
  if (!subagents)
36118
- return { ok: false, error: harnessError("Claude subagents are unavailable", false) };
36119
- return subagents.readSnapshot(subagentReadSnapshotSchema.parse(request.params));
36407
+ return { ok: false, error: harnessError("Harness subagents are unavailable", false) };
36408
+ const params = subagentReadSnapshotSchema.parse(request.params);
36409
+ if (params.parent.harnessId !== input.adapter.harnessId)
36410
+ return { ok: false, error: protocolError("Subagent parent belongs to another Harness") };
36411
+ return subagents.readSnapshot(params);
36120
36412
  }
36121
36413
  if (request.method === "adapter.sessionImport.list") {
36122
36414
  const { limit, offset } = brokerSessionImportListParamsSchema.parse(request.params);
@@ -36166,13 +36458,15 @@ async function startHarnessBrokerServer(input) {
36166
36458
  const openInput = brokerOpenInputSchema.parse(request.params);
36167
36459
  const sourceRef = openInput.kind === "create" ? void 0 : openInput.kind === "resume" ? openInput.nativeRef : openInput.sourceRef;
36168
36460
  const sourceNativeId = sourceRef?.nativeSessionId;
36461
+ if (sourceRef && sourceRef.harnessId !== input.adapter.harnessId)
36462
+ return { ok: false, error: protocolError("Native Session belongs to another Harness") };
36169
36463
  const sourceKey = sourceNativeId ? nativeWriterKey(sourceNativeId) : void 0;
36170
36464
  if (sourceKey && nativeWriters.has(sourceKey)) {
36171
36465
  return {
36172
36466
  ok: false,
36173
36467
  error: {
36174
36468
  code: "sessionBusy",
36175
- message: "Native Claude Session already has an active writer",
36469
+ message: "Native Harness Session already has an active writer",
36176
36470
  retryable: true,
36177
36471
  stage: "harnessBroker.open"
36178
36472
  }
@@ -36183,13 +36477,13 @@ async function startHarnessBrokerServer(input) {
36183
36477
  ok: false,
36184
36478
  error: {
36185
36479
  code: "sessionBusy",
36186
- message: "Native Claude Session identity claim is already pending",
36480
+ message: "Native Harness Session identity claim is already pending",
36187
36481
  retryable: true,
36188
36482
  stage: "harnessBroker.open"
36189
36483
  }
36190
36484
  };
36191
36485
  }
36192
- const openReservation = randomUUID14();
36486
+ const openReservation = randomUUID15();
36193
36487
  if (sourceKey)
36194
36488
  nativeWriters.set(sourceKey, openReservation);
36195
36489
  const provisionalReservation = openInput.kind === "create" ? openReservation : void 0;
@@ -36217,6 +36511,14 @@ async function startHarnessBrokerServer(input) {
36217
36511
  return { ok: false, error: harnessError("Harness broker connection closed") };
36218
36512
  }
36219
36513
  const openedRef = opened.value.initialState.nativeRef;
36514
+ if (openedRef && openedRef.harnessId !== input.adapter.harnessId) {
36515
+ releaseOpenReservations();
36516
+ await opened.value.close().catch(() => void 0);
36517
+ return {
36518
+ ok: false,
36519
+ error: protocolError("Adapter opened a Session for another Harness")
36520
+ };
36521
+ }
36220
36522
  if (sourceRef && (!openedRef || openedRef.harnessId !== sourceRef.harnessId || openedRef.formatVersion !== sourceRef.formatVersion || openInput.kind === "resume" && openedRef.nativeSessionId !== sourceRef.nativeSessionId)) {
36221
36523
  releaseOpenReservations();
36222
36524
  await opened.value.close().catch(() => void 0);
@@ -36224,7 +36526,7 @@ async function startHarnessBrokerServer(input) {
36224
36526
  ok: false,
36225
36527
  error: {
36226
36528
  code: "protocolError",
36227
- message: "Native Claude Session identity did not match the requested open",
36529
+ message: "Native Harness Session identity did not match the requested open",
36228
36530
  retryable: false,
36229
36531
  stage: "harnessBroker.open"
36230
36532
  }
@@ -36240,7 +36542,7 @@ async function startHarnessBrokerServer(input) {
36240
36542
  ok: false,
36241
36543
  error: {
36242
36544
  code: "sessionBusy",
36243
- message: "Native Claude Session already has an active writer",
36545
+ message: "Native Harness Session already has an active writer",
36244
36546
  retryable: true,
36245
36547
  stage: "harnessBroker.open"
36246
36548
  }
@@ -36252,6 +36554,7 @@ async function startHarnessBrokerServer(input) {
36252
36554
  generation: 1,
36253
36555
  owner: state.id,
36254
36556
  cwd: openInput.cwd,
36557
+ ...openInput.environment ? { environment: openInput.environment } : {},
36255
36558
  ...nativeId ? { nativeId } : {},
36256
36559
  ...opened.value.initialState.nativeRef ? { nativeRef: opened.value.initialState.nativeRef } : {},
36257
36560
  ...nativeKey ? { writerKey: nativeKey } : {},
@@ -36292,7 +36595,7 @@ async function startHarnessBrokerServer(input) {
36292
36595
  ok: false,
36293
36596
  error: {
36294
36597
  code: "sessionBusy",
36295
- message: "Native Claude Session identity has not been claimed yet",
36598
+ message: "Native Harness Session identity has not been claimed yet",
36296
36599
  retryable: true,
36297
36600
  stage: "harnessBroker.identity"
36298
36601
  }
@@ -36369,7 +36672,7 @@ async function startHarnessBrokerServer(input) {
36369
36672
  ok: false,
36370
36673
  error: {
36371
36674
  code: "sessionBusy",
36372
- message: "Faulted Claude Session has no authoritative native identity",
36675
+ message: "Faulted Harness Session has no authoritative native identity",
36373
36676
  retryable: false,
36374
36677
  stage: "harnessBroker.reopen"
36375
36678
  }
@@ -36381,7 +36684,12 @@ async function startHarnessBrokerServer(input) {
36381
36684
  record4.forwarderEpoch += 1;
36382
36685
  await oldSession.close().catch(() => void 0);
36383
36686
  await oldOutputTask.catch(() => void 0);
36384
- const reopened = await input.adapter.open({ kind: "resume", cwd: record4.cwd, nativeRef });
36687
+ const reopened = await input.adapter.open({
36688
+ kind: "resume",
36689
+ cwd: record4.cwd,
36690
+ nativeRef,
36691
+ ...record4.environment ? { environment: record4.environment } : {}
36692
+ });
36385
36693
  if (!reopened.ok)
36386
36694
  return reopened;
36387
36695
  const reopenedRef = reopened.value.initialState.nativeRef;
@@ -36391,7 +36699,7 @@ async function startHarnessBrokerServer(input) {
36391
36699
  ok: false,
36392
36700
  error: {
36393
36701
  code: "protocolError",
36394
- message: "Claude Aqua broker reopen changed the native Session identity",
36702
+ message: "Aqua Harness broker reopen changed the native Session identity",
36395
36703
  retryable: false,
36396
36704
  stage: "harnessBroker.reopen"
36397
36705
  }
@@ -36455,7 +36763,7 @@ async function startHarnessBrokerServer(input) {
36455
36763
  }
36456
36764
  state.authenticated = true;
36457
36765
  state.inputSequence = 1;
36458
- await send({ kind: "response", id: randomUUID14(), ok: true, value: { ready: true } });
36766
+ await send({ kind: "response", id: randomUUID15(), ok: true, value: { ready: true } });
36459
36767
  return;
36460
36768
  }
36461
36769
  const parsed = harnessBrokerRequestSchema.safeParse(raw);
@@ -36528,15 +36836,16 @@ async function startHarnessBrokerServer(input) {
36528
36836
  }
36529
36837
 
36530
36838
  // packages/host-runtime/src/aqua-harness-broker.ts
36531
- async function runClaudeAquaHarnessBroker(environment = process.env) {
36839
+ async function runClaudeAquaHarnessBroker(environment = process.env, requestedHarnessId = "claude-code") {
36840
+ const harnessId = harnessPluginIdSchema.parse(requestedHarnessId);
36532
36841
  if (process.platform !== "darwin") {
36533
- throw new Error("Claude Aqua Harness broker is available only on macOS");
36842
+ throw new Error("Aqua Harness broker is available only on macOS");
36534
36843
  }
36535
36844
  const { pluginRoots, pluginContext } = installedHarnessPluginOptions(environment);
36536
36845
  const plugins = await loadHarnessPlugins({
36537
36846
  roots: pluginRoots,
36538
36847
  context: pluginContext,
36539
- onlyIds: /* @__PURE__ */ new Set(["claude-code"]),
36848
+ onlyIds: /* @__PURE__ */ new Set([harnessId]),
36540
36849
  warmup: false,
36541
36850
  diagnose: (diagnostic) => process.stderr.write(`Harness plugin: ${JSON.stringify(diagnostic)}
36542
36851
  `)
@@ -36549,19 +36858,19 @@ async function runClaudeAquaHarnessBroker(environment = process.env) {
36549
36858
  let server;
36550
36859
  try {
36551
36860
  server = await startHarnessBrokerServer({
36552
- descriptorPath: defaultHarnessBrokerDescriptorPath(environment),
36553
- socketPath: defaultHarnessBrokerSocketPath(environment),
36861
+ descriptorPath: defaultHarnessBrokerDescriptorPath(environment, harnessId),
36862
+ socketPath: defaultHarnessBrokerSocketPath(environment, harnessId),
36554
36863
  adapter
36555
36864
  });
36556
36865
  } catch (error51) {
36557
36866
  await adapter.close().catch(() => void 0);
36558
36867
  throw error51;
36559
36868
  }
36560
- process.title = "codexhost claude-code Aqua harness broker";
36869
+ process.title = `codexhost ${harnessId} Aqua harness broker`;
36561
36870
  process.stdout.write(
36562
36871
  `${JSON.stringify({
36563
36872
  method: "codexhost/harness-broker/ready",
36564
- params: { protocolVersion: 1, harnessId: "claude-code" }
36873
+ params: { protocolVersion: 1, harnessId }
36565
36874
  })}
36566
36875
  `
36567
36876
  );
@@ -36584,7 +36893,7 @@ async function runClaudeAquaHarnessBroker(environment = process.env) {
36584
36893
 
36585
36894
  // packages/host-runtime/src/release-main.ts
36586
36895
  var arguments_ = process.argv.slice(2);
36587
- 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({
36896
+ 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({
36588
36897
  arguments: arguments_,
36589
36898
  environment: process.env,
36590
36899
  hostRuntimeUrl: import.meta.url