@liberseek/boft-cli-win32-arm64 0.6.9 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4283,7 +4283,7 @@ async function runDelegationCli(input) {
4283
4283
 
4284
4284
  // packages/host-runtime/src/run-host-runtime.ts
4285
4285
  import { randomBytes as randomBytes2 } from "node:crypto";
4286
- import path20 from "node:path";
4286
+ import path21 from "node:path";
4287
4287
  import { homedir as homedir2 } from "node:os";
4288
4288
  import { fileURLToPath as fileURLToPath2 } from "node:url";
4289
4289
 
@@ -5978,10 +5978,10 @@ function mergeDefs(...defs) {
5978
5978
  function cloneDef(schema) {
5979
5979
  return mergeDefs(schema._zod.def);
5980
5980
  }
5981
- function getElementAtPath(obj, path25) {
5982
- if (!path25)
5981
+ function getElementAtPath(obj, path26) {
5982
+ if (!path26)
5983
5983
  return obj;
5984
- return path25.reduce((acc, key) => acc?.[key], obj);
5984
+ return path26.reduce((acc, key) => acc?.[key], obj);
5985
5985
  }
5986
5986
  function promiseAllObject(promisesObj) {
5987
5987
  const keys = Object.keys(promisesObj);
@@ -6390,11 +6390,11 @@ function explicitlyAborted(x, startIndex = 0) {
6390
6390
  }
6391
6391
  return false;
6392
6392
  }
6393
- function prefixIssues(path25, issues) {
6393
+ function prefixIssues(path26, issues) {
6394
6394
  return issues.map((iss) => {
6395
6395
  var _a3;
6396
6396
  (_a3 = iss).path ?? (_a3.path = []);
6397
- iss.path.unshift(path25);
6397
+ iss.path.unshift(path26);
6398
6398
  return iss;
6399
6399
  });
6400
6400
  }
@@ -6541,16 +6541,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
6541
6541
  }
6542
6542
  function formatError(error51, mapper = (issue2) => issue2.message) {
6543
6543
  const fieldErrors = { _errors: [] };
6544
- const processError = (error52, path25 = []) => {
6544
+ const processError = (error52, path26 = []) => {
6545
6545
  for (const issue2 of error52.issues) {
6546
6546
  if (issue2.code === "invalid_union" && issue2.errors.length) {
6547
- issue2.errors.map((issues) => processError({ issues }, [...path25, ...issue2.path]));
6547
+ issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
6548
6548
  } else if (issue2.code === "invalid_key") {
6549
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6549
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6550
6550
  } else if (issue2.code === "invalid_element") {
6551
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6551
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6552
6552
  } else {
6553
- const fullpath = [...path25, ...issue2.path];
6553
+ const fullpath = [...path26, ...issue2.path];
6554
6554
  if (fullpath.length === 0) {
6555
6555
  fieldErrors._errors.push(mapper(issue2));
6556
6556
  } else {
@@ -6577,17 +6577,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
6577
6577
  }
6578
6578
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
6579
6579
  const result = { errors: [] };
6580
- const processError = (error52, path25 = []) => {
6580
+ const processError = (error52, path26 = []) => {
6581
6581
  var _a3, _b;
6582
6582
  for (const issue2 of error52.issues) {
6583
6583
  if (issue2.code === "invalid_union" && issue2.errors.length) {
6584
- issue2.errors.map((issues) => processError({ issues }, [...path25, ...issue2.path]));
6584
+ issue2.errors.map((issues) => processError({ issues }, [...path26, ...issue2.path]));
6585
6585
  } else if (issue2.code === "invalid_key") {
6586
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6586
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6587
6587
  } else if (issue2.code === "invalid_element") {
6588
- processError({ issues: issue2.issues }, [...path25, ...issue2.path]);
6588
+ processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6589
6589
  } else {
6590
- const fullpath = [...path25, ...issue2.path];
6590
+ const fullpath = [...path26, ...issue2.path];
6591
6591
  if (fullpath.length === 0) {
6592
6592
  result.errors.push(mapper(issue2));
6593
6593
  continue;
@@ -6619,8 +6619,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
6619
6619
  }
6620
6620
  function toDotPath(_path) {
6621
6621
  const segs = [];
6622
- const path25 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6623
- for (const seg of path25) {
6622
+ const path26 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6623
+ for (const seg of path26) {
6624
6624
  if (typeof seg === "number")
6625
6625
  segs.push(`[${seg}]`);
6626
6626
  else if (typeof seg === "symbol")
@@ -19312,13 +19312,13 @@ function resolveRef(ref, ctx) {
19312
19312
  if (!ref.startsWith("#")) {
19313
19313
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
19314
19314
  }
19315
- const path25 = ref.slice(1).split("/").filter(Boolean);
19316
- if (path25.length === 0) {
19315
+ const path26 = ref.slice(1).split("/").filter(Boolean);
19316
+ if (path26.length === 0) {
19317
19317
  return ctx.rootSchema;
19318
19318
  }
19319
19319
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
19320
- if (path25[0] === defsKey) {
19321
- const key = path25[1];
19320
+ if (path26[0] === defsKey) {
19321
+ const key = path26[1];
19322
19322
  if (!key || !ctx.defs[key]) {
19323
19323
  throw new Error(`Reference not found: ${ref}`);
19324
19324
  }
@@ -19729,6 +19729,48 @@ config(en_default());
19729
19729
  // packages/shared-contracts/dist/version.js
19730
19730
  var WORKSPACE_CONTRACT_VERSION = 1;
19731
19731
 
19732
+ // packages/shared-contracts/dist/idle-release.js
19733
+ var IDLE_RELEASE_SETTINGS_METHOD = "codexhost/settings/idle-release/set";
19734
+ var IDLE_RELEASE_TIMEOUT_MINUTES_MIN = 5;
19735
+ var IDLE_RELEASE_TIMEOUT_MINUTES_MAX = 1440;
19736
+ var idleReleaseSettingsSchema = external_exports.strictObject({
19737
+ enabled: external_exports.boolean(),
19738
+ timeoutMinutes: external_exports.number().int().min(IDLE_RELEASE_TIMEOUT_MINUTES_MIN).max(IDLE_RELEASE_TIMEOUT_MINUTES_MAX)
19739
+ });
19740
+ var DEFAULT_IDLE_RELEASE_SETTINGS = Object.freeze({
19741
+ enabled: false,
19742
+ timeoutMinutes: 30
19743
+ });
19744
+
19745
+ // packages/shared-contracts/dist/loaded-sessions.js
19746
+ var LOADED_SESSIONS_METHOD = "codexhost/sessions/loaded/list";
19747
+ var loadedSessionStateSchema = external_exports.enum([
19748
+ "idle",
19749
+ "running",
19750
+ "busy",
19751
+ "closing",
19752
+ "failed",
19753
+ "blocked"
19754
+ ]);
19755
+ var loadedSessionReasonSchema = external_exports.enum([
19756
+ "none",
19757
+ "disabled",
19758
+ "timeout",
19759
+ "operation",
19760
+ "background",
19761
+ "identity",
19762
+ "persistence",
19763
+ "closeFailed"
19764
+ ]);
19765
+ var loadedSessionsSchema = external_exports.array(external_exports.strictObject({
19766
+ threadId: external_exports.string(),
19767
+ title: external_exports.string(),
19768
+ harnessId: external_exports.string(),
19769
+ state: loadedSessionStateSchema,
19770
+ reason: loadedSessionReasonSchema,
19771
+ inactiveMs: external_exports.number().nonnegative()
19772
+ }));
19773
+
19732
19774
  // packages/shared-contracts/dist/ids.js
19733
19775
  var opaqueIdSchema = external_exports.string().refine((value2) => value2.trim().length > 0, {
19734
19776
  message: "Identifier must not be empty or whitespace"
@@ -20919,10 +20961,20 @@ function processIdentity(pid) {
20919
20961
  if (systemErrorCode2(error51) !== "EPERM")
20920
20962
  return null;
20921
20963
  }
20922
- if (process.platform !== "win32") {
20964
+ if (process.platform !== "win32" && process.platform !== "darwin") {
20923
20965
  return { executablePath: null, startedAt: null };
20924
20966
  }
20925
20967
  try {
20968
+ if (process.platform === "darwin") {
20969
+ const result2 = execFileSync("/bin/ps", ["-p", String(pid), "-o", "lstart="], {
20970
+ encoding: "utf8",
20971
+ stdio: ["ignore", "pipe", "ignore"],
20972
+ env: { ...process.env, LC_ALL: "C" },
20973
+ timeout: 1e3
20974
+ }).trim();
20975
+ const startedAt2 = Date.parse(result2);
20976
+ return { executablePath: null, startedAt: Number.isFinite(startedAt2) ? startedAt2 : null };
20977
+ }
20926
20978
  const query = [
20927
20979
  "$ErrorActionPreference = 'Stop'",
20928
20980
  `$process = Get-Process -Id ${pid}`,
@@ -20964,7 +21016,7 @@ function lockOwnerIsLive(lock) {
20964
21016
  const identity = processIdentity(lock.pid);
20965
21017
  if (!identity)
20966
21018
  return false;
20967
- if (process.platform !== "win32")
21019
+ if (process.platform !== "win32" && process.platform !== "darwin")
20968
21020
  return true;
20969
21021
  if (identity.executablePath && lock.executablePath) {
20970
21022
  if (normalizeExecutablePath(identity.executablePath) !== normalizeExecutablePath(lock.executablePath)) {
@@ -21920,6 +21972,8 @@ function projectCodexQuestionRequest(input) {
21920
21972
  const mapped = labels.get(value2);
21921
21973
  if (mapped !== void 0)
21922
21974
  return mapped;
21975
+ if (question.options.some((option) => option.value === value2))
21976
+ return value2;
21923
21977
  if (question.allowOther)
21924
21978
  return value2;
21925
21979
  throw responseError2("contains an undeclared choice");
@@ -22194,6 +22248,681 @@ function projectCodexRateLimitsToCredits(usage, resetCredits) {
22194
22248
  };
22195
22249
  }
22196
22250
 
22251
+ // node_modules/diff/libesm/diff/base.js
22252
+ var Diff = class {
22253
+ diff(oldStr, newStr, options2 = {}) {
22254
+ let callback;
22255
+ if (typeof options2 === "function") {
22256
+ callback = options2;
22257
+ options2 = {};
22258
+ } else if ("callback" in options2) {
22259
+ callback = options2.callback;
22260
+ }
22261
+ const oldString = this.castInput(oldStr, options2);
22262
+ const newString = this.castInput(newStr, options2);
22263
+ const oldTokens = this.removeEmpty(this.tokenize(oldString, options2));
22264
+ const newTokens = this.removeEmpty(this.tokenize(newString, options2));
22265
+ return this.diffWithOptionsObj(oldTokens, newTokens, options2, callback);
22266
+ }
22267
+ diffWithOptionsObj(oldTokens, newTokens, options2, callback) {
22268
+ var _a3;
22269
+ const done = (value2) => {
22270
+ value2 = this.postProcess(value2, options2);
22271
+ if (callback) {
22272
+ setTimeout(function() {
22273
+ callback(value2);
22274
+ }, 0);
22275
+ return void 0;
22276
+ } else {
22277
+ return value2;
22278
+ }
22279
+ };
22280
+ const newLen = newTokens.length, oldLen = oldTokens.length;
22281
+ let editLength = 1;
22282
+ let maxEditLength = newLen + oldLen;
22283
+ if (options2.maxEditLength != null) {
22284
+ maxEditLength = Math.min(maxEditLength, options2.maxEditLength);
22285
+ }
22286
+ const maxExecutionTime = (_a3 = options2.timeout) !== null && _a3 !== void 0 ? _a3 : Infinity;
22287
+ const abortAfterTimestamp = Date.now() + maxExecutionTime;
22288
+ const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
22289
+ let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options2);
22290
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
22291
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
22292
+ }
22293
+ let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
22294
+ const execEditLength = () => {
22295
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
22296
+ let basePath;
22297
+ const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
22298
+ if (removePath) {
22299
+ bestPath[diagonalPath - 1] = void 0;
22300
+ }
22301
+ let canAdd = false;
22302
+ if (addPath) {
22303
+ const addPathNewPos = addPath.oldPos - diagonalPath;
22304
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
22305
+ }
22306
+ const canRemove = removePath && removePath.oldPos + 1 < oldLen;
22307
+ if (!canAdd && !canRemove) {
22308
+ bestPath[diagonalPath] = void 0;
22309
+ continue;
22310
+ }
22311
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
22312
+ basePath = this.addToPath(addPath, true, false, 0, options2);
22313
+ } else {
22314
+ basePath = this.addToPath(removePath, false, true, 1, options2);
22315
+ }
22316
+ newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options2);
22317
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
22318
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
22319
+ } else {
22320
+ bestPath[diagonalPath] = basePath;
22321
+ if (basePath.oldPos + 1 >= oldLen) {
22322
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
22323
+ }
22324
+ if (newPos + 1 >= newLen) {
22325
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
22326
+ }
22327
+ }
22328
+ }
22329
+ editLength++;
22330
+ };
22331
+ if (callback) {
22332
+ (function exec() {
22333
+ setTimeout(function() {
22334
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
22335
+ return callback(void 0);
22336
+ }
22337
+ if (!execEditLength()) {
22338
+ exec();
22339
+ }
22340
+ }, 0);
22341
+ })();
22342
+ } else {
22343
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
22344
+ const ret = execEditLength();
22345
+ if (ret) {
22346
+ return ret;
22347
+ }
22348
+ }
22349
+ }
22350
+ }
22351
+ addToPath(path26, added, removed, oldPosInc, options2) {
22352
+ const last = path26.lastComponent;
22353
+ if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
22354
+ return {
22355
+ oldPos: path26.oldPos + oldPosInc,
22356
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
22357
+ };
22358
+ } else {
22359
+ return {
22360
+ oldPos: path26.oldPos + oldPosInc,
22361
+ lastComponent: { count: 1, added, removed, previousComponent: last }
22362
+ };
22363
+ }
22364
+ }
22365
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options2) {
22366
+ const newLen = newTokens.length, oldLen = oldTokens.length;
22367
+ let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
22368
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options2)) {
22369
+ newPos++;
22370
+ oldPos++;
22371
+ commonCount++;
22372
+ if (options2.oneChangePerToken) {
22373
+ basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
22374
+ }
22375
+ }
22376
+ if (commonCount && !options2.oneChangePerToken) {
22377
+ basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
22378
+ }
22379
+ basePath.oldPos = oldPos;
22380
+ return newPos;
22381
+ }
22382
+ equals(left, right, options2) {
22383
+ if (options2.comparator) {
22384
+ return options2.comparator(left, right);
22385
+ } else {
22386
+ return left === right || !!options2.ignoreCase && left.toLowerCase() === right.toLowerCase();
22387
+ }
22388
+ }
22389
+ removeEmpty(array2) {
22390
+ const ret = [];
22391
+ for (let i = 0; i < array2.length; i++) {
22392
+ if (array2[i]) {
22393
+ ret.push(array2[i]);
22394
+ }
22395
+ }
22396
+ return ret;
22397
+ }
22398
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22399
+ castInput(value2, options2) {
22400
+ return value2;
22401
+ }
22402
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22403
+ tokenize(value2, options2) {
22404
+ return Array.from(value2);
22405
+ }
22406
+ join(chars) {
22407
+ return chars.join("");
22408
+ }
22409
+ postProcess(changeObjects, options2) {
22410
+ return changeObjects;
22411
+ }
22412
+ get useLongestToken() {
22413
+ return false;
22414
+ }
22415
+ buildValues(lastComponent, newTokens, oldTokens) {
22416
+ const components = [];
22417
+ let nextComponent;
22418
+ while (lastComponent) {
22419
+ components.push(lastComponent);
22420
+ nextComponent = lastComponent.previousComponent;
22421
+ delete lastComponent.previousComponent;
22422
+ lastComponent = nextComponent;
22423
+ }
22424
+ components.reverse();
22425
+ const componentLen = components.length;
22426
+ let componentPos = 0, newPos = 0, oldPos = 0;
22427
+ for (; componentPos < componentLen; componentPos++) {
22428
+ const component = components[componentPos];
22429
+ if (!component.removed) {
22430
+ if (!component.added && this.useLongestToken) {
22431
+ let value2 = newTokens.slice(newPos, newPos + component.count);
22432
+ value2 = value2.map(function(value3, i) {
22433
+ const oldValue = oldTokens[oldPos + i];
22434
+ return oldValue.length > value3.length ? oldValue : value3;
22435
+ });
22436
+ component.value = this.join(value2);
22437
+ } else {
22438
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
22439
+ }
22440
+ newPos += component.count;
22441
+ if (!component.added) {
22442
+ oldPos += component.count;
22443
+ }
22444
+ } else {
22445
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
22446
+ oldPos += component.count;
22447
+ }
22448
+ }
22449
+ return components;
22450
+ }
22451
+ };
22452
+
22453
+ // node_modules/diff/libesm/diff/line.js
22454
+ var LineDiff = class extends Diff {
22455
+ constructor() {
22456
+ super(...arguments);
22457
+ this.tokenize = tokenize;
22458
+ }
22459
+ equals(left, right, options2) {
22460
+ if (options2.ignoreWhitespace) {
22461
+ if (!options2.newlineIsToken || !left.includes("\n")) {
22462
+ left = left.trim();
22463
+ }
22464
+ if (!options2.newlineIsToken || !right.includes("\n")) {
22465
+ right = right.trim();
22466
+ }
22467
+ } else if (options2.ignoreNewlineAtEof && !options2.newlineIsToken) {
22468
+ if (left.endsWith("\n")) {
22469
+ left = left.slice(0, -1);
22470
+ }
22471
+ if (right.endsWith("\n")) {
22472
+ right = right.slice(0, -1);
22473
+ }
22474
+ }
22475
+ return super.equals(left, right, options2);
22476
+ }
22477
+ };
22478
+ var lineDiff = new LineDiff();
22479
+ function diffLines(oldStr, newStr, options2) {
22480
+ return lineDiff.diff(oldStr, newStr, options2);
22481
+ }
22482
+ function tokenize(value2, options2) {
22483
+ if (options2.stripTrailingCr) {
22484
+ value2 = value2.replace(/\r\n/g, "\n");
22485
+ }
22486
+ const retLines = [], linesAndNewlines = value2.split(/(\n|\r\n)/);
22487
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
22488
+ linesAndNewlines.pop();
22489
+ }
22490
+ for (let i = 0; i < linesAndNewlines.length; i++) {
22491
+ const line = linesAndNewlines[i];
22492
+ if (i % 2 && !options2.newlineIsToken) {
22493
+ retLines[retLines.length - 1] += line;
22494
+ } else {
22495
+ retLines.push(line);
22496
+ }
22497
+ }
22498
+ return retLines;
22499
+ }
22500
+
22501
+ // node_modules/diff/libesm/diff/array.js
22502
+ var ArrayDiff = class extends Diff {
22503
+ tokenize(value2) {
22504
+ return value2.slice();
22505
+ }
22506
+ join(value2) {
22507
+ return value2;
22508
+ }
22509
+ removeEmpty(value2) {
22510
+ return value2;
22511
+ }
22512
+ };
22513
+ var arrayDiff = new ArrayDiff();
22514
+ function diffArrays(oldArr, newArr, options2) {
22515
+ return arrayDiff.diff(oldArr, newArr, options2);
22516
+ }
22517
+
22518
+ // node_modules/diff/libesm/patch/parse.js
22519
+ function parsePatch(uniDiff) {
22520
+ const diffstr = uniDiff.split(/\n/), list = [];
22521
+ let i = 0;
22522
+ function parseIndex() {
22523
+ const index = {};
22524
+ list.push(index);
22525
+ while (i < diffstr.length) {
22526
+ const line = diffstr[i];
22527
+ if (/^(---|\+\+\+|@@)\s/.test(line)) {
22528
+ break;
22529
+ }
22530
+ const header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
22531
+ if (header) {
22532
+ index.index = header[1];
22533
+ }
22534
+ i++;
22535
+ }
22536
+ parseFileHeader(index);
22537
+ parseFileHeader(index);
22538
+ index.hunks = [];
22539
+ while (i < diffstr.length) {
22540
+ const line = diffstr[i];
22541
+ if (/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line)) {
22542
+ break;
22543
+ } else if (/^@@/.test(line)) {
22544
+ index.hunks.push(parseHunk());
22545
+ } else if (line) {
22546
+ throw new Error("Unknown line " + (i + 1) + " " + JSON.stringify(line));
22547
+ } else {
22548
+ i++;
22549
+ }
22550
+ }
22551
+ }
22552
+ function parseFileHeader(index) {
22553
+ const fileHeader = /^(---|\+\+\+)\s+(.*)\r?$/.exec(diffstr[i]);
22554
+ if (fileHeader) {
22555
+ const data = fileHeader[2].split(" ", 2), header = (data[1] || "").trim();
22556
+ let fileName = data[0].replace(/\\\\/g, "\\");
22557
+ if (/^".*"$/.test(fileName)) {
22558
+ fileName = fileName.substr(1, fileName.length - 2);
22559
+ }
22560
+ if (fileHeader[1] === "---") {
22561
+ index.oldFileName = fileName;
22562
+ index.oldHeader = header;
22563
+ } else {
22564
+ index.newFileName = fileName;
22565
+ index.newHeader = header;
22566
+ }
22567
+ i++;
22568
+ }
22569
+ }
22570
+ function parseHunk() {
22571
+ var _a3;
22572
+ const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
22573
+ const hunk = {
22574
+ oldStart: +chunkHeader[1],
22575
+ oldLines: typeof chunkHeader[2] === "undefined" ? 1 : +chunkHeader[2],
22576
+ newStart: +chunkHeader[3],
22577
+ newLines: typeof chunkHeader[4] === "undefined" ? 1 : +chunkHeader[4],
22578
+ lines: []
22579
+ };
22580
+ if (hunk.oldLines === 0) {
22581
+ hunk.oldStart += 1;
22582
+ }
22583
+ if (hunk.newLines === 0) {
22584
+ hunk.newStart += 1;
22585
+ }
22586
+ let addCount = 0, removeCount = 0;
22587
+ for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a3 = diffstr[i]) === null || _a3 === void 0 ? void 0 : _a3.startsWith("\\"))); i++) {
22588
+ const operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? " " : diffstr[i][0];
22589
+ if (operation === "+" || operation === "-" || operation === " " || operation === "\\") {
22590
+ hunk.lines.push(diffstr[i]);
22591
+ if (operation === "+") {
22592
+ addCount++;
22593
+ } else if (operation === "-") {
22594
+ removeCount++;
22595
+ } else if (operation === " ") {
22596
+ addCount++;
22597
+ removeCount++;
22598
+ }
22599
+ } else {
22600
+ throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
22601
+ }
22602
+ }
22603
+ if (!addCount && hunk.newLines === 1) {
22604
+ hunk.newLines = 0;
22605
+ }
22606
+ if (!removeCount && hunk.oldLines === 1) {
22607
+ hunk.oldLines = 0;
22608
+ }
22609
+ if (addCount !== hunk.newLines) {
22610
+ throw new Error("Added line count did not match for hunk at line " + (chunkHeaderIndex + 1));
22611
+ }
22612
+ if (removeCount !== hunk.oldLines) {
22613
+ throw new Error("Removed line count did not match for hunk at line " + (chunkHeaderIndex + 1));
22614
+ }
22615
+ return hunk;
22616
+ }
22617
+ while (i < diffstr.length) {
22618
+ parseIndex();
22619
+ }
22620
+ return list;
22621
+ }
22622
+
22623
+ // node_modules/diff/libesm/patch/create.js
22624
+ function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options2) {
22625
+ let optionsObj;
22626
+ if (!options2) {
22627
+ optionsObj = {};
22628
+ } else if (typeof options2 === "function") {
22629
+ optionsObj = { callback: options2 };
22630
+ } else {
22631
+ optionsObj = options2;
22632
+ }
22633
+ if (typeof optionsObj.context === "undefined") {
22634
+ optionsObj.context = 4;
22635
+ }
22636
+ const context = optionsObj.context;
22637
+ if (optionsObj.newlineIsToken) {
22638
+ throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
22639
+ }
22640
+ if (!optionsObj.callback) {
22641
+ return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
22642
+ } else {
22643
+ const { callback } = optionsObj;
22644
+ diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
22645
+ const patch = diffLinesResultToPatch(diff);
22646
+ callback(patch);
22647
+ } }));
22648
+ }
22649
+ function diffLinesResultToPatch(diff) {
22650
+ if (!diff) {
22651
+ return;
22652
+ }
22653
+ diff.push({ value: "", lines: [] });
22654
+ function contextLines(lines) {
22655
+ return lines.map(function(entry) {
22656
+ return " " + entry;
22657
+ });
22658
+ }
22659
+ const hunks = [];
22660
+ let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
22661
+ for (let i = 0; i < diff.length; i++) {
22662
+ const current = diff[i], lines = current.lines || splitLines(current.value);
22663
+ current.lines = lines;
22664
+ if (current.added || current.removed) {
22665
+ if (!oldRangeStart) {
22666
+ const prev = diff[i - 1];
22667
+ oldRangeStart = oldLine;
22668
+ newRangeStart = newLine;
22669
+ if (prev) {
22670
+ curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
22671
+ oldRangeStart -= curRange.length;
22672
+ newRangeStart -= curRange.length;
22673
+ }
22674
+ }
22675
+ for (const line of lines) {
22676
+ curRange.push((current.added ? "+" : "-") + line);
22677
+ }
22678
+ if (current.added) {
22679
+ newLine += lines.length;
22680
+ } else {
22681
+ oldLine += lines.length;
22682
+ }
22683
+ } else {
22684
+ if (oldRangeStart) {
22685
+ if (lines.length <= context * 2 && i < diff.length - 2) {
22686
+ for (const line of contextLines(lines)) {
22687
+ curRange.push(line);
22688
+ }
22689
+ } else {
22690
+ const contextSize = Math.min(lines.length, context);
22691
+ for (const line of contextLines(lines.slice(0, contextSize))) {
22692
+ curRange.push(line);
22693
+ }
22694
+ const hunk = {
22695
+ oldStart: oldRangeStart,
22696
+ oldLines: oldLine - oldRangeStart + contextSize,
22697
+ newStart: newRangeStart,
22698
+ newLines: newLine - newRangeStart + contextSize,
22699
+ lines: curRange
22700
+ };
22701
+ hunks.push(hunk);
22702
+ oldRangeStart = 0;
22703
+ newRangeStart = 0;
22704
+ curRange = [];
22705
+ }
22706
+ }
22707
+ oldLine += lines.length;
22708
+ newLine += lines.length;
22709
+ }
22710
+ }
22711
+ for (const hunk of hunks) {
22712
+ for (let i = 0; i < hunk.lines.length; i++) {
22713
+ if (hunk.lines[i].endsWith("\n")) {
22714
+ hunk.lines[i] = hunk.lines[i].slice(0, -1);
22715
+ } else {
22716
+ hunk.lines.splice(i + 1, 0, "\");
22717
+ i++;
22718
+ }
22719
+ }
22720
+ }
22721
+ return {
22722
+ oldFileName,
22723
+ newFileName,
22724
+ oldHeader,
22725
+ newHeader,
22726
+ hunks
22727
+ };
22728
+ }
22729
+ }
22730
+ function formatPatch(patch) {
22731
+ if (Array.isArray(patch)) {
22732
+ return patch.map(formatPatch).join("\n");
22733
+ }
22734
+ const ret = [];
22735
+ if (patch.oldFileName == patch.newFileName) {
22736
+ ret.push("Index: " + patch.oldFileName);
22737
+ }
22738
+ ret.push("===================================================================");
22739
+ ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : " " + patch.oldHeader));
22740
+ ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : " " + patch.newHeader));
22741
+ for (let i = 0; i < patch.hunks.length; i++) {
22742
+ const hunk = patch.hunks[i];
22743
+ if (hunk.oldLines === 0) {
22744
+ hunk.oldStart -= 1;
22745
+ }
22746
+ if (hunk.newLines === 0) {
22747
+ hunk.newStart -= 1;
22748
+ }
22749
+ ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
22750
+ for (const line of hunk.lines) {
22751
+ ret.push(line);
22752
+ }
22753
+ }
22754
+ return ret.join("\n") + "\n";
22755
+ }
22756
+ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options2) {
22757
+ if (typeof options2 === "function") {
22758
+ options2 = { callback: options2 };
22759
+ }
22760
+ if (!(options2 === null || options2 === void 0 ? void 0 : options2.callback)) {
22761
+ const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options2);
22762
+ if (!patchObj) {
22763
+ return;
22764
+ }
22765
+ return formatPatch(patchObj);
22766
+ } else {
22767
+ const { callback } = options2;
22768
+ structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options2), { callback: (patchObj) => {
22769
+ if (!patchObj) {
22770
+ callback(void 0);
22771
+ } else {
22772
+ callback(formatPatch(patchObj));
22773
+ }
22774
+ } }));
22775
+ }
22776
+ }
22777
+ function splitLines(text2) {
22778
+ const hasTrailingNl = text2.endsWith("\n");
22779
+ const result = text2.split("\n").map((line) => line + "\n");
22780
+ if (hasTrailingNl) {
22781
+ result.pop();
22782
+ } else {
22783
+ result.push(result.pop().slice(0, -1));
22784
+ }
22785
+ return result;
22786
+ }
22787
+
22788
+ // packages/protocol-core/dist/file-change-summary.js
22789
+ import path6 from "node:path";
22790
+ function filePathKey(file2, cwd) {
22791
+ const windows = /^[a-z]:[/\\]/i.test(cwd) || /^[a-z]:[/\\]/i.test(file2);
22792
+ const paths = windows ? path6.win32 : path6.posix;
22793
+ const resolved = paths.resolve(cwd, file2).replaceAll("\\", "/");
22794
+ return windows ? resolved.toLowerCase() : resolved;
22795
+ }
22796
+ function composePatches(changes) {
22797
+ if (changes.some((change) => change.diffScope === "fragment"))
22798
+ return null;
22799
+ const original = [];
22800
+ const current = [];
22801
+ for (const change of changes) {
22802
+ let patches;
22803
+ try {
22804
+ patches = parsePatch(change.unifiedDiff);
22805
+ } catch {
22806
+ return null;
22807
+ }
22808
+ const [patch] = patches;
22809
+ if (!patch || patches.length !== 1)
22810
+ return null;
22811
+ const hunks2 = patch.hunks;
22812
+ for (const hunk2 of [...hunks2].reverse()) {
22813
+ const start = hunk2.oldStart - 1;
22814
+ while (current.length < start + hunk2.oldLines) {
22815
+ const line = {};
22816
+ original.push(line);
22817
+ current.push(line);
22818
+ }
22819
+ const replacement = [];
22820
+ let offset = start;
22821
+ for (const [i, entry] of hunk2.lines.entries()) {
22822
+ const operation = entry[0];
22823
+ if (operation === "\\")
22824
+ continue;
22825
+ const text2 = entry.slice(1) + (hunk2.lines[i + 1]?.startsWith("\\") ? "" : "\n");
22826
+ if (operation === "+")
22827
+ replacement.push({ text: text2 });
22828
+ else {
22829
+ const line = current[offset++];
22830
+ if (!line || line.text !== void 0 && line.text !== text2)
22831
+ return null;
22832
+ line.text = text2;
22833
+ if (operation === " ")
22834
+ replacement.push(line);
22835
+ }
22836
+ }
22837
+ current.splice(start, hunk2.oldLines, ...replacement);
22838
+ }
22839
+ }
22840
+ const hunks = [];
22841
+ let oldStart = 1;
22842
+ let newStart = 1;
22843
+ let hunk;
22844
+ for (const part of diffArrays(original, current, {
22845
+ comparator: (a, b) => a === b || a.text !== void 0 && a.text === b.text
22846
+ })) {
22847
+ if (!part.added && !part.removed) {
22848
+ hunk = void 0;
22849
+ oldStart += part.count;
22850
+ newStart += part.count;
22851
+ continue;
22852
+ }
22853
+ if (!hunk) {
22854
+ hunk = { oldStart, newStart, oldLines: 0, newLines: 0, lines: [] };
22855
+ hunks.push(hunk);
22856
+ }
22857
+ for (const line of part.value) {
22858
+ const text2 = line.text;
22859
+ if (text2 === void 0)
22860
+ return null;
22861
+ hunk.lines.push((part.added ? "+" : "-") + text2.replace(/\n$/, ""));
22862
+ if (!text2.endsWith("\n"))
22863
+ hunk.lines.push("\");
22864
+ }
22865
+ if (part.added) {
22866
+ hunk.newLines += part.count;
22867
+ newStart += part.count;
22868
+ } else {
22869
+ hunk.oldLines += part.count;
22870
+ oldStart += part.count;
22871
+ }
22872
+ }
22873
+ return hunks;
22874
+ }
22875
+ function summarizeFileChanges(changes, cwd) {
22876
+ const groups = /* @__PURE__ */ new Map();
22877
+ for (const change of changes) {
22878
+ const key = filePathKey(change.path, cwd);
22879
+ const group = groups.get(key);
22880
+ if (group)
22881
+ group.push(change);
22882
+ else
22883
+ groups.set(key, [change]);
22884
+ }
22885
+ return [...groups.values()].flatMap((group) => {
22886
+ const first = group[0];
22887
+ if (group.length === 1)
22888
+ return [first];
22889
+ const last = group.at(-1) ?? first;
22890
+ const hunks = composePatches(group);
22891
+ const kind = last.kind === "delete" ? "delete" : first.kind === "add" ? "add" : "update";
22892
+ if (hunks) {
22893
+ if (hunks.length === 0 && first.kind !== "add" === (last.kind !== "delete"))
22894
+ return [];
22895
+ return [
22896
+ {
22897
+ path: first.path,
22898
+ kind,
22899
+ unifiedDiff: formatPatch({
22900
+ oldFileName: first.kind === "add" ? "/dev/null" : `a/${first.path}`,
22901
+ newFileName: last.kind === "delete" ? "/dev/null" : `b/${first.path}`,
22902
+ oldHeader: "",
22903
+ newHeader: "",
22904
+ hunks
22905
+ })
22906
+ }
22907
+ ];
22908
+ }
22909
+ const bodies = group.map(({ unifiedDiff }) => {
22910
+ const start = unifiedDiff.indexOf("@@");
22911
+ return start < 0 ? unifiedDiff : unifiedDiff.slice(start);
22912
+ });
22913
+ const headerEnd = first.unifiedDiff.indexOf("@@");
22914
+ const header = headerEnd < 0 ? "" : first.unifiedDiff.slice(0, headerEnd);
22915
+ return [
22916
+ {
22917
+ path: first.path,
22918
+ kind,
22919
+ unifiedDiff: header + bodies.join("\n"),
22920
+ diffScope: "fragment"
22921
+ }
22922
+ ];
22923
+ });
22924
+ }
22925
+
22197
22926
  // packages/protocol-core/dist/codex-ui-projector.js
22198
22927
  function resolvedItemDurationMs(item, startedAtMs, completedAtMs) {
22199
22928
  if ((item.type === "commandExecution" || item.type === "toolExecution" || item.type === "reasoning" || item.type === "agentMessage") && item.durationMs !== void 0) {
@@ -22215,17 +22944,17 @@ function itemStatus(outcome) {
22215
22944
  function isRecord5(value2) {
22216
22945
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
22217
22946
  }
22218
- function nestedString(value2, keys) {
22947
+ function nestedString(value2, keys, preserveText = false) {
22219
22948
  if (!isRecord5(value2))
22220
22949
  return void 0;
22221
22950
  for (const key of keys) {
22222
22951
  const field = value2[key];
22223
- if (typeof field === "string" && field.trim().length > 0)
22224
- return field.trim();
22952
+ if (typeof field === "string" && (preserveText || field.trim().length > 0))
22953
+ return preserveText ? field : field.trim();
22225
22954
  }
22226
22955
  for (const wrapper of ["input", "arguments", "params"]) {
22227
- const nested = nestedString(value2[wrapper], keys);
22228
- if (nested)
22956
+ const nested = nestedString(value2[wrapper], keys, preserveText);
22957
+ if (nested !== void 0)
22229
22958
  return nested;
22230
22959
  }
22231
22960
  return void 0;
@@ -22290,24 +23019,7 @@ function isWriteTool(toolName) {
22290
23019
  return ["write", "writefile", "filewrite", "create", "createfile"].includes(compactToolName(toolName));
22291
23020
  }
22292
23021
  function simpleUnifiedDiff(displayedPath, oldText, newText, kind) {
22293
- const oldLines = oldText === "" ? [] : oldText.split("\n");
22294
- const newLines = newText === "" ? [] : newText.split("\n");
22295
- if (oldLines.at(-1) === "")
22296
- oldLines.pop();
22297
- if (newLines.at(-1) === "")
22298
- newLines.pop();
22299
- const oldHeader = kind === "add" ? "/dev/null" : `a/${displayedPath}`;
22300
- const newHeader = `b/${displayedPath}`;
22301
- const oldRange = kind === "add" ? "0,0" : `1,${oldLines.length}`;
22302
- const newRange = newLines.length === 0 ? "0,0" : `1,${newLines.length}`;
22303
- return [
22304
- `--- ${oldHeader}`,
22305
- `+++ ${newHeader}`,
22306
- `@@ -${oldRange} +${newRange} @@`,
22307
- ...oldLines.map((line) => `-${line}`),
22308
- ...newLines.map((line) => `+${line}`),
22309
- ""
22310
- ].join("\n");
23022
+ return createTwoFilesPatch(kind === "add" ? "/dev/null" : `a/${displayedPath}`, `b/${displayedPath}`, oldText, newText);
22311
23023
  }
22312
23024
  function fileChangeFromTool(toolName, args) {
22313
23025
  if (!isFileMutatingTool(toolName))
@@ -22316,40 +23028,27 @@ function fileChangeFromTool(toolName, args) {
22316
23028
  if (!displayedPath)
22317
23029
  return null;
22318
23030
  if (isWriteTool(toolName)) {
22319
- const content = nestedString(args, [
22320
- "content",
22321
- "new_string",
22322
- "newString",
22323
- "newText",
22324
- "file_text",
22325
- "text",
22326
- "new"
22327
- ]);
23031
+ const content = nestedString(args, ["content", "new_string", "newString", "newText", "file_text", "text", "new"], true);
22328
23032
  if (content === void 0)
22329
23033
  return null;
22330
23034
  return [
22331
23035
  {
22332
23036
  path: displayedPath,
22333
23037
  kind: "add",
23038
+ diffScope: "fragment",
22334
23039
  unifiedDiff: simpleUnifiedDiff(displayedPath, "", content, "add")
22335
23040
  }
22336
23041
  ];
22337
23042
  }
22338
- const oldText = nestedString(args, ["old_string", "oldString", "oldText", "old_text", "old"]);
22339
- const newText = nestedString(args, [
22340
- "new_string",
22341
- "newString",
22342
- "newText",
22343
- "new_text",
22344
- "content",
22345
- "new"
22346
- ]);
23043
+ const oldText = nestedString(args, ["old_string", "oldString", "oldText", "old_text", "old"], true);
23044
+ const newText = nestedString(args, ["new_string", "newString", "newText", "new_text", "content", "new"], true);
22347
23045
  if (oldText === void 0 || newText === void 0)
22348
23046
  return null;
22349
23047
  return [
22350
23048
  {
22351
23049
  path: displayedPath,
22352
23050
  kind: "update",
23051
+ diffScope: "fragment",
22353
23052
  unifiedDiff: simpleUnifiedDiff(displayedPath, oldText, newText, "update")
22354
23053
  }
22355
23054
  ];
@@ -22360,21 +23059,25 @@ function projectFileChangeKind(kind) {
22360
23059
  return { type: kind };
22361
23060
  }
22362
23061
  function projectFileChanges(changes) {
22363
- return changes.map(({ path: path25, kind, unifiedDiff }) => ({
22364
- path: path25,
23062
+ return changes.map(({ path: path26, kind, unifiedDiff }) => ({
23063
+ path: path26,
22365
23064
  kind: projectFileChangeKind(kind),
22366
23065
  diff: unifiedDiff
22367
23066
  }));
22368
23067
  }
22369
- function wireFileChangeItem(projected) {
22370
- if (projected.item.type === "fileChange")
22371
- return projected.item;
22372
- if (!projected.wireFileChanges)
23068
+ function itemFileChanges(item) {
23069
+ return item.type === "fileChange" ? item.changes : item.type === "toolExecution" ? fileChangeFromTool(item.toolName, item.arguments) : null;
23070
+ }
23071
+ function summarizeHostFiles(items, cwd) {
23072
+ const first = items.find(({ item }) => itemFileChanges(item) !== null);
23073
+ if (!first)
22373
23074
  return null;
23075
+ const nativeSources = new Set(items.flatMap(({ item }) => item.type === "fileChange" ? item.sourceItemIds ?? [] : []));
23076
+ const changes = items.flatMap(({ item, outcome }) => outcome && outcome.status !== "succeeded" || nativeSources.has(item.itemId) ? [] : itemFileChanges(item) ?? []);
22374
23077
  return {
22375
23078
  type: "fileChange",
22376
- itemId: projected.item.itemId,
22377
- changes: projected.wireFileChanges
23079
+ itemId: first.item.itemId,
23080
+ changes: summarizeFileChanges(changes, cwd)
22378
23081
  };
22379
23082
  }
22380
23083
  function isTodoTool(toolName) {
@@ -22652,6 +23355,7 @@ function historicalStatus(outcome) {
22652
23355
  }
22653
23356
  function projectHistoricalTurn(input) {
22654
23357
  const { turnId, cwd, snapshot } = input;
23358
+ const files = summarizeHostFiles(snapshot.items, cwd);
22655
23359
  const error51 = snapshot.outcome.status === "failed" ? {
22656
23360
  message: snapshot.outcome.error.message,
22657
23361
  codexErrorInfo: "other",
@@ -22671,15 +23375,12 @@ function projectHistoricalTurn(input) {
22671
23375
  content: userInputContent(snapshot.input)
22672
23376
  },
22673
23377
  ...snapshot.items.flatMap(({ item, outcome }) => {
23378
+ if (itemFileChanges(item) !== null) {
23379
+ return files?.itemId === item.itemId ? [projectItem(files, { status: "succeeded" }, cwd)] : [];
23380
+ }
22674
23381
  if (item.type === "toolExecution") {
22675
23382
  if (isTodoTool(item.toolName) || todoPlanFromTool(item.toolName, item.arguments))
22676
23383
  return [];
22677
- const changes = fileChangeFromTool(item.toolName, item.arguments);
22678
- if (changes) {
22679
- return [
22680
- projectItem({ type: "fileChange", itemId: item.itemId, changes }, outcome, cwd, true, "")
22681
- ];
22682
- }
22683
23384
  if (isFileMutatingTool(item.toolName))
22684
23385
  return [];
22685
23386
  }
@@ -22722,7 +23423,6 @@ var CodexTurnProjector = class {
22722
23423
  #input;
22723
23424
  #interactions = /* @__PURE__ */ new Map();
22724
23425
  #items = /* @__PURE__ */ new Map();
22725
- #itemOrder = [];
22726
23426
  #wireItemOrder = [];
22727
23427
  #startedAt;
22728
23428
  #startedAtMs;
@@ -22730,6 +23430,7 @@ var CodexTurnProjector = class {
22730
23430
  #turnId;
22731
23431
  #completed = false;
22732
23432
  #started = false;
23433
+ #fileItemId = null;
22733
23434
  constructor(input) {
22734
23435
  this.#threadId = input.threadId;
22735
23436
  this.#turnId = input.turnId;
@@ -22751,8 +23452,7 @@ var CodexTurnProjector = class {
22751
23452
  if (projected.item.type === "agentMessage") {
22752
23453
  return [projectItem(projected.item, projected.outcome, this.#cwd)];
22753
23454
  }
22754
- const fileItem = wireFileChangeItem(projected);
22755
- return fileItem ? [projectItem(fileItem, projected.outcome, this.#cwd)] : [];
23455
+ return itemId === this.#fileItemId ? [projectItem(this.#fileSummary(), null, this.#cwd)] : [];
22756
23456
  })
22757
23457
  ],
22758
23458
  error: null,
@@ -22870,11 +23570,9 @@ var CodexTurnProjector = class {
22870
23570
  reasoningPartStarted: false,
22871
23571
  streamedCommandOutput: false,
22872
23572
  wireStarted: false,
22873
- wireFileChanges: null,
22874
23573
  startedAtMs
22875
23574
  };
22876
23575
  this.#items.set(event.item.itemId, projected);
22877
- this.#itemOrder.push(event.item.itemId);
22878
23576
  if ((event.item.type === "agentMessage" || event.item.type === "reasoning") && event.item.text.length === 0) {
22879
23577
  return { messages: [] };
22880
23578
  }
@@ -22885,30 +23583,18 @@ var CodexTurnProjector = class {
22885
23583
  }
22886
23584
  const changes = fileChangeFromTool(event.item.toolName, event.item.arguments);
22887
23585
  if (changes) {
22888
- projected.wireFileChanges = changes;
22889
- const fileItem = {
22890
- type: "fileChange",
22891
- itemId: event.item.itemId,
22892
- changes
22893
- };
22894
- return {
22895
- messages: [
22896
- this.#startWireItem(projected, fileItem, startedAtMs),
22897
- ...this.#fileChangeUpdates(event.item.itemId, changes)
22898
- ]
22899
- };
23586
+ return { messages: this.#fileChangeUpdates(startedAtMs) };
22900
23587
  }
22901
23588
  if (isFileMutatingTool(event.item.toolName))
22902
23589
  return { messages: [] };
22903
23590
  }
23591
+ if (event.item.type === "fileChange")
23592
+ return { messages: this.#fileChangeUpdates(startedAtMs) };
22904
23593
  const startedItem = event.item.type === "reasoning" ? { ...event.item, text: "" } : event.item;
22905
23594
  const messages = [this.#startWireItem(projected, startedItem, startedAtMs)];
22906
23595
  if (event.item.type === "reasoning") {
22907
23596
  messages.push(this.#startReasoningTranscript(event.item, startedAtMs), this.#reasoningOutputDelta(event.item.itemId, event.item.text, startedAtMs), ...this.#reasoningDelta(projected, event.item.text, startedAtMs));
22908
23597
  }
22909
- if (event.item.type === "fileChange") {
22910
- messages.push(...this.#fileChangeUpdates(event.item.itemId, event.item.changes));
22911
- }
22912
23598
  return { messages };
22913
23599
  }
22914
23600
  #updateItem(event, emittedAtMs) {
@@ -22974,7 +23660,7 @@ var CodexTurnProjector = class {
22974
23660
  }
22975
23661
  }
22976
23662
  } else if (event.update.type === "fileChanges.replace") {
22977
- messages.push(...this.#fileChangeUpdates(event.itemId, event.update.changes));
23663
+ messages.push(...this.#fileChangeUpdates(emittedAtMs));
22978
23664
  } else if (event.update.type === "subagents.replace") {
22979
23665
  messages.push({
22980
23666
  method: "item/started",
@@ -23011,6 +23697,9 @@ var CodexTurnProjector = class {
23011
23697
  const durationMs = resolvedItemDurationMs(projected.item, startedAtMs, emittedAtMs);
23012
23698
  projected.item = withResolvedDuration(projected.item, durationMs);
23013
23699
  projected.durationMs = durationMs;
23700
+ if (itemFileChanges(projected.item) !== null) {
23701
+ return { messages: this.#fileChangeUpdates(emittedAtMs) };
23702
+ }
23014
23703
  const completedItem = (item) => ({
23015
23704
  method: "item/completed",
23016
23705
  emittedAtMs,
@@ -23028,28 +23717,11 @@ var CodexTurnProjector = class {
23028
23717
  const plan = planFromTodoValue(projected.item.arguments) ?? planFromTodoValue(projected.item.output);
23029
23718
  return { messages: plan ? [this.#planUpdated(plan, emittedAtMs)] : [] };
23030
23719
  }
23031
- const changes = fileChangeFromTool(projected.item.toolName, projected.item.arguments);
23032
- if (changes) {
23033
- projected.wireFileChanges = changes;
23034
- const fileItem2 = {
23035
- type: "fileChange",
23036
- itemId: projected.item.itemId,
23037
- changes
23038
- };
23039
- return {
23040
- messages: [
23041
- this.#startWireItem(projected, fileItem2, startedAtMs),
23042
- ...this.#fileChangeUpdates(projected.item.itemId, changes),
23043
- completedItem(projectItem(fileItem2, projected.outcome, this.#cwd, true, this.#threadId))
23044
- ]
23045
- };
23046
- }
23047
23720
  }
23048
23721
  return { messages: [] };
23049
23722
  }
23050
- const fileItem = wireFileChangeItem(projected);
23051
23723
  const messages = [
23052
- completedItem(projectItem(fileItem ?? projected.item, projected.outcome, this.#cwd, !projected.streamedCommandOutput, this.#threadId))
23724
+ completedItem(projectItem(projected.item, projected.outcome, this.#cwd, !projected.streamedCommandOutput, this.#threadId))
23053
23725
  ];
23054
23726
  if (projected.item.type === "reasoning") {
23055
23727
  const reasoning = projected.item;
@@ -23108,8 +23780,7 @@ var CodexTurnProjector = class {
23108
23780
  if (projected.item.type === "agentMessage") {
23109
23781
  return [projectItem(projected.item, projected.outcome, this.#cwd)];
23110
23782
  }
23111
- const fileItem = wireFileChangeItem(projected);
23112
- return fileItem ? [projectItem(fileItem, projected.outcome, this.#cwd)] : [];
23783
+ return itemId === this.#fileItemId ? [projectItem(this.#fileSummary(), { status: "succeeded" }, this.#cwd)] : [];
23113
23784
  })
23114
23785
  ],
23115
23786
  error: error51,
@@ -23121,6 +23792,17 @@ var CodexTurnProjector = class {
23121
23792
  return {
23122
23793
  completedTurn: turn,
23123
23794
  messages: [
23795
+ ...this.#fileItemId ? [
23796
+ {
23797
+ method: "item/completed",
23798
+ emittedAtMs: completedAtMs,
23799
+ params: {
23800
+ threadId: this.#threadId,
23801
+ turnId: this.#turnId,
23802
+ item: projectItem(this.#fileSummary(), { status: "succeeded" }, this.#cwd)
23803
+ }
23804
+ }
23805
+ ] : [],
23124
23806
  ...error51 ? [
23125
23807
  {
23126
23808
  method: "error",
@@ -23234,15 +23916,31 @@ var CodexTurnProjector = class {
23234
23916
  }
23235
23917
  };
23236
23918
  }
23237
- #fileChangeUpdates(itemId, changes) {
23238
- const projectedChanges = projectFileChanges(changes);
23919
+ #fileSummary() {
23920
+ const summary = summarizeHostFiles([...this.#items.values()], this.#cwd);
23921
+ if (!summary)
23922
+ throw new Error("File summary requested without a file Item");
23923
+ return this.#fileItemId ? { ...summary, itemId: this.#fileItemId } : summary;
23924
+ }
23925
+ #fileChangeUpdates(emittedAtMs) {
23926
+ const summary = this.#fileSummary();
23927
+ const messages = [];
23928
+ if (!this.#fileItemId) {
23929
+ this.#fileItemId = summary.itemId;
23930
+ const source = this.#items.get(summary.itemId);
23931
+ if (!source)
23932
+ throw new Error("File summary references an unknown Item");
23933
+ messages.push(this.#startWireItem(source, summary, emittedAtMs));
23934
+ }
23935
+ const projectedChanges = projectFileChanges(summary.changes);
23239
23936
  return [
23937
+ ...messages,
23240
23938
  {
23241
23939
  method: "item/fileChange/patchUpdated",
23242
23940
  params: {
23243
23941
  threadId: this.#threadId,
23244
23942
  turnId: this.#turnId,
23245
- itemId,
23943
+ itemId: this.#fileItemId,
23246
23944
  changes: projectedChanges
23247
23945
  }
23248
23946
  },
@@ -23251,21 +23949,11 @@ var CodexTurnProjector = class {
23251
23949
  params: {
23252
23950
  threadId: this.#threadId,
23253
23951
  turnId: this.#turnId,
23254
- diff: diffText(this.#allFileChanges())
23952
+ diff: diffText(summary.changes)
23255
23953
  }
23256
23954
  }
23257
23955
  ];
23258
23956
  }
23259
- #allFileChanges() {
23260
- return this.#itemOrder.flatMap((itemId) => {
23261
- const projected = this.#items.get(itemId);
23262
- if (!projected)
23263
- return [];
23264
- if (projected.item.type === "fileChange")
23265
- return projected.item.changes;
23266
- return projected.wireFileChanges ?? [];
23267
- });
23268
- }
23269
23957
  #activeItem(itemId) {
23270
23958
  const projected = this.#items.get(itemId);
23271
23959
  if (!projected)
@@ -23319,13 +24007,13 @@ function decodeThreadForkRequest(request) {
23319
24007
  if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
23320
24008
  throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
23321
24009
  }
23322
- const path25 = optionalText(params, "path", { allowEmpty: true });
24010
+ const path26 = optionalText(params, "path", { allowEmpty: true });
23323
24011
  const ephemeral = optionalBoolean(params, "ephemeral");
23324
24012
  return {
23325
24013
  threadId: threadId2,
23326
24014
  ...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
23327
24015
  ...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
23328
- ...path25 ? { path: path25 } : {},
24016
+ ...path26 ? { path: path26 } : {},
23329
24017
  ...optionalField(params, "model"),
23330
24018
  ...optionalField(params, "modelProvider"),
23331
24019
  ...optionalField(params, "cwd"),
@@ -24484,7 +25172,7 @@ var HarnessAccountInspectionCache = class {
24484
25172
  // packages/host-runtime/src/app-server-host.ts
24485
25173
  import { createHash as createHash6, randomUUID as randomUUID8 } from "node:crypto";
24486
25174
  import os2 from "node:os";
24487
- import path11 from "node:path";
25175
+ import path12 from "node:path";
24488
25176
 
24489
25177
  // packages/host-runtime/src/external-thread-fork.ts
24490
25178
  import nodePath from "node:path";
@@ -24492,7 +25180,7 @@ import nodePath from "node:path";
24492
25180
  // packages/host-runtime/src/external-thread-repository.ts
24493
25181
  import { randomUUID as randomUUID4 } from "node:crypto";
24494
25182
  import os from "node:os";
24495
- import path6 from "node:path";
25183
+ import path7 from "node:path";
24496
25184
 
24497
25185
  // packages/host-runtime/src/external-subagent-threads.ts
24498
25186
  import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
@@ -24632,8 +25320,8 @@ function sameMapping(left, right) {
24632
25320
  }
24633
25321
  function defaultMappingStoreDirectory(environment) {
24634
25322
  const dataDirectory = environment.CODEXHOST_DATA_DIR;
24635
- return path6.join(
24636
- dataDirectory ? path6.resolve(dataDirectory) : path6.join(os.homedir(), ".codexhost"),
25323
+ return path7.join(
25324
+ dataDirectory ? path7.resolve(dataDirectory) : path7.join(os.homedir(), ".codexhost"),
24637
25325
  "mapping-store"
24638
25326
  );
24639
25327
  }
@@ -25866,16 +26554,236 @@ var SessionStateObserver = class {
25866
26554
  }
25867
26555
  };
25868
26556
 
25869
- // packages/host-runtime/src/external-thread-runtime.ts
25870
- function nativeTurnKey3(turn) {
25871
- const ref = turn.nativeTurnRef;
25872
- return `${ref.harnessId}\0${ref.nativeSessionId}\0${ref.nativeTurnKey}\0${ref.formatVersion}`;
25873
- }
25874
- function mergeReadonlySnapshot(previous, next) {
25875
- const nextByTurn = new Map(next.turns.map((turn) => [nativeTurnKey3(turn), turn]));
25876
- const retainedKeys = /* @__PURE__ */ new Set();
25877
- const turns = previous.turns.map((turn) => {
25878
- const key = nativeTurnKey3(turn);
26557
+ // packages/host-runtime/src/desktop-request-queue.ts
26558
+ var DesktopRequestQueue = class {
26559
+ #threads = /* @__PURE__ */ new Map();
26560
+ #pending = /* @__PURE__ */ new Set();
26561
+ run(threadId2, operation) {
26562
+ const previous = threadId2 === void 0 ? void 0 : this.#threads.get(threadId2);
26563
+ const task = (previous ?? Promise.resolve()).then(operation);
26564
+ const settled = task.then(
26565
+ () => void 0,
26566
+ () => void 0
26567
+ );
26568
+ this.#pending.add(settled);
26569
+ if (threadId2 !== void 0) this.#threads.set(threadId2, settled);
26570
+ void settled.then(() => {
26571
+ this.#pending.delete(settled);
26572
+ if (threadId2 !== void 0 && this.#threads.get(threadId2) === settled) {
26573
+ this.#threads.delete(threadId2);
26574
+ }
26575
+ });
26576
+ return task;
26577
+ }
26578
+ /** Call after admission stops, before taking the Session snapshot for shutdown. */
26579
+ async drain() {
26580
+ await Promise.all(this.#pending);
26581
+ }
26582
+ };
26583
+
26584
+ // packages/host-runtime/src/external-thread-idle-release.ts
26585
+ var CHECK_INTERVAL_MS = 6e4;
26586
+ var CLOSE_TIMEOUT_MS = 6e4;
26587
+ var CLOSE_FAILURE = "External Session resource release failed. Further use is blocked to avoid duplicate writers. Restart Codex Desktop to retry recovery; residual processes may require manual cleanup.";
26588
+ var ExternalThreadIdleRelease = class {
26589
+ constructor(options2) {
26590
+ this.options = options2;
26591
+ }
26592
+ options;
26593
+ #activity = /* @__PURE__ */ new WeakMap();
26594
+ #operations = /* @__PURE__ */ new Map();
26595
+ #closing = /* @__PURE__ */ new Map();
26596
+ #pending = /* @__PURE__ */ new Set();
26597
+ #scheduled = /* @__PURE__ */ new Set();
26598
+ #settings = { ...DEFAULT_IDLE_RELEASE_SETTINGS };
26599
+ #timer;
26600
+ #stopped = false;
26601
+ configure(value2) {
26602
+ const settings = idleReleaseSettingsSchema.parse(value2);
26603
+ if (this.#stopped) throw new Error("Host is shutting down");
26604
+ this.#settings = settings;
26605
+ if (settings.enabled && !this.#timer) {
26606
+ this.#timer = setInterval(() => this.check(), CHECK_INTERVAL_MS);
26607
+ this.#timer.unref();
26608
+ } else if (!settings.enabled && this.#timer) {
26609
+ clearInterval(this.#timer);
26610
+ this.#timer = void 0;
26611
+ }
26612
+ return { ...settings };
26613
+ }
26614
+ touch(thread) {
26615
+ const state = this.#activity.get(thread);
26616
+ if (state) state.lastActivity = Date.now();
26617
+ else
26618
+ this.#activity.set(thread, {
26619
+ lastActivity: Date.now(),
26620
+ outputFailed: false,
26621
+ closeFailed: false
26622
+ });
26623
+ }
26624
+ outputFailed(thread) {
26625
+ this.touch(thread);
26626
+ const state = this.#activity.get(thread);
26627
+ if (state) state.outputFailed = true;
26628
+ }
26629
+ failure(thread) {
26630
+ return this.#activity.get(thread)?.closeFailed ? CLOSE_FAILURE : void 0;
26631
+ }
26632
+ async waitForClose(id2) {
26633
+ await this.#closing.get(id2);
26634
+ }
26635
+ /** Acquire before resolving a Session, not after an await has exposed its reference. */
26636
+ async runOperation(id2, operation) {
26637
+ if (this.#stopped) throw new Error("Host is shutting down");
26638
+ if (id2) {
26639
+ while (this.#closing.has(id2)) await this.#closing.get(id2);
26640
+ }
26641
+ if (this.#stopped) throw new Error("Host is shutting down");
26642
+ return this.#track(id2, operation);
26643
+ }
26644
+ /** Closing may emit outputs: consume them without waiting on the close being drained. */
26645
+ consumeOutput(thread, operation) {
26646
+ this.touch(thread);
26647
+ return this.#track(thread.id, operation, false);
26648
+ }
26649
+ #track(id2, operation, drain = true) {
26650
+ if (id2) this.#operations.set(id2, (this.#operations.get(id2) ?? 0) + 1);
26651
+ const task = Promise.resolve().then(operation).finally(() => {
26652
+ if (id2) {
26653
+ const remaining = (this.#operations.get(id2) ?? 1) - 1;
26654
+ if (remaining) this.#operations.set(id2, remaining);
26655
+ else {
26656
+ this.#operations.delete(id2);
26657
+ const thread = this.options.get(id2);
26658
+ if (thread) this.touch(thread);
26659
+ }
26660
+ }
26661
+ this.#pending.delete(task);
26662
+ });
26663
+ if (drain) this.#pending.add(task);
26664
+ return task;
26665
+ }
26666
+ /** Read only: never resolve a Session or touch its activity clock. */
26667
+ list() {
26668
+ const now = Date.now();
26669
+ return this.options.threads().map((thread) => {
26670
+ const activity = this.#activity.get(thread);
26671
+ const inactiveMs = Math.max(0, now - (activity?.lastActivity ?? now));
26672
+ let state = "idle";
26673
+ let reason = "none";
26674
+ if (activity?.closeFailed) {
26675
+ state = "failed";
26676
+ reason = "closeFailed";
26677
+ } else if (this.#closing.has(thread.id)) {
26678
+ state = "closing";
26679
+ } else if (thread.running || thread.activeTurnId) {
26680
+ state = "running";
26681
+ reason = "operation";
26682
+ } else if (thread.persistenceError || activity?.outputFailed) {
26683
+ state = "blocked";
26684
+ reason = "persistence";
26685
+ } else if (thread.record.subagent || thread.record.state !== "ready" || !thread.record.nativeSessionRef) {
26686
+ state = "blocked";
26687
+ reason = "identity";
26688
+ } else if (this.#operations.has(thread.id)) {
26689
+ state = "busy";
26690
+ reason = "operation";
26691
+ } else if (!this.options.canRelease(thread)) {
26692
+ state = "busy";
26693
+ reason = "background";
26694
+ } else if (!this.#settings.enabled) {
26695
+ reason = "disabled";
26696
+ } else if (inactiveMs < this.#settings.timeoutMinutes * 6e4) {
26697
+ reason = "timeout";
26698
+ }
26699
+ return {
26700
+ threadId: thread.id,
26701
+ title: thread.record.title ?? thread.id,
26702
+ harnessId: thread.harnessId,
26703
+ state,
26704
+ reason,
26705
+ inactiveMs
26706
+ };
26707
+ });
26708
+ }
26709
+ #eligible(thread) {
26710
+ const state = this.#activity.get(thread);
26711
+ return !this.#stopped && this.#settings.enabled && !!state && !state.outputFailed && !state.closeFailed && this.options.get(thread.id) === thread && !this.#closing.has(thread.id) && !this.#operations.has(thread.id) && !thread.record.subagent && thread.record.state === "ready" && !!thread.record.nativeSessionRef && !thread.persistenceError && !thread.running && !thread.activeTurnId && this.options.canRelease(thread) && Date.now() - state.lastActivity >= this.#settings.timeoutMinutes * 6e4;
26712
+ }
26713
+ check() {
26714
+ for (const thread of this.options.threads()) {
26715
+ if (this.#scheduled.has(thread.id) || !this.#eligible(thread)) continue;
26716
+ this.#scheduled.add(thread.id);
26717
+ const task = this.options.queue.run(thread.id, async () => {
26718
+ if (!this.#eligible(thread)) return;
26719
+ const closing = this.#close(thread);
26720
+ this.#closing.set(thread.id, closing);
26721
+ try {
26722
+ await closing;
26723
+ } finally {
26724
+ this.#closing.delete(thread.id);
26725
+ }
26726
+ }).catch(this.options.diagnose).finally(() => this.#scheduled.delete(thread.id));
26727
+ this.#pending.add(task);
26728
+ void task.finally(() => this.#pending.delete(task));
26729
+ }
26730
+ }
26731
+ async #close(thread) {
26732
+ const state = this.#activity.get(thread);
26733
+ if (!state) return;
26734
+ let timeout;
26735
+ const closed = Promise.resolve().then(async () => {
26736
+ await thread.session.close();
26737
+ await thread.outputTask;
26738
+ await this.options.onClosed?.(thread);
26739
+ });
26740
+ try {
26741
+ await Promise.race([
26742
+ closed,
26743
+ new Promise((_, reject) => {
26744
+ timeout = setTimeout(
26745
+ () => reject(new Error("Session release timed out")),
26746
+ CLOSE_TIMEOUT_MS
26747
+ );
26748
+ timeout.unref();
26749
+ })
26750
+ ]);
26751
+ if (state.outputFailed || thread.persistenceError || thread.record.state !== "ready" || !thread.record.nativeSessionRef) {
26752
+ throw new Error("Session release could not confirm persisted history and identity");
26753
+ }
26754
+ if (this.options.get(thread.id) !== thread) throw new Error("Session changed during release");
26755
+ this.options.remove(thread.id);
26756
+ } catch (error51) {
26757
+ state.closeFailed = true;
26758
+ this.options.diagnose(error51);
26759
+ } finally {
26760
+ if (timeout) clearTimeout(timeout);
26761
+ }
26762
+ }
26763
+ disable() {
26764
+ this.#settings = { ...this.#settings, enabled: false };
26765
+ if (this.#timer) clearInterval(this.#timer);
26766
+ this.#timer = void 0;
26767
+ }
26768
+ stop() {
26769
+ this.#stopped = true;
26770
+ this.disable();
26771
+ }
26772
+ async drain() {
26773
+ while (this.#pending.size) await Promise.allSettled([...this.#pending]);
26774
+ }
26775
+ };
26776
+
26777
+ // packages/host-runtime/src/external-thread-runtime.ts
26778
+ function nativeTurnKey3(turn) {
26779
+ const ref = turn.nativeTurnRef;
26780
+ return `${ref.harnessId}\0${ref.nativeSessionId}\0${ref.nativeTurnKey}\0${ref.formatVersion}`;
26781
+ }
26782
+ function mergeReadonlySnapshot(previous, next) {
26783
+ const nextByTurn = new Map(next.turns.map((turn) => [nativeTurnKey3(turn), turn]));
26784
+ const retainedKeys = /* @__PURE__ */ new Set();
26785
+ const turns = previous.turns.map((turn) => {
26786
+ const key = nativeTurnKey3(turn);
25879
26787
  retainedKeys.add(key);
25880
26788
  const update = nextByTurn.get(key);
25881
26789
  if (!update) return turn;
@@ -25955,12 +26863,14 @@ function errorMessage2(error51) {
25955
26863
  return error51 instanceof Error ? error51.message : String(error51);
25956
26864
  }
25957
26865
  var ExternalThreadRuntime = class {
26866
+ idleRelease;
25958
26867
  #adapters;
25959
26868
  #consumeOutputs;
25960
26869
  #diagnose;
25961
26870
  #environment;
25962
26871
  #repository;
25963
26872
  #restores = /* @__PURE__ */ new Map();
26873
+ #subagentRunning;
25964
26874
  #threads = /* @__PURE__ */ new Map();
25965
26875
  constructor(input) {
25966
26876
  this.#adapters = input.adapters;
@@ -25968,6 +26878,16 @@ var ExternalThreadRuntime = class {
25968
26878
  this.#repository = input.repository;
25969
26879
  this.#consumeOutputs = input.consumeOutputs;
25970
26880
  this.#diagnose = input.diagnose;
26881
+ this.#subagentRunning = input.subagentRunning ?? (() => false);
26882
+ this.idleRelease = new ExternalThreadIdleRelease({
26883
+ threads: () => this.values(),
26884
+ get: (id2) => this.get(id2),
26885
+ remove: (id2) => this.remove(id2),
26886
+ queue: input.idleRelease?.queue ?? new DesktopRequestQueue(),
26887
+ canRelease: input.idleRelease?.canRelease ?? (() => false),
26888
+ ...input.idleRelease?.onClosed ? { onClosed: input.idleRelease.onClosed } : {},
26889
+ diagnose: input.diagnose
26890
+ });
25971
26891
  }
25972
26892
  get(threadId2) {
25973
26893
  return this.#threads.get(threadId2);
@@ -25997,6 +26917,7 @@ var ExternalThreadRuntime = class {
25997
26917
  ...effectiveThinkingOptionId ? { effectiveThinkingOptionId } : {},
25998
26918
  ...effectivePermissionModeId ? { effectivePermissionModeId } : {}
25999
26919
  };
26920
+ const running = this.#subagentRunning(input.record.hostThreadId);
26000
26921
  const externalThread = {
26001
26922
  id: input.record.hostThreadId,
26002
26923
  cwd: input.record.cwd,
@@ -26009,11 +26930,11 @@ var ExternalThreadRuntime = class {
26009
26930
  record: input.record,
26010
26931
  sessionId: input.sessionId,
26011
26932
  stateObserver: new SessionStateObserver(observerState),
26012
- thread: input.thread,
26933
+ thread: running ? { ...input.thread, status: { type: "active", activeFlags: [] } } : input.thread,
26013
26934
  transportModelId: input.transportModelId ?? input.record.transportModelId,
26014
26935
  turns: input.turns,
26015
26936
  historyHydrated: true,
26016
- running: false,
26937
+ running,
26017
26938
  activeTurnId: null,
26018
26939
  latestUsage: input.session.initialUsage,
26019
26940
  usageTurnId: null,
@@ -26023,6 +26944,7 @@ var ExternalThreadRuntime = class {
26023
26944
  persistenceError: null,
26024
26945
  ignoredInteractionIds: /* @__PURE__ */ new Set()
26025
26946
  };
26947
+ this.idleRelease.touch(externalThread);
26026
26948
  externalThread.outputTask = this.#consumeOutputs(externalThread);
26027
26949
  this.#threads.set(externalThread.id, externalThread);
26028
26950
  return externalThread;
@@ -26075,8 +26997,13 @@ var ExternalThreadRuntime = class {
26075
26997
  }
26076
26998
  }
26077
26999
  async locate(threadId2) {
27000
+ await this.idleRelease.waitForClose(threadId2);
26078
27001
  const loaded = this.#threads.get(threadId2);
26079
- if (loaded) return { kind: "external", record: loaded.record, thread: loaded };
27002
+ if (loaded) {
27003
+ const failure = this.idleRelease.failure(loaded);
27004
+ if (failure) return { kind: "error", error: { code: -32075, message: failure } };
27005
+ return { kind: "external", record: loaded.record, thread: loaded };
27006
+ }
26080
27007
  let record3;
26081
27008
  try {
26082
27009
  record3 = await this.#repository.find(threadId2);
@@ -26099,13 +27026,17 @@ var ExternalThreadRuntime = class {
26099
27026
  const location = await this.locate(threadId2);
26100
27027
  if (location.kind !== "external") return location;
26101
27028
  if (location.thread) {
27029
+ this.idleRelease.touch(location.thread);
26102
27030
  return { kind: "external", thread: location.thread, historyFresh: false };
26103
27031
  }
26104
27032
  const { record: record3 } = location;
26105
27033
  let restoring = this.#restores.get(threadId2);
26106
27034
  if (!restoring) {
26107
27035
  const restored = this.#threads.get(threadId2);
26108
- if (restored) return { kind: "external", thread: restored, historyFresh: false };
27036
+ if (restored) {
27037
+ this.idleRelease.touch(restored);
27038
+ return { kind: "external", thread: restored, historyFresh: false };
27039
+ }
26109
27040
  restoring = this.#restore(record3).finally(() => {
26110
27041
  this.#restores.delete(threadId2);
26111
27042
  });
@@ -26465,7 +27396,7 @@ var ExternalTurnSteering = class {
26465
27396
 
26466
27397
  // packages/host-runtime/src/harness-delegation-coordinator.ts
26467
27398
  import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
26468
- import path7 from "node:path";
27399
+ import path8 from "node:path";
26469
27400
 
26470
27401
  // packages/host-runtime/src/delegation-snapshot.ts
26471
27402
  import { createHash as createHash4 } from "node:crypto";
@@ -26636,7 +27567,7 @@ function taskDigest(input) {
26636
27567
  return createHash5("sha256").update(
26637
27568
  JSON.stringify({
26638
27569
  task: input.task,
26639
- cwd: path7.resolve(input.cwd),
27570
+ cwd: path8.resolve(input.cwd),
26640
27571
  modelId: input.model?.id ?? null,
26641
27572
  thinkingOptionId: input.thinkingOptionId ?? null
26642
27573
  })
@@ -26707,7 +27638,7 @@ var HarnessDelegationCoordinator = class {
26707
27638
  return {
26708
27639
  harnessId: input.harnessId,
26709
27640
  inspection: await adapter.inspect({
26710
- ...input.cwd ? { cwd: path7.resolve(input.cwd) } : {},
27641
+ ...input.cwd ? { cwd: path8.resolve(input.cwd) } : {},
26711
27642
  ...input.refresh !== void 0 ? { refresh: input.refresh } : {}
26712
27643
  })
26713
27644
  };
@@ -26721,7 +27652,7 @@ var HarnessDelegationCoordinator = class {
26721
27652
  const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
26722
27653
  return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
26723
27654
  }
26724
- const startInput = { ...input, parentThreadId, cwd: path7.resolve(selectedCwd) };
27655
+ const startInput = { ...input, parentThreadId, cwd: path8.resolve(selectedCwd) };
26725
27656
  if (!this.#adapters.has(input.harnessId)) {
26726
27657
  throw new DelegationControlError(
26727
27658
  "HARNESS_NOT_FOUND",
@@ -26782,94 +27713,101 @@ var HarnessDelegationCoordinator = class {
26782
27713
  );
26783
27714
  let delegation = null;
26784
27715
  let session = null;
26785
- try {
26786
- delegation = await this.#repository.createDelegation({
26787
- delegationId,
26788
- parentHostThreadId: hostThreadIdSchema.parse(parentThreadId),
26789
- childHostThreadId: childThreadId,
26790
- sourceHarnessId: harnessIdSchema.parse(parent.harnessId),
26791
- targetHarnessId: harnessIdSchema.parse(targetHarnessId),
26792
- status: "creating",
26793
- ...input.requestId ? { requestId: input.requestId } : {},
26794
- taskDigest: digest2
26795
- });
26796
- const opened = await adapter.open({
26797
- kind: "create",
26798
- cwd: record3.cwd,
26799
- environment: { ...this.#environment, [DELEGATION_THREAD_ID_ENV]: childThreadId },
26800
- executionPolicy: "unattended-full-access",
26801
- ...input.model ? { model: input.model } : {},
26802
- ...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
26803
- });
26804
- if (!opened.ok) throw new DelegationControlError("DELEGATION_FAILED", opened.error.message);
26805
- session = opened.value;
26806
- if (session.initialState.nativeRef) {
26807
- record3 = await this.#repository.commitNative(
26808
- record3.hostThreadId,
26809
- session.initialState.nativeRef
26810
- );
26811
- }
26812
- const threadValue = externalThreadValue({
26813
- record: record3,
26814
- turns: [],
26815
- sessionId: record3.hostThreadId,
26816
- running: true
26817
- });
26818
- const thread = this.#registerExternalThread({
26819
- record: record3,
26820
- session,
26821
- sessionId: record3.hostThreadId,
26822
- thread: threadValue,
26823
- turns: [],
26824
- ...input.model ? { requestedModel: input.model } : {},
26825
- ...input.thinkingOptionId ? { requestedThinkingOptionId: input.thinkingOptionId } : {},
26826
- ...session.initialState.nativeRef ? {} : { restoredState: session.initialState }
26827
- });
26828
- const beforeRevision = thread.stateObserver.revision;
26829
- await this.#startExternalTurn(thread, input.task, turnId);
26830
- if (!thread.record.nativeSessionRef) {
26831
- const deadline = Date.now() + NATIVE_REF_TIMEOUT_MS;
26832
- let revision = beforeRevision;
26833
- while (!thread.record.nativeSessionRef) {
26834
- const remaining = deadline - Date.now();
26835
- if (remaining <= 0) {
26836
- throw new Error("Target Harness Native Session identity was not persisted");
27716
+ return this.#externalRuntime.idleRelease.runOperation(childThreadId, async () => {
27717
+ try {
27718
+ delegation = await this.#repository.createDelegation({
27719
+ delegationId,
27720
+ parentHostThreadId: hostThreadIdSchema.parse(parentThreadId),
27721
+ childHostThreadId: childThreadId,
27722
+ sourceHarnessId: harnessIdSchema.parse(parent.harnessId),
27723
+ targetHarnessId: harnessIdSchema.parse(targetHarnessId),
27724
+ status: "creating",
27725
+ ...input.requestId ? { requestId: input.requestId } : {},
27726
+ taskDigest: digest2
27727
+ });
27728
+ const opened = await adapter.open({
27729
+ kind: "create",
27730
+ cwd: record3.cwd,
27731
+ environment: { ...this.#environment, [DELEGATION_THREAD_ID_ENV]: childThreadId },
27732
+ executionPolicy: "unattended-full-access",
27733
+ ...input.model ? { model: input.model } : {},
27734
+ ...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
27735
+ });
27736
+ if (!opened.ok) throw new DelegationControlError("DELEGATION_FAILED", opened.error.message);
27737
+ session = opened.value;
27738
+ if (session.initialState.nativeRef) {
27739
+ record3 = await this.#repository.commitNative(
27740
+ record3.hostThreadId,
27741
+ session.initialState.nativeRef
27742
+ );
27743
+ }
27744
+ const threadValue = externalThreadValue({
27745
+ record: record3,
27746
+ turns: [],
27747
+ sessionId: record3.hostThreadId,
27748
+ running: true
27749
+ });
27750
+ const thread = this.#registerExternalThread({
27751
+ record: record3,
27752
+ session,
27753
+ sessionId: record3.hostThreadId,
27754
+ thread: threadValue,
27755
+ turns: [],
27756
+ ...input.model ? { requestedModel: input.model } : {},
27757
+ ...input.thinkingOptionId ? { requestedThinkingOptionId: input.thinkingOptionId } : {},
27758
+ ...session.initialState.nativeRef ? {} : { restoredState: session.initialState }
27759
+ });
27760
+ const beforeRevision = thread.stateObserver.revision;
27761
+ await this.#startExternalTurn(thread, input.task, turnId);
27762
+ if (!thread.record.nativeSessionRef) {
27763
+ const deadline = Date.now() + NATIVE_REF_TIMEOUT_MS;
27764
+ let revision = beforeRevision;
27765
+ while (!thread.record.nativeSessionRef) {
27766
+ const remaining = deadline - Date.now();
27767
+ if (remaining <= 0) {
27768
+ throw new Error("Target Harness Native Session identity was not persisted");
27769
+ }
27770
+ await thread.stateObserver.waitForChange(revision, remaining);
27771
+ revision = thread.stateObserver.revision;
26837
27772
  }
26838
- await thread.stateObserver.waitForChange(revision, remaining);
26839
- revision = thread.stateObserver.revision;
26840
27773
  }
27774
+ await this.#repository.setDelegationStatus(delegationId, "running");
27775
+ await this.#notifyThreadStarted(thread.thread);
27776
+ return {
27777
+ ...this.#result(delegationId, childThreadId, turnId, targetHarnessId, "running", {
27778
+ requested: {
27779
+ ...input.model ? { model: input.model } : {},
27780
+ ...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
27781
+ },
27782
+ effective: {
27783
+ ...thread.stateObserver.state.effectiveModel ? { effectiveModel: thread.stateObserver.state.effectiveModel } : {},
27784
+ ...thread.stateObserver.state.resolvedModelLabel ? { resolvedModelLabel: thread.stateObserver.state.resolvedModelLabel } : {},
27785
+ ...thread.stateObserver.state.effectiveThinkingOptionId ? {
27786
+ effectiveThinkingOptionId: thread.stateObserver.state.effectiveThinkingOptionId
27787
+ } : {}
27788
+ }
27789
+ }),
27790
+ cwd: record3.cwd,
27791
+ parentThreadId
27792
+ };
27793
+ } catch (error51) {
27794
+ if (session) await session.close().catch(() => void 0);
27795
+ this.#externalRuntime.remove(childThreadId);
27796
+ if (delegation)
27797
+ await this.#repository.removeDelegation(delegation.delegationId).catch(() => void 0);
27798
+ await this.#repository.removeThread(childThreadId).catch(() => void 0);
27799
+ if (error51 instanceof DelegationControlError) throw error51;
27800
+ throw new DelegationControlError(
27801
+ "DELEGATION_FAILED",
27802
+ error51 instanceof Error ? error51.message : String(error51)
27803
+ );
26841
27804
  }
26842
- await this.#repository.setDelegationStatus(delegationId, "running");
26843
- await this.#notifyThreadStarted(thread.thread);
26844
- return {
26845
- ...this.#result(delegationId, childThreadId, turnId, targetHarnessId, "running", {
26846
- requested: {
26847
- ...input.model ? { model: input.model } : {},
26848
- ...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
26849
- },
26850
- effective: {
26851
- ...thread.stateObserver.state.effectiveModel ? { effectiveModel: thread.stateObserver.state.effectiveModel } : {},
26852
- ...thread.stateObserver.state.resolvedModelLabel ? { resolvedModelLabel: thread.stateObserver.state.resolvedModelLabel } : {},
26853
- ...thread.stateObserver.state.effectiveThinkingOptionId ? { effectiveThinkingOptionId: thread.stateObserver.state.effectiveThinkingOptionId } : {}
26854
- }
26855
- }),
26856
- cwd: record3.cwd,
26857
- parentThreadId
26858
- };
26859
- } catch (error51) {
26860
- if (session) await session.close().catch(() => void 0);
26861
- this.#externalRuntime.remove(childThreadId);
26862
- if (delegation)
26863
- await this.#repository.removeDelegation(delegation.delegationId).catch(() => void 0);
26864
- await this.#repository.removeThread(childThreadId).catch(() => void 0);
26865
- if (error51 instanceof DelegationControlError) throw error51;
26866
- throw new DelegationControlError(
26867
- "DELEGATION_FAILED",
26868
- error51 instanceof Error ? error51.message : String(error51)
26869
- );
26870
- }
27805
+ });
26871
27806
  }
26872
27807
  async send(input) {
27808
+ return this.#externalRuntime.idleRelease.runOperation(input.threadId, () => this.#send(input));
27809
+ }
27810
+ async #send(input) {
26873
27811
  if (!input.message?.trim()) {
26874
27812
  throw new DelegationControlError("INVALID_ARGUMENT", "Message must not be empty");
26875
27813
  }
@@ -26901,6 +27839,12 @@ var HarnessDelegationCoordinator = class {
26901
27839
  return this.#turnResult(thread.id, turnId, thread.harnessId);
26902
27840
  }
26903
27841
  async cancel(input) {
27842
+ return this.#externalRuntime.idleRelease.runOperation(
27843
+ input.threadId,
27844
+ () => this.#cancel(input)
27845
+ );
27846
+ }
27847
+ async #cancel(input) {
26904
27848
  const location = await this.#externalRuntime.locate(input.threadId);
26905
27849
  if (location.kind === "official") return this.#cancelOfficial(input);
26906
27850
  if (location.kind === "error") {
@@ -26925,6 +27869,9 @@ var HarnessDelegationCoordinator = class {
26925
27869
  return { threadId: thread.id, turnId, harnessId: thread.harnessId, cancelled: true };
26926
27870
  }
26927
27871
  async read(input) {
27872
+ return this.#externalRuntime.idleRelease.runOperation(input.threadId, () => this.#read(input));
27873
+ }
27874
+ async #read(input) {
26928
27875
  validateReadOptions(input);
26929
27876
  const location = await this.#externalRuntime.locate(input.threadId);
26930
27877
  if (location.kind === "official") return this.#readOfficial(input);
@@ -27134,7 +28081,7 @@ var HarnessDelegationCoordinator = class {
27134
28081
 
27135
28082
  // packages/host-runtime/src/harness-plugin-loader.ts
27136
28083
  import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
27137
- import path9 from "node:path";
28084
+ import path10 from "node:path";
27138
28085
  import { pathToFileURL } from "node:url";
27139
28086
 
27140
28087
  // packages/host-runtime/src/harness-plugin-registry.ts
@@ -27172,16 +28119,16 @@ var HarnessPluginRegistry = class {
27172
28119
 
27173
28120
  // packages/host-runtime/src/plugin-files.ts
27174
28121
  import { open as open4, realpath, stat as stat2 } from "node:fs/promises";
27175
- import path8 from "node:path";
28122
+ import path9 from "node:path";
27176
28123
  function inside(root, candidate) {
27177
- const relative = path8.relative(root, candidate);
27178
- return relative !== "" && !path8.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path8.sep}`);
28124
+ const relative = path9.relative(root, candidate);
28125
+ return relative !== "" && !path9.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path9.sep}`);
27179
28126
  }
27180
28127
  async function pluginResourcePath(root, relative) {
27181
- if (path8.isAbsolute(relative) || !inside(root, path8.resolve(root, relative))) {
28128
+ if (path9.isAbsolute(relative) || !inside(root, path9.resolve(root, relative))) {
27182
28129
  throw new Error("Plugin resource escapes its root");
27183
28130
  }
27184
- const resolved = await realpath(path8.resolve(root, relative));
28131
+ const resolved = await realpath(path9.resolve(root, relative));
27185
28132
  if (!inside(root, resolved) || !(await stat2(resolved)).isFile()) {
27186
28133
  throw new Error("Plugin resource must be a regular file inside its root");
27187
28134
  }
@@ -27263,10 +28210,11 @@ function unavailableAdapter(descriptor, code) {
27263
28210
  close: async () => void 0
27264
28211
  };
27265
28212
  }
27266
- async function loadAdapter(candidate, context, timeoutMs, diagnose, warmup) {
28213
+ async function loadAdapter(candidate, context, timeoutMs, diagnose, warmup, signal) {
27267
28214
  const { manifest } = candidate;
27268
28215
  let expired = false;
27269
28216
  let timer;
28217
+ let onAbort;
27270
28218
  const operation = (async () => {
27271
28219
  const entry = await pluginResourcePath(candidate.root, manifest.entry);
27272
28220
  if (!/\.(?:mjs|js)$/u.test(entry))
@@ -27292,7 +28240,7 @@ async function loadAdapter(candidate, context, timeoutMs, diagnose, warmup) {
27292
28240
  return value2;
27293
28241
  })();
27294
28242
  try {
27295
- const adapter = await Promise.race([
28243
+ const races = [
27296
28244
  operation,
27297
28245
  new Promise((_, reject) => {
27298
28246
  timer = setTimeout(() => {
@@ -27300,15 +28248,31 @@ async function loadAdapter(candidate, context, timeoutMs, diagnose, warmup) {
27300
28248
  reject(new PluginLoadTimeout());
27301
28249
  }, timeoutMs);
27302
28250
  })
27303
- ]);
28251
+ ];
28252
+ if (signal) {
28253
+ races.push(
28254
+ new Promise((_, reject) => {
28255
+ onAbort = () => {
28256
+ expired = true;
28257
+ reject(new PluginLoadCancelled());
28258
+ };
28259
+ if (signal.aborted) onAbort();
28260
+ else signal.addEventListener("abort", onAbort, { once: true });
28261
+ })
28262
+ );
28263
+ }
28264
+ const adapter = await Promise.race(races);
27304
28265
  if (!adapter) throw new PluginLoadTimeout();
27305
28266
  return adapter;
27306
28267
  } finally {
27307
28268
  if (timer) clearTimeout(timer);
28269
+ if (signal && onAbort) signal.removeEventListener("abort", onAbort);
27308
28270
  }
27309
28271
  }
27310
28272
  var PluginLoadTimeout = class extends Error {
27311
28273
  };
28274
+ var PluginLoadCancelled = class extends Error {
28275
+ };
27312
28276
  async function loadHarnessPlugins(options2) {
27313
28277
  const timeoutMs = options2.loadTimeoutMs ?? 1e4;
27314
28278
  if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 6e4) {
@@ -27326,7 +28290,7 @@ async function loadHarnessPlugins(options2) {
27326
28290
  const enabledIds = /* @__PURE__ */ new Set();
27327
28291
  const roots = /* @__PURE__ */ new Set();
27328
28292
  for (const configuredRoot of options2.roots) {
27329
- if (!path9.isAbsolute(configuredRoot)) {
28293
+ if (!path10.isAbsolute(configuredRoot)) {
27330
28294
  diagnose({ code: "invalidRoot" });
27331
28295
  continue;
27332
28296
  }
@@ -27356,7 +28320,7 @@ async function loadHarnessPlugins(options2) {
27356
28320
  for (const directory of directories) {
27357
28321
  try {
27358
28322
  const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
27359
- const pluginRoot = await realpath2(path9.join(root, directory.name));
28323
+ const pluginRoot = await realpath2(path10.join(root, directory.name));
27360
28324
  await pluginResourcePath(pluginRoot, "manifest.json");
27361
28325
  const manifest = harnessPluginManifestSchema.parse(
27362
28326
  JSON.parse(
@@ -27394,13 +28358,15 @@ async function loadHarnessPlugins(options2) {
27394
28358
  }
27395
28359
  pending.push(candidate);
27396
28360
  }
27397
- const deadline = Date.now() + timeoutMs;
28361
+ if (options2.signal?.aborted) return registry2;
27398
28362
  let next = 0;
27399
28363
  const loaded = /* @__PURE__ */ new Map();
27400
28364
  const worker = async () => {
27401
28365
  for (; ; ) {
28366
+ if (options2.signal?.aborted) return;
27402
28367
  const candidate = pending[next++];
27403
28368
  if (!candidate) return;
28369
+ if (options2.signal?.aborted) return;
27404
28370
  const { manifest } = candidate;
27405
28371
  const descriptor = harnessPluginDescriptorSchema.parse({
27406
28372
  id: manifest.id,
@@ -27416,16 +28382,20 @@ async function loadHarnessPlugins(options2) {
27416
28382
  } else {
27417
28383
  try {
27418
28384
  if (manifest.icon) descriptor.icon = await readPluginIcon(candidate.root, manifest.icon);
27419
- const remaining = deadline - Date.now();
27420
- if (remaining <= 0) throw new PluginLoadTimeout();
27421
28385
  adapter = await loadAdapter(
27422
28386
  candidate,
27423
28387
  options2.context,
27424
- remaining,
28388
+ timeoutMs,
27425
28389
  diagnose,
27426
- options2.warmup !== false
28390
+ options2.warmup !== false,
28391
+ options2.signal
27427
28392
  );
28393
+ if (options2.signal?.aborted) {
28394
+ await adapter.close().catch(() => diagnose({ id: manifest.id, code: "cleanupFailed" }));
28395
+ return;
28396
+ }
27428
28397
  } catch (error51) {
28398
+ if (error51 instanceof PluginLoadCancelled) return;
27429
28399
  failure = error51 instanceof PluginLoadTimeout ? "loadTimeout" : "loadFailed";
27430
28400
  adapter = unavailableAdapter(descriptor, failure);
27431
28401
  }
@@ -27633,7 +28603,7 @@ var SingleNativeCodexAccount = class {
27633
28603
 
27634
28604
  // packages/host-runtime/src/account/codex-home-auth.ts
27635
28605
  import { readFile as readFile5 } from "node:fs/promises";
27636
- import path10 from "node:path";
28606
+ import path11 from "node:path";
27637
28607
  var CODEX_API_AUTH_IDENTITY_FALLBACK = "BANK OF TOKEN";
27638
28608
  function tomlUnquote(value2) {
27639
28609
  const trimmed = value2.trim();
@@ -27779,10 +28749,10 @@ function inspectCodexApiUsageSource(input) {
27779
28749
  return { baseUrl, apiKey };
27780
28750
  }
27781
28751
  async function inspectCodexHomeAuth(codexHome) {
27782
- const root = path10.resolve(codexHome);
28752
+ const root = path11.resolve(codexHome);
27783
28753
  const [configToml, authJson] = await Promise.all([
27784
- readOptionalUtf8(path10.join(root, "config.toml")),
27785
- readOptionalUtf8(path10.join(root, "auth.json"))
28754
+ readOptionalUtf8(path11.join(root, "config.toml")),
28755
+ readOptionalUtf8(path11.join(root, "auth.json"))
27786
28756
  ]);
27787
28757
  return inspectCodexAuthDocuments({
27788
28758
  ...configToml ? { configToml } : {},
@@ -27790,10 +28760,10 @@ async function inspectCodexHomeAuth(codexHome) {
27790
28760
  });
27791
28761
  }
27792
28762
  async function inspectCodexHomeApiUsageSource(codexHome, env = process.env) {
27793
- const root = path10.resolve(codexHome);
28763
+ const root = path11.resolve(codexHome);
27794
28764
  const [configToml, authJson] = await Promise.all([
27795
- readOptionalUtf8(path10.join(root, "config.toml")),
27796
- readOptionalUtf8(path10.join(root, "auth.json"))
28765
+ readOptionalUtf8(path11.join(root, "config.toml")),
28766
+ readOptionalUtf8(path11.join(root, "auth.json"))
27797
28767
  ]);
27798
28768
  return inspectCodexApiUsageSource({
27799
28769
  ...configToml ? { configToml } : {},
@@ -28835,25 +29805,25 @@ function resolveExternalSessionTreeIds(records) {
28835
29805
  const resolve = (start) => {
28836
29806
  const cached2 = resolved.get(start.hostThreadId);
28837
29807
  if (cached2) return cached2;
28838
- const path25 = [];
29808
+ const path26 = [];
28839
29809
  const visited = /* @__PURE__ */ new Set();
28840
29810
  let current = start;
28841
29811
  while (true) {
28842
29812
  const known = resolved.get(current.hostThreadId);
28843
29813
  if (known) {
28844
- for (const record3 of path25) resolved.set(record3.hostThreadId, known);
29814
+ for (const record3 of path26) resolved.set(record3.hostThreadId, known);
28845
29815
  return known;
28846
29816
  }
28847
29817
  if (visited.has(current.hostThreadId)) {
28848
29818
  throw new Error("External Thread Fork tree contains a cycle");
28849
29819
  }
28850
29820
  visited.add(current.hostThreadId);
28851
- path25.push(current);
29821
+ path26.push(current);
28852
29822
  const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
28853
29823
  const source = sourceId ? byId.get(sourceId) : void 0;
28854
29824
  if (!source) {
28855
29825
  const root = current.hostThreadId;
28856
- for (const record3 of path25) resolved.set(record3.hostThreadId, root);
29826
+ for (const record3 of path26) resolved.set(record3.hostThreadId, root);
28857
29827
  return root;
28858
29828
  }
28859
29829
  current = source;
@@ -29189,6 +30159,9 @@ function isHostApprovalRequestId(value2) {
29189
30159
  function isHostQuestionRequestId(value2) {
29190
30160
  return typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= HOST_QUESTION_REQUEST_ID_MIN && value2 <= HOST_QUESTION_REQUEST_ID_MAX;
29191
30161
  }
30162
+ function jsonRpcResponseFailed(value2) {
30163
+ return value2.error != null;
30164
+ }
29192
30165
  function classifyCreateRequestRoute(request, defaultAgent) {
29193
30166
  const route = decodeCreateRoute(request);
29194
30167
  if (!route) return null;
@@ -29291,6 +30264,9 @@ var AppServerHost = class {
29291
30264
  #runningSubagentsByParent = /* @__PURE__ */ new Map();
29292
30265
  #pendingExternalCommandRequests = /* @__PURE__ */ new Set();
29293
30266
  #closeRequested = false;
30267
+ #pluginLoadAbort = new AbortController();
30268
+ #pluginLoading;
30269
+ #desktopRequests = new DesktopRequestQueue();
29294
30270
  #drainActiveWorkOnInputEnd = false;
29295
30271
  #desktopInputEnded = false;
29296
30272
  constructor(options2) {
@@ -29302,7 +30278,7 @@ var AppServerHost = class {
29302
30278
  };
29303
30279
  this.#writer = new OrderedWriter(this.#options.desktopOutput);
29304
30280
  const environment = this.#options.environment ?? process.env;
29305
- const permanentHome = path11.resolve(environment.CODEX_HOME ?? path11.join(os2.homedir(), ".codex"));
30281
+ const permanentHome = path12.resolve(environment.CODEX_HOME ?? path12.join(os2.homedir(), ".codex"));
29306
30282
  this.#ownsOfficialRuntimeScope = options2.officialRuntimeScope === void 0;
29307
30283
  this.#officialRuntimeScope = options2.officialRuntimeScope ?? new OfficialRuntimeScope({
29308
30284
  diagnosticOutput: this.#options.diagnosticOutput,
@@ -29373,7 +30349,24 @@ var AppServerHost = class {
29373
30349
  environment: this.#options.environment ?? process.env,
29374
30350
  repository: this.#repository,
29375
30351
  consumeOutputs: (thread) => this.#consumeHarnessOutputs(thread),
29376
- diagnose: (error51) => this.#diagnose(error51)
30352
+ diagnose: (error51) => this.#diagnose(error51),
30353
+ subagentRunning: (threadId2) => this.#subagentThreadStatuses.get(threadId2) === "active",
30354
+ idleRelease: {
30355
+ queue: this.#desktopRequests,
30356
+ onClosed: async (thread) => {
30357
+ for (const pending of [...this.#pendingDesktopApprovals.values()]) {
30358
+ if (pending.thread === thread)
30359
+ await this.#resolveDesktopApproval(pending.interaction.interactionId);
30360
+ }
30361
+ for (const pending of [...this.#pendingDesktopQuestions.values()]) {
30362
+ if (pending.thread === thread)
30363
+ await this.#resolveDesktopQuestion(pending.interaction.interactionId);
30364
+ }
30365
+ },
30366
+ canRelease: (thread) => !this.#hasRunningSubagents(thread.id) && !this.#externalSteering.hasPending(thread.id) && !this.#pendingExternalCommandRequests.has(thread.id) && ![...this.#pendingDesktopApprovals.values()].some(
30367
+ (pending) => pending.thread === thread
30368
+ ) && ![...this.#pendingDesktopQuestions.values()].some((pending) => pending.thread === thread)
30369
+ }
29377
30370
  });
29378
30371
  this.#delegationCoordinator = new HarnessDelegationCoordinator({
29379
30372
  adapters: this.#externalAdapters,
@@ -29393,14 +30386,14 @@ var AppServerHost = class {
29393
30386
  activeOfficialParents: () => [...this.#activeOfficialTurns.keys()]
29394
30387
  });
29395
30388
  const unregisterDelegationApi = options2.onDelegationApi?.({
29396
- listHarnesses: () => this.#delegationCoordinator.listHarnesses(),
29397
- inspect: (input) => this.#delegationCoordinator.inspect(input),
29398
- start: (input) => this.#delegationCoordinator.start(input),
29399
- send: (input) => this.#delegationCoordinator.send(input),
29400
- cancel: (input) => this.#delegationCoordinator.cancel(input),
29401
- read: (input) => this.#delegationCoordinator.read(input),
29402
- wait: (input) => this.#delegationCoordinator.wait(input),
29403
- list: (input) => this.#delegationCoordinator.list(input),
30389
+ listHarnesses: () => this.#waitForPlugins().then(() => this.#delegationCoordinator.listHarnesses()),
30390
+ inspect: (input) => this.#waitForPlugins().then(() => this.#delegationCoordinator.inspect(input)),
30391
+ start: (input) => this.#waitForPlugins().then(() => this.#delegationCoordinator.start(input)),
30392
+ send: (input) => this.#waitForPlugins().then(() => this.#delegationCoordinator.send(input)),
30393
+ cancel: (input) => this.#waitForPlugins().then(() => this.#delegationCoordinator.cancel(input)),
30394
+ read: (input) => this.#waitForPlugins().then(() => this.#delegationCoordinator.read(input)),
30395
+ wait: (input) => this.#waitForPlugins().then(() => this.#delegationCoordinator.wait(input)),
30396
+ list: (input) => this.#waitForPlugins().then(() => this.#delegationCoordinator.list(input)),
29404
30397
  canHandleStart: (input) => this.#canHandleDelegationStart(input),
29405
30398
  ownsThread: (threadId2) => this.#ownsDelegationThread(threadId2)
29406
30399
  });
@@ -29409,6 +30402,8 @@ var AppServerHost = class {
29409
30402
  close() {
29410
30403
  if (this.#closeRequested) return;
29411
30404
  this.#closeRequested = true;
30405
+ this.#externalRuntime.idleRelease.disable();
30406
+ this.#pluginLoadAbort.abort();
29412
30407
  this.#externalSteering.close();
29413
30408
  this.#signalActiveWorkChanged();
29414
30409
  this.#options.desktopInput.destroy();
@@ -29427,25 +30422,38 @@ var AppServerHost = class {
29427
30422
  if (typeof desktopInput.end === "function") desktopInput.end();
29428
30423
  else desktopInput.destroy();
29429
30424
  }
30425
+ #waitForPlugins() {
30426
+ return this.#pluginLoading ??= this.#loadInstalledPlugins().catch((error51) => {
30427
+ this.#diagnose(`Harness plugin load failed: ${errorMessage3(error51)}`);
30428
+ });
30429
+ }
30430
+ async #loadInstalledPlugins() {
30431
+ if (!this.#options.pluginRoots || this.#pluginLoadAbort.signal.aborted) return;
30432
+ const plugins = await loadHarnessPlugins({
30433
+ roots: this.#options.pluginRoots,
30434
+ context: this.#options.pluginContext ?? {
30435
+ environment: this.#options.environment ?? process.env,
30436
+ platform: process.platform,
30437
+ managedRemoteHost: false
30438
+ },
30439
+ reservedIds: new Set(this.#externalAdapters.keys()),
30440
+ signal: this.#pluginLoadAbort.signal,
30441
+ diagnose: (diagnostic) => this.#diagnose(`Harness plugin: ${JSON.stringify(diagnostic)}`)
30442
+ });
30443
+ if (this.#pluginLoadAbort.signal.aborted) {
30444
+ await plugins.close().catch((error51) => this.#diagnose(error51));
30445
+ return;
30446
+ }
30447
+ this.#pluginDescriptors = plugins.list();
30448
+ for (const [id2, adapter] of plugins.adapters) this.#externalAdapters.set(id2, adapter);
30449
+ }
29430
30450
  async run() {
29431
30451
  try {
29432
- if (this.#options.pluginRoots) {
29433
- const plugins = await loadHarnessPlugins({
29434
- roots: this.#options.pluginRoots,
29435
- context: this.#options.pluginContext ?? {
29436
- environment: this.#options.environment ?? process.env,
29437
- platform: process.platform,
29438
- managedRemoteHost: false
29439
- },
29440
- reservedIds: new Set(this.#externalAdapters.keys()),
29441
- diagnose: (diagnostic) => this.#diagnose(`Harness plugin: ${JSON.stringify(diagnostic)}`)
29442
- });
29443
- this.#pluginDescriptors = plugins.list();
29444
- for (const [id2, adapter] of plugins.adapters) this.#externalAdapters.set(id2, adapter);
29445
- }
29446
30452
  await this.#repository.initialize();
29447
30453
  } catch (error51) {
29448
30454
  this.#diagnose(`Host initialization failed: ${errorMessage3(error51)}`);
30455
+ this.#pluginLoadAbort.abort();
30456
+ await this.#pluginLoading;
29449
30457
  await Promise.allSettled(
29450
30458
  [...new Set(this.#externalAdapters.values())].map(
29451
30459
  (adapter) => Promise.resolve().then(() => adapter.close())
@@ -29469,6 +30477,7 @@ var AppServerHost = class {
29469
30477
  await this.#officialRuntimeScope.owner.stop().catch((closeError) => this.#diagnose(closeError));
29470
30478
  }
29471
30479
  }
30480
+ void this.#waitForPlugins();
29472
30481
  if (this.#closeRequested) await this.#closeOfficialRuntime();
29473
30482
  try {
29474
30483
  void this.#officialRuntime.failure().then(async () => {
@@ -29483,7 +30492,12 @@ var AppServerHost = class {
29483
30492
  await this.#closeOfficialRuntime();
29484
30493
  return this.#closeRequested ? 0 : 1;
29485
30494
  } finally {
30495
+ this.#pluginLoadAbort.abort();
29486
30496
  this.#externalSteering.close();
30497
+ await this.#desktopRequests.drain();
30498
+ this.#externalRuntime.idleRelease.stop();
30499
+ await this.#externalRuntime.idleRelease.drain();
30500
+ await this.#pluginLoading;
29487
30501
  const threads = this.#externalRuntime.values();
29488
30502
  await Promise.allSettled(threads.map(({ session }) => session.close()));
29489
30503
  await Promise.allSettled(threads.map(({ outputTask }) => outputTask));
@@ -29573,454 +30587,486 @@ var AppServerHost = class {
29573
30587
  }
29574
30588
  continue;
29575
30589
  }
29576
- if (request.method === "codexhost/update/check" || request.method === "codexhost/update/start" || request.method === "codexhost/update/status") {
29577
- this.#dispatchDesktopRequest(() => this.#handleUpdateRequest(request));
29578
- continue;
29579
- }
29580
- if (request.method === "codexhost/account/usage/inspect" || request.method === "codexhost/account/list" || request.method === "codexhost/account/refresh") {
29581
- this.#dispatchDesktopRequest(() => this.#handleCodexAccountRequest(request));
29582
- continue;
30590
+ const threadId2 = isRecord14(request.params) && typeof request.params.threadId === "string" ? request.params.threadId : void 0;
30591
+ this.#dispatchDesktopRequest(
30592
+ () => this.#desktopRequests.run(
30593
+ threadId2,
30594
+ () => this.#externalRuntime.idleRelease.runOperation(
30595
+ threadId2,
30596
+ () => this.#handleDesktopRequest(request, frame)
30597
+ )
30598
+ )
30599
+ );
30600
+ }
30601
+ this.#desktopInputEnded = true;
30602
+ this.#externalRuntime.idleRelease.disable();
30603
+ this.#pluginLoadAbort.abort();
30604
+ await this.#desktopRequests.drain();
30605
+ this.#externalSteering.close();
30606
+ if (this.#drainActiveWorkOnInputEnd) await this.#waitForActiveWorkToDrain();
30607
+ await this.#closeOfficialRuntime();
30608
+ }
30609
+ async #handleDesktopRequest(request, frame) {
30610
+ if (this.#closeRequested) return;
30611
+ if (request.method === LOADED_SESSIONS_METHOD) {
30612
+ await this.#writer.json(
30613
+ rpcEnvelope(request, { result: this.#externalRuntime.idleRelease.list() })
30614
+ );
30615
+ return;
30616
+ }
30617
+ if (request.method === IDLE_RELEASE_SETTINGS_METHOD) {
30618
+ const parsed = idleReleaseSettingsSchema.safeParse(request.params);
30619
+ if (!parsed.success) {
30620
+ await this.#writer.json(rpcError(request, -32602, "Invalid idle release settings"));
30621
+ } else {
30622
+ const settings = this.#externalRuntime.idleRelease.configure(parsed.data);
30623
+ await this.#writer.json(rpcEnvelope(request, { result: settings }));
29583
30624
  }
29584
- if (request.method === "codexhost/harness/accounts/sources") {
29585
- this.#dispatchDesktopRequest(async () => {
29586
- if (!harnessAccountSourceListParamsSchema.safeParse(request.params).success) {
29587
- await this.#writer.json(
29588
- rpcError(request, -32602, "Invalid Harness account source list params")
29589
- );
29590
- return;
29591
- }
29592
- const result = listHarnessAccountSources(
29593
- this.#externalAdapters.values(),
29594
- this.#pluginDescriptors
30625
+ return;
30626
+ }
30627
+ if (request.method === "codexhost/update/check" || request.method === "codexhost/update/start" || request.method === "codexhost/update/status") {
30628
+ this.#dispatchDesktopRequest(() => this.#handleUpdateRequest(request));
30629
+ return;
30630
+ }
30631
+ if (request.method === "codexhost/account/usage/inspect" || request.method === "codexhost/account/list" || request.method === "codexhost/account/refresh") {
30632
+ this.#dispatchDesktopRequest(() => this.#handleCodexAccountRequest(request));
30633
+ return;
30634
+ }
30635
+ if (request.method === "codexhost/harness/accounts/sources") {
30636
+ this.#dispatchDesktopRequest(async () => {
30637
+ if (!harnessAccountSourceListParamsSchema.safeParse(request.params).success) {
30638
+ await this.#writer.json(
30639
+ rpcError(request, -32602, "Invalid Harness account source list params")
29595
30640
  );
29596
- await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
29597
- });
29598
- continue;
29599
- }
29600
- if (request.method === "codexhost/harness/accounts/inspect") {
29601
- this.#dispatchDesktopRequest(async () => {
29602
- const params = harnessAccountInspectParamsSchema.safeParse(request.params);
29603
- if (!params.success) {
29604
- await this.#writer.json(
29605
- rpcError(request, -32602, "Invalid Harness account inspection params")
29606
- );
29607
- return;
29608
- }
29609
- const adapter = this.#externalAdapters.get(params.data.harnessId);
29610
- if (!adapter) {
29611
- await this.#writer.json(
29612
- rpcError(request, -32077, `Harness '${params.data.harnessId}' is unavailable`)
29613
- );
29614
- return;
29615
- }
29616
- const result = harnessAccountInspectResultSchema.parse(
29617
- await this.#inspectHarnessAccount(adapter, params.data.refresh === true)
30641
+ return;
30642
+ }
30643
+ await this.#waitForPlugins();
30644
+ const result = listHarnessAccountSources(
30645
+ this.#externalAdapters.values(),
30646
+ this.#pluginDescriptors
30647
+ );
30648
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
30649
+ });
30650
+ return;
30651
+ }
30652
+ if (request.method === "codexhost/harness/accounts/inspect") {
30653
+ this.#dispatchDesktopRequest(async () => {
30654
+ const params = harnessAccountInspectParamsSchema.safeParse(request.params);
30655
+ if (!params.success) {
30656
+ await this.#writer.json(
30657
+ rpcError(request, -32602, "Invalid Harness account inspection params")
29618
30658
  );
29619
- await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
29620
- });
29621
- continue;
29622
- }
29623
- if (request.method === "codexhost/harness/accounts/list") {
29624
- this.#dispatchDesktopRequest(async () => {
29625
- const params = harnessAccountListParamsSchema.safeParse(request.params);
29626
- if (!params.success) {
29627
- await this.#writer.json(
29628
- rpcError(request, -32602, "Invalid Harness account list params")
29629
- );
29630
- return;
29631
- }
29632
- const inspections = await Promise.all(
29633
- [...this.#externalAdapters.values()].map(
29634
- (adapter) => this.#inspectHarnessAccount(adapter, params.data.refresh === true)
29635
- )
30659
+ return;
30660
+ }
30661
+ await this.#waitForPlugins();
30662
+ const adapter = this.#externalAdapters.get(params.data.harnessId);
30663
+ if (!adapter) {
30664
+ await this.#writer.json(
30665
+ rpcError(request, -32077, `Harness '${params.data.harnessId}' is unavailable`)
29636
30666
  );
29637
- const result = harnessAccountListResultSchema.parse({
29638
- accounts: inspections.flatMap(
29639
- ({ harnessId, harnessName: harnessName2, account }) => account ? [{ ...account, harnessId, harnessName: harnessName2 }] : []
29640
- )
29641
- });
29642
- await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
29643
- });
29644
- continue;
29645
- }
29646
- if (request.method === "codexhost/harness/inspect") {
29647
- this.#dispatchDesktopRequest(() => this.#inspectHarness(request));
29648
- continue;
29649
- }
29650
- if (request.method === "codexhost/harness/web-ui/open") {
29651
- this.#dispatchDesktopRequest(() => this.#openHarnessWebUi(request));
29652
- continue;
29653
- }
29654
- if (request.method === "codexhost/harness/plugins/list") {
29655
- this.#dispatchDesktopRequest(async () => {
29656
- if (!harnessPluginListParamsSchema.safeParse(request.params).success) {
29657
- await this.#writer.json(
29658
- rpcError(request, -32602, "Invalid Harness plugin list params")
29659
- );
29660
- return;
29661
- }
29662
- const result = harnessPluginListResultSchema.parse({ plugins: this.#pluginDescriptors });
29663
- await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
30667
+ return;
30668
+ }
30669
+ const result = harnessAccountInspectResultSchema.parse(
30670
+ await this.#inspectHarnessAccount(adapter, params.data.refresh === true)
30671
+ );
30672
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
30673
+ });
30674
+ return;
30675
+ }
30676
+ if (request.method === "codexhost/harness/accounts/list") {
30677
+ this.#dispatchDesktopRequest(async () => {
30678
+ const params = harnessAccountListParamsSchema.safeParse(request.params);
30679
+ if (!params.success) {
30680
+ await this.#writer.json(rpcError(request, -32602, "Invalid Harness account list params"));
30681
+ return;
30682
+ }
30683
+ await this.#waitForPlugins();
30684
+ const inspections = await Promise.all(
30685
+ [...this.#externalAdapters.values()].map(
30686
+ (adapter) => this.#inspectHarnessAccount(adapter, params.data.refresh === true)
30687
+ )
30688
+ );
30689
+ const result = harnessAccountListResultSchema.parse({
30690
+ accounts: inspections.flatMap(
30691
+ ({ harnessId, harnessName: harnessName2, account }) => account ? [{ ...account, harnessId, harnessName: harnessName2 }] : []
30692
+ )
29664
30693
  });
29665
- continue;
29666
- }
29667
- if (isSessionImportRequest(request.method)) {
29668
- this.#dispatchDesktopRequest(() => this.#handleSessionImport(request));
29669
- continue;
29670
- }
29671
- if (request.method === "codexhost/thread/fork") {
29672
- await this.#forkExternalThreadFromRenderer(request);
29673
- continue;
30694
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
30695
+ });
30696
+ return;
30697
+ }
30698
+ if (request.method === "codexhost/harness/inspect") {
30699
+ this.#dispatchDesktopRequest(() => this.#inspectHarness(request));
30700
+ return;
30701
+ }
30702
+ if (request.method === "codexhost/harness/web-ui/open") {
30703
+ this.#dispatchDesktopRequest(() => this.#openHarnessWebUi(request));
30704
+ return;
30705
+ }
30706
+ if (request.method === "codexhost/harness/plugins/list") {
30707
+ this.#dispatchDesktopRequest(async () => {
30708
+ if (!harnessPluginListParamsSchema.safeParse(request.params).success) {
30709
+ await this.#writer.json(rpcError(request, -32602, "Invalid Harness plugin list params"));
30710
+ return;
30711
+ }
30712
+ await this.#waitForPlugins();
30713
+ const result = harnessPluginListResultSchema.parse({ plugins: this.#pluginDescriptors });
30714
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
30715
+ });
30716
+ return;
30717
+ }
30718
+ if (isSessionImportRequest(request.method)) {
30719
+ this.#dispatchDesktopRequest(() => this.#handleSessionImport(request));
30720
+ return;
30721
+ }
30722
+ if (request.method === "codexhost/thread/fork") {
30723
+ await this.#forkExternalThreadFromRenderer(request);
30724
+ return;
30725
+ }
30726
+ if (request.method === "codexhost/thread/inspect") {
30727
+ await this.#inspectThread(request);
30728
+ return;
30729
+ }
30730
+ if (request.method === "codexhost/thread/usage/inspect") {
30731
+ await this.#inspectThreadUsage(request);
30732
+ return;
30733
+ }
30734
+ if (request.method === "codexhost/thread/ownership/list") {
30735
+ await this.#listThreadOwnership(request);
30736
+ return;
30737
+ }
30738
+ if (request.method === "codexhost/thread/model/select") {
30739
+ await this.#selectThreadModel(request);
30740
+ return;
30741
+ }
30742
+ if (request.method === "codexhost/thread/thinking/select") {
30743
+ await this.#selectThreadThinking(request);
30744
+ return;
30745
+ }
30746
+ if (request.method === "codexhost/thread/permission-mode/select") {
30747
+ await this.#selectThreadPermissionMode(request);
30748
+ return;
30749
+ }
30750
+ if (request.method === "codexhost/harness/commands/inspect") {
30751
+ const params = harnessCommandsInspectParamsSchema.safeParse(request.params);
30752
+ if (!params.success) {
30753
+ await this.#writer.json(
30754
+ rpcError(request, -32602, "Invalid Harness command inspection params")
30755
+ );
30756
+ } else {
30757
+ await this.#writeHarnessCommandCatalog(request, params.data.harnessId);
29674
30758
  }
29675
- if (request.method === "codexhost/thread/inspect") {
29676
- await this.#inspectThread(request);
29677
- continue;
30759
+ return;
30760
+ }
30761
+ if (request.method === "codexhost/thread/commands/inspect") {
30762
+ await this.#inspectThreadCommands(request);
30763
+ return;
30764
+ }
30765
+ if (request.method === "codexhost/thread/command/execute") {
30766
+ await this.#executeThreadCommand(request);
30767
+ return;
30768
+ }
30769
+ if (request.method === "thread/list") {
30770
+ let listRequest;
30771
+ try {
30772
+ const decoded = decodeThreadListRequest(request);
30773
+ if (!decoded) throw new Error("Expected thread/list request");
30774
+ listRequest = decoded;
30775
+ } catch (error51) {
30776
+ await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
30777
+ return;
29678
30778
  }
29679
- if (request.method === "codexhost/thread/usage/inspect") {
29680
- await this.#inspectThreadUsage(request);
29681
- continue;
30779
+ if (!listRequest.supportsExternal) {
30780
+ await this.#forwardOfficialRequest(request, frame);
30781
+ return;
29682
30782
  }
29683
- if (request.method === "codexhost/thread/ownership/list") {
29684
- await this.#listThreadOwnership(request);
29685
- continue;
30783
+ this.#dispatchDesktopRequest(() => this.#listThreads(request, listRequest));
30784
+ return;
30785
+ }
30786
+ if (request.method === "thread/archive" || request.method === "thread/unarchive") {
30787
+ let threadId2;
30788
+ try {
30789
+ const decoded = decodeThreadArchiveRequest(request);
30790
+ if (!decoded) throw new Error(`Expected ${request.method} request`);
30791
+ threadId2 = decoded.threadId;
30792
+ } catch (error51) {
30793
+ await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
30794
+ return;
29686
30795
  }
29687
- if (request.method === "codexhost/thread/model/select") {
29688
- await this.#selectThreadModel(request);
29689
- continue;
30796
+ const location = await this.#locateExternalThread(threadId2);
30797
+ if (await this.#writeResolutionError(request, location)) return;
30798
+ if (location.kind === "official") {
30799
+ await this.#forwardOfficialRequest(request, frame);
30800
+ return;
29690
30801
  }
29691
- if (request.method === "codexhost/thread/thinking/select") {
29692
- await this.#selectThreadThinking(request);
29693
- continue;
30802
+ if (location.kind === "external") {
30803
+ await this.#setExternalThreadArchived(
30804
+ request,
30805
+ location,
30806
+ request.method === "thread/archive"
30807
+ );
29694
30808
  }
29695
- if (request.method === "codexhost/thread/permission-mode/select") {
29696
- await this.#selectThreadPermissionMode(request);
29697
- continue;
30809
+ return;
30810
+ }
30811
+ if (request.method === "thread/metadata/update") {
30812
+ let threadId2;
30813
+ let decoded;
30814
+ try {
30815
+ const parsed = decodeThreadMetadataUpdateRequest(request);
30816
+ if (!parsed) throw new Error("Expected thread/metadata/update request");
30817
+ decoded = parsed;
30818
+ threadId2 = decoded.threadId;
30819
+ } catch (error51) {
30820
+ await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
30821
+ return;
29698
30822
  }
29699
- if (request.method === "codexhost/harness/commands/inspect") {
29700
- const params = harnessCommandsInspectParamsSchema.safeParse(request.params);
29701
- if (!params.success) {
29702
- await this.#writer.json(
29703
- rpcError(request, -32602, "Invalid Harness command inspection params")
29704
- );
29705
- } else {
29706
- await this.#writeHarnessCommandCatalog(request, params.data.harnessId);
29707
- }
29708
- continue;
30823
+ const location = await this.#locateExternalThread(threadId2);
30824
+ if (await this.#writeResolutionError(request, location)) return;
30825
+ if (location.kind === "official") {
30826
+ await this.#forwardOfficialRequest(request, frame);
30827
+ return;
29709
30828
  }
29710
- if (request.method === "codexhost/thread/commands/inspect") {
29711
- await this.#inspectThreadCommands(request);
29712
- continue;
30829
+ if (location.kind !== "external") return;
30830
+ if (decoded.isPinned === void 0 || decoded.gitInfo !== void 0) {
30831
+ await this.#writer.json(
30832
+ rpcError(request, -32078, "External Thread metadata updates are unsupported")
30833
+ );
30834
+ return;
29713
30835
  }
29714
- if (request.method === "codexhost/thread/command/execute") {
29715
- this.#dispatchDesktopRequest(() => this.#executeThreadCommand(request));
29716
- continue;
30836
+ await this.#setExternalThreadPinned(request, location, decoded.isPinned ?? false);
30837
+ return;
30838
+ }
30839
+ let createRoute;
30840
+ try {
30841
+ createRoute = classifyCreateRequestRoute(request, this.#options.defaultAgent);
30842
+ } catch (error51) {
30843
+ await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
30844
+ return;
30845
+ }
30846
+ if (createRoute) {
30847
+ this.#options.onCreateRequestRoute?.(createRoute);
30848
+ this.#options.onRequestRoute?.(
30849
+ this.#routeObservationTracker.registerCreate(
30850
+ request.id,
30851
+ createRoute,
30852
+ classifyThreadPurpose(request)
30853
+ )
30854
+ );
30855
+ }
30856
+ if (createRoute && createRoute.selectedHarness !== "codex") {
30857
+ await this.#startExternalThread(request, createRoute.selectedHarness);
30858
+ return;
30859
+ }
30860
+ if (request.method === "thread/fork") {
30861
+ const params = isRecord14(request.params) ? request.params : {};
30862
+ const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30863
+ if (resolution.kind === "error") {
30864
+ await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
30865
+ return;
29717
30866
  }
29718
- if (request.method === "thread/list") {
29719
- let listRequest;
30867
+ if (resolution.kind === "external") {
30868
+ let fork;
29720
30869
  try {
29721
- const decoded = decodeThreadListRequest(request);
29722
- if (!decoded) throw new Error("Expected thread/list request");
29723
- listRequest = decoded;
30870
+ const decoded = decodeThreadForkRequest(request);
30871
+ if (!decoded) throw new Error("Expected thread/fork request");
30872
+ fork = decoded;
29724
30873
  } catch (error51) {
29725
30874
  await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
29726
- continue;
29727
- }
29728
- if (!listRequest.supportsExternal) {
29729
- await this.#forwardOfficialRequest(request, frame);
29730
- continue;
30875
+ return;
29731
30876
  }
29732
- this.#dispatchDesktopRequest(() => this.#listThreads(request, listRequest));
29733
- continue;
30877
+ await this.#forkExternalThread(request, resolution.thread, fork);
30878
+ return;
29734
30879
  }
29735
- if (request.method === "thread/archive" || request.method === "thread/unarchive") {
29736
- let threadId2;
30880
+ }
30881
+ if (request.method === "thread/revert") {
30882
+ const params = isRecord14(request.params) ? request.params : {};
30883
+ const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30884
+ if (resolution.kind === "error") {
30885
+ await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
30886
+ return;
30887
+ }
30888
+ if (resolution.kind === "external") {
30889
+ let revert;
29737
30890
  try {
29738
- const decoded = decodeThreadArchiveRequest(request);
29739
- if (!decoded) throw new Error(`Expected ${request.method} request`);
29740
- threadId2 = decoded.threadId;
30891
+ const decoded = decodeThreadRevertRequest(request);
30892
+ if (!decoded) throw new Error("Expected thread/revert request");
30893
+ revert = decoded;
29741
30894
  } catch (error51) {
29742
30895
  await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
29743
- continue;
29744
- }
29745
- const location = await this.#locateExternalThread(threadId2);
29746
- if (await this.#writeResolutionError(request, location)) continue;
29747
- if (location.kind === "official") {
29748
- await this.#forwardOfficialRequest(request, frame);
29749
- continue;
29750
- }
29751
- if (location.kind === "external") {
29752
- await this.#setExternalThreadArchived(
29753
- request,
29754
- location,
29755
- request.method === "thread/archive"
29756
- );
30896
+ return;
29757
30897
  }
29758
- continue;
30898
+ await this.#revertExternalThread(request, resolution.thread, revert);
30899
+ return;
30900
+ }
30901
+ }
30902
+ if (request.method === "thread/rollback") {
30903
+ const params = isRecord14(request.params) ? request.params : {};
30904
+ const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30905
+ if (resolution.kind === "error") {
30906
+ await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
30907
+ return;
29759
30908
  }
29760
- if (request.method === "thread/metadata/update") {
29761
- let threadId2;
29762
- let decoded;
30909
+ if (resolution.kind === "external") {
30910
+ let rollback;
29763
30911
  try {
29764
- const parsed2 = decodeThreadMetadataUpdateRequest(request);
29765
- if (!parsed2) throw new Error("Expected thread/metadata/update request");
29766
- decoded = parsed2;
29767
- threadId2 = decoded.threadId;
30912
+ const decoded = decodeThreadRollbackRequest(request);
30913
+ if (!decoded) throw new Error("Expected thread/rollback request");
30914
+ rollback = decoded;
29768
30915
  } catch (error51) {
29769
30916
  await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
29770
- continue;
29771
- }
29772
- const location = await this.#locateExternalThread(threadId2);
29773
- if (await this.#writeResolutionError(request, location)) continue;
29774
- if (location.kind === "official") {
29775
- await this.#forwardOfficialRequest(request, frame);
29776
- continue;
29777
- }
29778
- if (location.kind !== "external") continue;
29779
- if (decoded.isPinned === void 0 || decoded.gitInfo !== void 0) {
29780
- await this.#writer.json(
29781
- rpcError(request, -32078, "External Thread metadata updates are unsupported")
29782
- );
29783
- continue;
30917
+ return;
29784
30918
  }
29785
- await this.#setExternalThreadPinned(request, location, decoded.isPinned ?? false);
29786
- continue;
30919
+ await this.#rollbackExternalThread(request, resolution.thread, rollback);
30920
+ return;
29787
30921
  }
29788
- let createRoute;
29789
- try {
29790
- createRoute = classifyCreateRequestRoute(request, this.#options.defaultAgent);
29791
- } catch (error51) {
29792
- await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
29793
- continue;
30922
+ }
30923
+ if (request.method === "thread/turns/list" || request.method === "thread/items/list") {
30924
+ const params = requestObject(request);
30925
+ const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30926
+ if (await this.#writeResolutionError(request, resolution)) return;
30927
+ if (resolution.kind === "external") {
30928
+ await this.#listExternalHistory(
30929
+ request,
30930
+ resolution.thread,
30931
+ params,
30932
+ resolution.historyFresh
30933
+ );
30934
+ return;
29794
30935
  }
29795
- if (createRoute) {
29796
- this.#options.onCreateRequestRoute?.(createRoute);
30936
+ }
30937
+ if (request.method === "turn/start") {
30938
+ const params = requestObject(request);
30939
+ const threadId2 = params.threadId;
30940
+ const resolution = typeof threadId2 === "string" ? await this.#resolveExternalThread(threadId2) : { kind: "official" };
30941
+ if (typeof threadId2 === "string") {
29797
30942
  this.#options.onRequestRoute?.(
29798
- this.#routeObservationTracker.registerCreate(
29799
- request.id,
29800
- createRoute,
29801
- classifyThreadPurpose(request)
30943
+ this.#routeObservationTracker.observeTurn(
30944
+ threadId2,
30945
+ resolution.kind === "external" ? resolution.thread.harnessId : "codex"
29802
30946
  )
29803
30947
  );
29804
30948
  }
29805
- if (createRoute && createRoute.selectedHarness !== "codex") {
29806
- await this.#startExternalThread(request, createRoute.selectedHarness);
29807
- continue;
30949
+ if (await this.#writeResolutionError(request, resolution)) return;
30950
+ if (resolution.kind === "external") {
30951
+ this.#dispatchDesktopRequest(
30952
+ () => this.#startExternalTurn(request, resolution.thread),
30953
+ resolution.thread.id
30954
+ );
30955
+ return;
29808
30956
  }
29809
- if (request.method === "thread/fork") {
29810
- const params = isRecord14(request.params) ? request.params : {};
29811
- const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
29812
- if (resolution.kind === "error") {
29813
- await this.#writer.json(
29814
- rpcError(request, resolution.error.code, resolution.error.message)
29815
- );
29816
- continue;
29817
- }
29818
- if (resolution.kind === "external") {
29819
- let fork;
29820
- try {
29821
- const decoded = decodeThreadForkRequest(request);
29822
- if (!decoded) throw new Error("Expected thread/fork request");
29823
- fork = decoded;
29824
- } catch (error51) {
29825
- await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
29826
- continue;
29827
- }
29828
- await this.#forkExternalThread(request, resolution.thread, fork);
29829
- continue;
29830
- }
30957
+ if (typeof threadId2 === "string") {
30958
+ this.#pendingOfficialTurnStarts.set(request.id, threadId2);
29831
30959
  }
29832
- if (request.method === "thread/revert") {
29833
- const params = isRecord14(request.params) ? request.params : {};
29834
- const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
29835
- if (resolution.kind === "error") {
29836
- await this.#writer.json(
29837
- rpcError(request, resolution.error.code, resolution.error.message)
29838
- );
29839
- continue;
29840
- }
29841
- if (resolution.kind === "external") {
29842
- let revert;
29843
- try {
29844
- const decoded = decodeThreadRevertRequest(request);
29845
- if (!decoded) throw new Error("Expected thread/revert request");
29846
- revert = decoded;
29847
- } catch (error51) {
29848
- await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
29849
- continue;
29850
- }
29851
- await this.#revertExternalThread(request, resolution.thread, revert);
29852
- continue;
29853
- }
30960
+ }
30961
+ if (request.method === "turn/steer") {
30962
+ const params = requestObject(request);
30963
+ const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30964
+ if (await this.#writeResolutionError(request, resolution)) return;
30965
+ if (resolution.kind === "external") {
30966
+ this.#dispatchDesktopRequest(
30967
+ () => this.#steerExternalTurn(request, resolution.thread),
30968
+ resolution.thread.id
30969
+ );
30970
+ return;
29854
30971
  }
29855
- if (request.method === "thread/rollback") {
29856
- const params = isRecord14(request.params) ? request.params : {};
29857
- const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
29858
- if (resolution.kind === "error") {
29859
- await this.#writer.json(
29860
- rpcError(request, resolution.error.code, resolution.error.message)
29861
- );
29862
- continue;
29863
- }
29864
- if (resolution.kind === "external") {
29865
- let rollback;
29866
- try {
29867
- const decoded = decodeThreadRollbackRequest(request);
29868
- if (!decoded) throw new Error("Expected thread/rollback request");
29869
- rollback = decoded;
29870
- } catch (error51) {
29871
- await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
29872
- continue;
29873
- }
29874
- await this.#rollbackExternalThread(request, resolution.thread, rollback);
29875
- continue;
29876
- }
30972
+ }
30973
+ if (request.method === "turn/interrupt") {
30974
+ const params = requestObject(request);
30975
+ const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30976
+ if (await this.#writeResolutionError(request, resolution)) return;
30977
+ if (resolution.kind === "external") {
30978
+ await this.#interruptExternalTurn(request, resolution.thread, params.turnId);
30979
+ return;
30980
+ }
30981
+ }
30982
+ if (request.method === "thread/read") {
30983
+ const params = requestObject(request);
30984
+ const location = typeof params.threadId === "string" ? await this.#locateExternalThread(params.threadId) : { kind: "official" };
30985
+ if (location.kind === "error") {
30986
+ await this.#writer.json(rpcError(request, location.error.code, location.error.message));
30987
+ return;
29877
30988
  }
29878
- if (request.method === "thread/turns/list" || request.method === "thread/items/list") {
29879
- const params = requestObject(request);
29880
- const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
29881
- if (await this.#writeResolutionError(request, resolution)) continue;
29882
- if (resolution.kind === "external") {
29883
- await this.#listExternalHistory(
30989
+ if (location.kind === "official") {
30990
+ await this.#forwardOfficialRequest(request, frame);
30991
+ return;
30992
+ }
30993
+ if (params.includeTurns !== true) {
30994
+ await this.#readExternalThreadMetadata(request, location);
30995
+ return;
30996
+ }
30997
+ if (location.record.historyMode === "paginated") {
30998
+ await this.#writer.json(
30999
+ rpcError(request, -32602, "Paginated External Threads require thread/turns/list")
31000
+ );
31001
+ return;
31002
+ }
31003
+ }
31004
+ if (request.method === "thread/read" || request.method === "thread/resume") {
31005
+ const params = requestObject(request);
31006
+ const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
31007
+ if (await this.#writeResolutionError(request, resolution)) return;
31008
+ if (resolution.kind === "external") {
31009
+ if (request.method === "thread/read") {
31010
+ await this.#readExternalThread(
29884
31011
  request,
29885
31012
  resolution.thread,
29886
- params,
31013
+ params.includeTurns === true,
29887
31014
  resolution.historyFresh
29888
31015
  );
29889
- continue;
29890
- }
29891
- }
29892
- if (request.method === "turn/start") {
29893
- const params = requestObject(request);
29894
- const threadId2 = params.threadId;
29895
- const resolution = typeof threadId2 === "string" ? await this.#resolveExternalThread(threadId2) : { kind: "official" };
29896
- if (typeof threadId2 === "string") {
29897
- this.#options.onRequestRoute?.(
29898
- this.#routeObservationTracker.observeTurn(
29899
- threadId2,
29900
- resolution.kind === "external" ? resolution.thread.harnessId : "codex"
29901
- )
31016
+ } else {
31017
+ await this.#resumeExternalThread(
31018
+ request,
31019
+ resolution.thread,
31020
+ params,
31021
+ resolution.historyFresh
29902
31022
  );
29903
31023
  }
29904
- if (await this.#writeResolutionError(request, resolution)) continue;
29905
- if (resolution.kind === "external") {
29906
- this.#dispatchDesktopRequest(() => this.#startExternalTurn(request, resolution.thread));
29907
- continue;
29908
- }
29909
- if (typeof threadId2 === "string") {
29910
- this.#pendingOfficialTurnStarts.set(request.id, threadId2);
29911
- }
29912
- }
29913
- if (request.method === "turn/steer") {
29914
- const params = requestObject(request);
29915
- const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
29916
- if (await this.#writeResolutionError(request, resolution)) continue;
29917
- if (resolution.kind === "external") {
29918
- this.#dispatchDesktopRequest(() => this.#steerExternalTurn(request, resolution.thread));
29919
- continue;
29920
- }
29921
- }
29922
- if (request.method === "turn/interrupt") {
29923
- const params = requestObject(request);
29924
- const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
29925
- if (await this.#writeResolutionError(request, resolution)) continue;
29926
- if (resolution.kind === "external") {
29927
- await this.#interruptExternalTurn(request, resolution.thread, params.turnId);
29928
- continue;
29929
- }
31024
+ return;
29930
31025
  }
29931
- if (request.method === "thread/read") {
29932
- const params = requestObject(request);
29933
- const location = typeof params.threadId === "string" ? await this.#locateExternalThread(params.threadId) : { kind: "official" };
29934
- if (location.kind === "error") {
29935
- await this.#writer.json(rpcError(request, location.error.code, location.error.message));
29936
- continue;
29937
- }
31026
+ }
31027
+ if (request.method === "thread/unsubscribe") {
31028
+ const params = requestObject(request);
31029
+ if (typeof params.threadId === "string") {
31030
+ const location = await this.#locateExternalThread(params.threadId);
31031
+ if (await this.#writeResolutionError(request, location)) return;
29938
31032
  if (location.kind === "official") {
29939
31033
  await this.#forwardOfficialRequest(request, frame);
29940
- continue;
29941
- }
29942
- if (params.includeTurns !== true) {
29943
- await this.#readExternalThreadMetadata(request, location);
29944
- continue;
31034
+ return;
29945
31035
  }
29946
- if (location.record.historyMode === "paginated") {
31036
+ if (location.kind === "external") {
29947
31037
  await this.#writer.json(
29948
- rpcError(request, -32602, "Paginated External Threads require thread/turns/list")
31038
+ rpcEnvelope(request, {
31039
+ result: { status: location.thread ? "notSubscribed" : "notLoaded" }
31040
+ })
29949
31041
  );
29950
- continue;
29951
- }
29952
- }
29953
- if (request.method === "thread/read" || request.method === "thread/resume") {
29954
- const params = requestObject(request);
29955
- const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
29956
- if (await this.#writeResolutionError(request, resolution)) continue;
29957
- if (resolution.kind === "external") {
29958
- if (request.method === "thread/read") {
29959
- await this.#readExternalThread(
29960
- request,
29961
- resolution.thread,
29962
- params.includeTurns === true,
29963
- resolution.historyFresh
29964
- );
29965
- } else {
29966
- await this.#resumeExternalThread(
29967
- request,
29968
- resolution.thread,
29969
- params,
29970
- resolution.historyFresh
29971
- );
29972
- }
29973
- continue;
29974
- }
29975
- }
29976
- if (request.method === "thread/unsubscribe") {
29977
- const params = requestObject(request);
29978
- if (typeof params.threadId === "string") {
29979
- const location = await this.#locateExternalThread(params.threadId);
29980
- if (await this.#writeResolutionError(request, location)) continue;
29981
- if (location.kind === "official") {
29982
- await this.#forwardOfficialRequest(request, frame);
29983
- continue;
29984
- }
29985
- if (location.kind === "external") {
29986
- await this.#writer.json(
29987
- rpcEnvelope(request, {
29988
- result: { status: location.thread ? "notSubscribed" : "notLoaded" }
29989
- })
29990
- );
29991
- continue;
29992
- }
31042
+ return;
29993
31043
  }
29994
31044
  }
29995
- if (request.method === "thread/name/set" || request.method === "thread/delete") {
29996
- const params = requestObject(request);
29997
- const location = typeof params.threadId === "string" ? await this.#locateExternalThread(params.threadId) : { kind: "official" };
29998
- if (await this.#writeResolutionError(request, location)) continue;
29999
- if (location.kind === "external") {
30000
- if (request.method === "thread/name/set") {
30001
- await this.#setExternalThreadName(request, location, params.name);
30002
- } else {
30003
- await this.#deleteExternalThread(request, location);
30004
- }
30005
- continue;
31045
+ }
31046
+ if (request.method === "thread/name/set" || request.method === "thread/delete") {
31047
+ const params = requestObject(request);
31048
+ const location = typeof params.threadId === "string" ? await this.#locateExternalThread(params.threadId) : { kind: "official" };
31049
+ if (await this.#writeResolutionError(request, location)) return;
31050
+ if (location.kind === "external") {
31051
+ if (request.method === "thread/name/set") {
31052
+ await this.#setExternalThreadName(request, location, params.name);
31053
+ } else {
31054
+ await this.#deleteExternalThread(request, location);
30006
31055
  }
31056
+ return;
30007
31057
  }
30008
- if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord14(request.params) && typeof request.params.threadId === "string") {
30009
- const location = await this.#locateExternalThread(request.params.threadId);
30010
- if (await this.#writeResolutionError(request, location)) continue;
30011
- if (location.kind === "external") {
30012
- await this.#writer.json(
30013
- rpcError(request, -32076, `External Thread does not support ${request.method}`)
30014
- );
30015
- continue;
30016
- }
31058
+ }
31059
+ if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord14(request.params) && typeof request.params.threadId === "string") {
31060
+ const location = await this.#locateExternalThread(request.params.threadId);
31061
+ if (await this.#writeResolutionError(request, location)) return;
31062
+ if (location.kind === "external") {
31063
+ await this.#writer.json(
31064
+ rpcError(request, -32076, `External Thread does not support ${request.method}`)
31065
+ );
31066
+ return;
30017
31067
  }
30018
- await this.#forwardOfficialRequest(request, frame);
30019
31068
  }
30020
- this.#desktopInputEnded = true;
30021
- this.#externalSteering.close();
30022
- if (this.#drainActiveWorkOnInputEnd) await this.#waitForActiveWorkToDrain();
30023
- await this.#closeOfficialRuntime();
31069
+ await this.#forwardOfficialRequest(request, frame);
30024
31070
  }
30025
31071
  async #forwardOfficialNonRequest(value2, frame) {
30026
31072
  const response = isRecord14(value2) ? value2 : null;
@@ -30731,6 +31777,7 @@ var AppServerHost = class {
30731
31777
  await this.#writer.json(rpcError(request, -32602, "Invalid Harness inspection params"));
30732
31778
  return;
30733
31779
  }
31780
+ await this.#waitForPlugins();
30734
31781
  const registered = [...this.#externalAdapters].find(
30735
31782
  ([harnessId]) => harnessId === params.data.harnessId
30736
31783
  );
@@ -30770,6 +31817,7 @@ var AppServerHost = class {
30770
31817
  await this.#writer.json(rpcError(request, -32602, "Invalid Harness Web UI params"));
30771
31818
  return;
30772
31819
  }
31820
+ await this.#waitForPlugins();
30773
31821
  const adapter = [...this.#externalAdapters].find(
30774
31822
  ([harnessId]) => harnessId === params.data.harnessId
30775
31823
  )?.[1];
@@ -30792,6 +31840,7 @@ var AppServerHost = class {
30792
31840
  }
30793
31841
  }
30794
31842
  async #handleSessionImport(request) {
31843
+ await this.#waitForPlugins();
30795
31844
  this.#sessionImportRequests ??= new SessionImportRequests({
30796
31845
  adapters: this.#externalAdapters,
30797
31846
  descriptors: () => this.#pluginDescriptors,
@@ -30931,6 +31980,7 @@ var AppServerHost = class {
30931
31980
  await this.#writeHarnessCommandCatalog(request, location.record.harnessId);
30932
31981
  }
30933
31982
  async #writeHarnessCommandCatalog(request, harnessId) {
31983
+ await this.#waitForPlugins();
30934
31984
  const adapter = this.#externalAdapters.get(harnessId);
30935
31985
  if (!adapter) {
30936
31986
  await this.#writer.json(rpcError(request, -32077, `Harness '${harnessId}' is unavailable`));
@@ -30955,7 +32005,12 @@ var AppServerHost = class {
30955
32005
  await this.#writer.json(rpcError(request, -32078, "Thread is not externally owned"));
30956
32006
  return;
30957
32007
  }
30958
- const thread = resolution.thread;
32008
+ this.#dispatchDesktopRequest(
32009
+ () => this.#executeResolvedThreadCommand(request, resolution.thread, params.data),
32010
+ resolution.thread.id
32011
+ );
32012
+ }
32013
+ async #executeResolvedThreadCommand(request, thread, params) {
30959
32014
  if (thread.running || this.#externalSteering.hasPending(thread.id) || this.#pendingExternalCommandRequests.has(thread.id)) {
30960
32015
  await this.#writer.json(
30961
32016
  rpcError(request, -32072, "External Thread already has an active operation")
@@ -30976,13 +32031,13 @@ var AppServerHost = class {
30976
32031
  await this.#writer.json(rpcError(request, -32078, catalog.error.message));
30977
32032
  return;
30978
32033
  }
30979
- const descriptor = catalog.value.commands.find(({ id: id2 }) => id2 === params.data.commandId);
32034
+ const descriptor = catalog.value.commands.find(({ id: id2 }) => id2 === params.commandId);
30980
32035
  if (!descriptor) {
30981
32036
  await this.#writer.json(
30982
32037
  rpcError(
30983
32038
  request,
30984
32039
  -32078,
30985
- `External Harness does not expose command '${params.data.commandId}'`
32040
+ `External Harness does not expose command '${params.commandId}'`
30986
32041
  )
30987
32042
  );
30988
32043
  return;
@@ -30991,9 +32046,9 @@ var AppServerHost = class {
30991
32046
  await this.#startExternalCommand(
30992
32047
  request,
30993
32048
  thread,
30994
- params.data.commandId,
30995
- params.data.arguments,
30996
- params.data.turnId,
32049
+ params.commandId,
32050
+ params.arguments,
32051
+ params.turnId,
30997
32052
  "command"
30998
32053
  );
30999
32054
  } catch (error51) {
@@ -31308,6 +32363,7 @@ var AppServerHost = class {
31308
32363
  }
31309
32364
  }
31310
32365
  async #startExternalThread(request, harnessId) {
32366
+ await this.#waitForPlugins();
31311
32367
  const adapter = this.#externalAdapters.get(harnessId);
31312
32368
  if (!adapter) {
31313
32369
  this.#routeObservationTracker.rejectCreate(request.id);
@@ -31364,60 +32420,64 @@ var AppServerHost = class {
31364
32420
  return;
31365
32421
  }
31366
32422
  const session = sessionResult.value;
31367
- try {
31368
- if (session.initialState.nativeRef) {
31369
- record3 = await this.#repository.commitNative(
31370
- record3.hostThreadId,
31371
- session.initialState.nativeRef
32423
+ await this.#externalRuntime.idleRelease.runOperation(record3.hostThreadId, async () => {
32424
+ try {
32425
+ if (session.initialState.nativeRef) {
32426
+ record3 = await this.#repository.commitNative(
32427
+ record3.hostThreadId,
32428
+ session.initialState.nativeRef
32429
+ );
32430
+ }
32431
+ const thread = externalThreadValue({
32432
+ record: record3,
32433
+ turns: [],
32434
+ sessionId: record3.hostThreadId
32435
+ });
32436
+ const externalThread = this.#registerExternalThread({
32437
+ record: record3,
32438
+ session,
32439
+ sessionId: record3.hostThreadId,
32440
+ thread,
32441
+ turns: [],
32442
+ ...requestedModel ? { requestedModel } : {},
32443
+ ...requestedThinkingOptionId ? { requestedThinkingOptionId } : {},
32444
+ ...requestedPermissionModeId ? { requestedPermissionModeId } : {}
32445
+ });
32446
+ this.#routeObservationTracker.bindCreatedThread(request.id, externalThread.id);
32447
+ await this.#writer.json(
32448
+ rpcEnvelope(request, {
32449
+ result: {
32450
+ thread,
32451
+ model: transportModelId,
32452
+ modelProvider: "codexhost",
32453
+ cwd,
32454
+ approvalPolicy: typeof params.approvalPolicy === "string" ? params.approvalPolicy : "never",
32455
+ approvalsReviewer: "user",
32456
+ sandbox: sandboxResult(params),
32457
+ reasoningEffort: "medium",
32458
+ serviceTier: "flex",
32459
+ multiAgentMode: "explicitRequestOnly",
32460
+ activePermissionProfile: null,
32461
+ runtimeWorkspaceRoots: Array.isArray(params.runtimeWorkspaceRoots) ? params.runtimeWorkspaceRoots : [],
32462
+ instructionSources: []
32463
+ }
32464
+ })
32465
+ );
32466
+ await this.#writer.json({
32467
+ method: "thread/started",
32468
+ emittedAtMs: Date.now(),
32469
+ params: { thread }
32470
+ });
32471
+ } catch {
32472
+ this.#externalRuntime.remove(record3.hostThreadId);
32473
+ this.#routeObservationTracker.forgetThread(record3.hostThreadId);
32474
+ await session.close().catch(() => void 0);
32475
+ await this.#repository.removeProvisional(record3.hostThreadId).catch(() => void 0);
32476
+ await this.#writer.json(
32477
+ rpcError(request, -32081, "External Thread could not be persisted")
31372
32478
  );
31373
32479
  }
31374
- const thread = externalThreadValue({
31375
- record: record3,
31376
- turns: [],
31377
- sessionId: record3.hostThreadId
31378
- });
31379
- const externalThread = this.#registerExternalThread({
31380
- record: record3,
31381
- session,
31382
- sessionId: record3.hostThreadId,
31383
- thread,
31384
- turns: [],
31385
- ...requestedModel ? { requestedModel } : {},
31386
- ...requestedThinkingOptionId ? { requestedThinkingOptionId } : {},
31387
- ...requestedPermissionModeId ? { requestedPermissionModeId } : {}
31388
- });
31389
- this.#routeObservationTracker.bindCreatedThread(request.id, externalThread.id);
31390
- await this.#writer.json(
31391
- rpcEnvelope(request, {
31392
- result: {
31393
- thread,
31394
- model: transportModelId,
31395
- modelProvider: "codexhost",
31396
- cwd,
31397
- approvalPolicy: typeof params.approvalPolicy === "string" ? params.approvalPolicy : "never",
31398
- approvalsReviewer: "user",
31399
- sandbox: sandboxResult(params),
31400
- reasoningEffort: "medium",
31401
- serviceTier: "flex",
31402
- multiAgentMode: "explicitRequestOnly",
31403
- activePermissionProfile: null,
31404
- runtimeWorkspaceRoots: Array.isArray(params.runtimeWorkspaceRoots) ? params.runtimeWorkspaceRoots : [],
31405
- instructionSources: []
31406
- }
31407
- })
31408
- );
31409
- await this.#writer.json({
31410
- method: "thread/started",
31411
- emittedAtMs: Date.now(),
31412
- params: { thread }
31413
- });
31414
- } catch {
31415
- this.#externalRuntime.remove(record3.hostThreadId);
31416
- this.#routeObservationTracker.forgetThread(record3.hostThreadId);
31417
- await session.close().catch(() => void 0);
31418
- await this.#repository.removeProvisional(record3.hostThreadId).catch(() => void 0);
31419
- await this.#writer.json(rpcError(request, -32081, "External Thread could not be persisted"));
31420
- }
32480
+ });
31421
32481
  }
31422
32482
  #registerExternalThread(input) {
31423
32483
  return this.#externalRuntime.register(input);
@@ -31425,7 +32485,10 @@ var AppServerHost = class {
31425
32485
  #locateExternalThread(threadId2) {
31426
32486
  return this.#externalRuntime.locate(threadId2);
31427
32487
  }
31428
- #resolveExternalThread(threadId2) {
32488
+ async #resolveExternalThread(threadId2) {
32489
+ const location = await this.#locateExternalThread(threadId2);
32490
+ if (location.kind !== "external") return location;
32491
+ await this.#waitForPlugins();
31429
32492
  return this.#externalRuntime.resolve(threadId2);
31430
32493
  }
31431
32494
  async #writeResolutionError(request, resolution) {
@@ -31950,12 +33013,16 @@ var AppServerHost = class {
31950
33013
  try {
31951
33014
  for await (const output of thread.session.outputs) {
31952
33015
  try {
31953
- await this.#projectHarnessOutput(thread, output);
33016
+ await this.#externalRuntime.idleRelease.consumeOutput(
33017
+ thread,
33018
+ () => this.#projectHarnessOutput(thread, output)
33019
+ );
31954
33020
  } catch (error51) {
31955
33021
  await this.#recoverFailedProjection(thread, error51);
31956
33022
  }
31957
33023
  }
31958
33024
  } catch (error51) {
33025
+ this.#externalRuntime.idleRelease.outputFailed(thread);
31959
33026
  this.#diagnose(error51);
31960
33027
  } finally {
31961
33028
  this.#externalSteering.fault(
@@ -32195,6 +33262,7 @@ var AppServerHost = class {
32195
33262
  if (event.type === "turn.completed" && !ephemeralTurn) {
32196
33263
  const persistenceError = await this.#persistTerminalIdentity(thread, event);
32197
33264
  if (persistenceError) {
33265
+ this.#externalRuntime.idleRelease.outputFailed(thread);
32198
33266
  event = {
32199
33267
  type: "turn.completed",
32200
33268
  turnId: event.turnId,
@@ -32421,32 +33489,37 @@ var AppServerHost = class {
32421
33489
  }
32422
33490
  async #handleDesktopApprovalResponse(value2) {
32423
33491
  if (!isRecord14(value2) || !isHostApprovalRequestId(value2.id)) return false;
32424
- const pending = this.#pendingDesktopApprovals.get(value2.id);
33492
+ const requestId = value2.id;
33493
+ const pending = this.#pendingDesktopApprovals.get(requestId);
32425
33494
  if (!pending) return true;
32426
- this.#pendingDesktopApprovals.delete(value2.id);
32427
- let response;
32428
- try {
32429
- response = "error" in value2 ? pending.projection.denyResponse : pending.projection.parseResponse(value2.result);
32430
- } catch (error51) {
32431
- this.#diagnose(error51);
32432
- response = pending.projection.denyResponse;
32433
- }
32434
- const result = await pending.thread.session.execute({
32435
- type: "interaction.respond",
32436
- interactionId: pending.interaction.interactionId,
32437
- response
32438
- });
32439
- if (!result.ok && result.error.code !== "invalidState") {
32440
- this.#diagnose(`Approval response failed: ${result.error.message}`);
32441
- const cancelled = await pending.thread.session.execute({
32442
- type: "turn.cancel",
32443
- turnId: pending.interaction.turnId
33495
+ return this.#externalRuntime.idleRelease.runOperation(pending.thread.id, async () => {
33496
+ if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
33497
+ return true;
33498
+ this.#pendingDesktopApprovals.delete(requestId);
33499
+ let response;
33500
+ try {
33501
+ response = jsonRpcResponseFailed(value2) ? pending.projection.denyResponse : pending.projection.parseResponse(value2.result);
33502
+ } catch (error51) {
33503
+ this.#diagnose(error51);
33504
+ response = pending.projection.denyResponse;
33505
+ }
33506
+ const result = await pending.thread.session.execute({
33507
+ type: "interaction.respond",
33508
+ interactionId: pending.interaction.interactionId,
33509
+ response
32444
33510
  });
32445
- if (!cancelled.ok && cancelled.error.code !== "invalidState") {
32446
- this.#diagnose(`Approval fail-closed cancellation failed: ${cancelled.error.message}`);
33511
+ if (!result.ok && result.error.code !== "invalidState") {
33512
+ this.#diagnose(`Approval response failed: ${result.error.message}`);
33513
+ const cancelled = await pending.thread.session.execute({
33514
+ type: "turn.cancel",
33515
+ turnId: pending.interaction.turnId
33516
+ });
33517
+ if (!cancelled.ok && cancelled.error.code !== "invalidState") {
33518
+ this.#diagnose(`Approval fail-closed cancellation failed: ${cancelled.error.message}`);
33519
+ }
32447
33520
  }
32448
- }
32449
- return true;
33521
+ return true;
33522
+ });
32450
33523
  }
32451
33524
  async #denyApproval(thread, interaction) {
32452
33525
  const denyActions = interaction.actions.filter(({ effect }) => effect === "deny");
@@ -32525,7 +33598,7 @@ var AppServerHost = class {
32525
33598
  };
32526
33599
  if (timeoutMs !== null) {
32527
33600
  pending.timeout = setTimeout(() => {
32528
- void this.#cancelExpiredQuestion(requestId);
33601
+ void this.#cancelExpiredQuestion(requestId).catch((error51) => this.#diagnose(error51));
32529
33602
  }, timeoutMs);
32530
33603
  }
32531
33604
  this.#pendingDesktopQuestions.set(requestId, pending);
@@ -32543,39 +33616,48 @@ var AppServerHost = class {
32543
33616
  }
32544
33617
  async #handleDesktopQuestionResponse(value2) {
32545
33618
  if (!isRecord14(value2) || !isHostQuestionRequestId(value2.id)) return false;
32546
- const pending = this.#pendingDesktopQuestions.get(value2.id);
33619
+ const requestId = value2.id;
33620
+ const pending = this.#pendingDesktopQuestions.get(requestId);
32547
33621
  if (!pending) return true;
32548
- this.#pendingDesktopQuestions.delete(value2.id);
32549
- if (pending.timeout) clearTimeout(pending.timeout);
32550
- let response;
32551
- try {
32552
- response = "error" in value2 ? { type: "question", answers: {}, cancelled: true } : pending.projection.parseResponse(value2.result);
32553
- } catch (error51) {
32554
- this.#diagnose(error51);
32555
- response = { type: "question", answers: {}, cancelled: true };
32556
- }
32557
- const result = await pending.thread.session.execute({
32558
- type: "interaction.respond",
32559
- interactionId: pending.interaction.interactionId,
32560
- response
33622
+ return this.#externalRuntime.idleRelease.runOperation(pending.thread.id, async () => {
33623
+ if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
33624
+ return true;
33625
+ this.#pendingDesktopQuestions.delete(requestId);
33626
+ if (pending.timeout) clearTimeout(pending.timeout);
33627
+ let response;
33628
+ try {
33629
+ response = jsonRpcResponseFailed(value2) ? { type: "question", answers: {}, cancelled: true } : pending.projection.parseResponse(value2.result);
33630
+ } catch (error51) {
33631
+ this.#diagnose(error51);
33632
+ response = { type: "question", answers: {}, cancelled: true };
33633
+ }
33634
+ const result = await pending.thread.session.execute({
33635
+ type: "interaction.respond",
33636
+ interactionId: pending.interaction.interactionId,
33637
+ response
33638
+ });
33639
+ if (!result.ok && result.error.code !== "invalidState") {
33640
+ this.#diagnose(`Question response failed: ${result.error.message}`);
33641
+ }
33642
+ return true;
32561
33643
  });
32562
- if (!result.ok && result.error.code !== "invalidState") {
32563
- this.#diagnose(`Question response failed: ${result.error.message}`);
32564
- }
32565
- return true;
32566
33644
  }
32567
33645
  async #cancelExpiredQuestion(requestId) {
32568
33646
  const pending = this.#pendingDesktopQuestions.get(requestId);
32569
33647
  if (!pending) return;
32570
- await this.#resolveDesktopQuestion(pending.interaction.interactionId);
32571
- const result = await pending.thread.session.execute({
32572
- type: "interaction.respond",
32573
- interactionId: pending.interaction.interactionId,
32574
- response: { type: "question", answers: {}, cancelled: true }
33648
+ await this.#externalRuntime.idleRelease.runOperation(pending.thread.id, async () => {
33649
+ if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
33650
+ return;
33651
+ await this.#resolveDesktopQuestion(pending.interaction.interactionId);
33652
+ const result = await pending.thread.session.execute({
33653
+ type: "interaction.respond",
33654
+ interactionId: pending.interaction.interactionId,
33655
+ response: { type: "question", answers: {}, cancelled: true }
33656
+ });
33657
+ if (!result.ok && result.error.code !== "invalidState") {
33658
+ this.#diagnose(`Question expiry failed: ${result.error.message}`);
33659
+ }
32575
33660
  });
32576
- if (!result.ok && result.error.code !== "invalidState") {
32577
- this.#diagnose(`Question expiry failed: ${result.error.message}`);
32578
- }
32579
33661
  }
32580
33662
  #retireDesktopQuestion(interactionId) {
32581
33663
  for (const [requestId, pending] of this.#pendingDesktopQuestions) {
@@ -32643,8 +33725,9 @@ var AppServerHost = class {
32643
33725
  }
32644
33726
  await this.#writer.json(projection);
32645
33727
  }
32646
- #dispatchDesktopRequest(run) {
32647
- void run().catch((error51) => this.#diagnose(error51));
33728
+ #dispatchDesktopRequest(run, threadId2) {
33729
+ const task = threadId2 ? this.#externalRuntime.idleRelease.runOperation(threadId2, run) : run();
33730
+ void task.catch((error51) => this.#diagnose(error51));
32648
33731
  }
32649
33732
  #diagnose(error51) {
32650
33733
  this.#options.diagnosticOutput.write(`codexhost Host Runtime: ${errorMessage3(error51)}
@@ -32655,7 +33738,7 @@ var AppServerHost = class {
32655
33738
  // packages/host-runtime/src/native-account-host.ts
32656
33739
  import { mkdir as mkdir6, realpath as realpath3 } from "node:fs/promises";
32657
33740
  import { homedir } from "node:os";
32658
- import path15 from "node:path";
33741
+ import path16 from "node:path";
32659
33742
 
32660
33743
  // packages/host-runtime/src/codex-runtime/owned-official-backends.ts
32661
33744
  import { createHash as createHash7, randomBytes } from "node:crypto";
@@ -32665,7 +33748,7 @@ import { Writable as Writable2 } from "node:stream";
32665
33748
  import { createServer } from "node:http";
32666
33749
  import net from "node:net";
32667
33750
  import { chmod as chmod3, lstat as lstat6, mkdir as mkdir5, rm as rm5 } from "node:fs/promises";
32668
- import path13 from "node:path";
33751
+ import path14 from "node:path";
32669
33752
  import { PassThrough } from "node:stream";
32670
33753
 
32671
33754
  // node_modules/ws/wrapper.mjs
@@ -32683,7 +33766,7 @@ var wrapper_default = import_websocket.default;
32683
33766
  import { randomUUID as randomUUID9 } from "node:crypto";
32684
33767
  import { chmod as chmod2, lstat as lstat5, mkdir as mkdir4, open as open5, readFile as readFile6, readdir as readdir4, rename as rename3, rm as rm4 } from "node:fs/promises";
32685
33768
  import { uptime } from "node:os";
32686
- import path12 from "node:path";
33769
+ import path13 from "node:path";
32687
33770
  import { setTimeout as delay4 } from "node:timers/promises";
32688
33771
  var LOCK_RETRY_COUNT = 200;
32689
33772
  var LOCK_RETRY_DELAY_MS = 25;
@@ -32757,7 +33840,7 @@ async function readLockEntrySnapshot(filePath) {
32757
33840
  source,
32758
33841
  identity: { dev: metadata.dev, ino: metadata.ino },
32759
33842
  mtimeMs: metadata.mtimeMs,
32760
- record: record3 && path12.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
33843
+ record: record3 && path13.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
32761
33844
  };
32762
33845
  }
32763
33846
  function lockEntryIsAbandoned(snapshot) {
@@ -32778,7 +33861,7 @@ async function readLockEntryCatalog(lockDirectory) {
32778
33861
  let unsettled = false;
32779
33862
  for (const name of names) {
32780
33863
  if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
32781
- const snapshot = await readLockEntrySnapshot(path12.join(lockDirectory, name));
33864
+ const snapshot = await readLockEntrySnapshot(path13.join(lockDirectory, name));
32782
33865
  if (snapshot === null) continue;
32783
33866
  if (lockEntryIsAbandoned(snapshot)) {
32784
33867
  if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
@@ -32806,7 +33889,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
32806
33889
  await chmod2(lockDirectory, 448);
32807
33890
  }
32808
33891
  async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
32809
- const temporary = path12.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID9()}`);
33892
+ const temporary = path13.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID9()}`);
32810
33893
  const handle = await open5(temporary, "wx", 384);
32811
33894
  try {
32812
33895
  await handle.writeFile(`${JSON.stringify(record3)}
@@ -32882,7 +33965,7 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
32882
33965
  const lockDirectory = `${socketPath}.initializers`;
32883
33966
  await preparePrivateLockDirectory(lockDirectory);
32884
33967
  const ownerToken = randomUUID9();
32885
- const entryPath = path12.join(lockDirectory, lockEntryName(ownerToken));
33968
+ const entryPath = path13.join(lockDirectory, lockEntryName(ownerToken));
32886
33969
  const baseRecord = {
32887
33970
  version: 2,
32888
33971
  ownerToken,
@@ -33056,14 +34139,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
33056
34139
  throw new Error("Remote app-server listener must use a Unix URL");
33057
34140
  }
33058
34141
  const explicit = listenUrl.slice("unix://".length);
33059
- if (explicit.length > 0) return path13.posix.resolve(decodeURIComponent(explicit));
33060
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path13.posix.join(environment.HOME, ".codex") : void 0);
34142
+ if (explicit.length > 0) return path14.posix.resolve(decodeURIComponent(explicit));
34143
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path14.posix.join(environment.HOME, ".codex") : void 0);
33061
34144
  if (!codexHome)
33062
34145
  throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
33063
- return path13.posix.join(codexHome, "app-server-control", "app-server-control.sock");
34146
+ return path14.posix.join(codexHome, "app-server-control", "app-server-control.sock");
33064
34147
  }
33065
34148
  function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
33066
- if (!path13.posix.isAbsolute(socketPath)) {
34149
+ if (!path14.posix.isAbsolute(socketPath)) {
33067
34150
  throw new Error("Shared official app-server socket path must be absolute");
33068
34151
  }
33069
34152
  if (remoteUnixListenerUrl(arguments_2) === null) {
@@ -33174,7 +34257,7 @@ async function removeStaleSocket(socketPath) {
33174
34257
  await rm5(socketPath, { force: true });
33175
34258
  }
33176
34259
  async function prepareRemoteAppServerSocketDirectory(socketPath) {
33177
- const socketDirectory = path13.dirname(socketPath);
34260
+ const socketDirectory = path14.dirname(socketPath);
33178
34261
  const existing = await lstat6(socketDirectory).catch((error51) => {
33179
34262
  if (error51.code === "ENOENT") return null;
33180
34263
  throw error51;
@@ -33381,18 +34464,18 @@ function createRemoteAppServerWebSocketListener(input) {
33381
34464
  import { spawn as spawn3 } from "node:child_process";
33382
34465
  import { randomUUID as randomUUID10 } from "node:crypto";
33383
34466
  import { lstat as lstat7, rm as rm6 } from "node:fs/promises";
33384
- import path14 from "node:path";
34467
+ import path15 from "node:path";
33385
34468
  var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
33386
34469
  var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
33387
34470
  function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID10()) {
33388
- if (!path14.posix.isAbsolute(desktopControlSocketPath)) {
34471
+ if (!path15.posix.isAbsolute(desktopControlSocketPath)) {
33389
34472
  throw new Error("Desktop control socket path must be absolute");
33390
34473
  }
33391
34474
  if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
33392
34475
  throw new Error("Shared official app-server socket token is invalid");
33393
34476
  }
33394
34477
  const compactToken = token.replaceAll("-", "").slice(0, 15);
33395
- return path14.posix.join(path14.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
34478
+ return path15.posix.join(path15.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
33396
34479
  }
33397
34480
  function errorMessage4(error51) {
33398
34481
  return error51 instanceof Error ? error51.message : String(error51);
@@ -33875,19 +34958,19 @@ function createOwnedUnixBackend(input) {
33875
34958
 
33876
34959
  // packages/host-runtime/src/native-account-host.ts
33877
34960
  async function canonicalCodexHome(home) {
33878
- const absolute = path15.resolve(home);
34961
+ const absolute = path16.resolve(home);
33879
34962
  try {
33880
34963
  return await realpath3(absolute);
33881
34964
  } catch (error51) {
33882
34965
  if (!(error51 instanceof Error && "code" in error51 && error51.code === "ENOENT")) throw error51;
33883
- const parent = path15.dirname(absolute);
34966
+ const parent = path16.dirname(absolute);
33884
34967
  if (parent === absolute) throw error51;
33885
- return path15.join(await canonicalCodexHome(parent), path15.basename(absolute));
34968
+ return path16.join(await canonicalCodexHome(parent), path16.basename(absolute));
33886
34969
  }
33887
34970
  }
33888
34971
  async function prepareLocalCodex(input) {
33889
34972
  const home = await canonicalCodexHome(
33890
- input.environment.CODEX_HOME ?? path15.join(homedir(), ".codex")
34973
+ input.environment.CODEX_HOME ?? path16.join(homedir(), ".codex")
33891
34974
  );
33892
34975
  await mkdir6(home, { recursive: true });
33893
34976
  const scope = new OfficialRuntimeScope({
@@ -34054,17 +35137,17 @@ var DelegationControlRegistry = class {
34054
35137
 
34055
35138
  // packages/host-runtime/src/installed-harness-plugins.ts
34056
35139
  import os3 from "node:os";
34057
- import path17 from "node:path";
35140
+ import path18 from "node:path";
34058
35141
  import { fileURLToPath } from "node:url";
34059
35142
 
34060
35143
  // packages/host-runtime/src/launcher-url-opener.ts
34061
35144
  import { spawn as spawn4 } from "node:child_process";
34062
- import path16 from "node:path";
35145
+ import path17 from "node:path";
34063
35146
  var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
34064
35147
  var OPEN_TIMEOUT_MS = 1e4;
34065
35148
  function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn4(command, arguments_2, options2)) {
34066
35149
  const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
34067
- if (!launcher || !path16.isAbsolute(launcher)) return void 0;
35150
+ if (!launcher || !path17.isAbsolute(launcher)) return void 0;
34068
35151
  const launcherEnvironment = Object.fromEntries(
34069
35152
  Object.entries(environment).filter(([name]) => {
34070
35153
  const normalized = name.toUpperCase();
@@ -34122,9 +35205,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
34122
35205
  const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
34123
35206
  return {
34124
35207
  pluginRoots: [
34125
- path17.join(path17.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
34126
- environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path17.join(
34127
- environment.CODEXHOST_DATA_DIR ? path17.resolve(environment.CODEXHOST_DATA_DIR) : path17.join(os3.homedir(), ".codexhost"),
35208
+ path18.join(path18.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
35209
+ environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path18.join(
35210
+ environment.CODEXHOST_DATA_DIR ? path18.resolve(environment.CODEXHOST_DATA_DIR) : path18.join(os3.homedir(), ".codexhost"),
34128
35211
  "plugins"
34129
35212
  )
34130
35213
  ],
@@ -34252,9 +35335,9 @@ async function startDelegationControlServer(input) {
34252
35335
  import { createHash as createHash8, randomUUID as randomUUID11 } from "node:crypto";
34253
35336
  import { mkdir as mkdir7, open as open6, readFile as readFile7, rename as rename4, rm as rm7, stat as stat3 } from "node:fs/promises";
34254
35337
  import os4 from "node:os";
34255
- import path18 from "node:path";
35338
+ import path19 from "node:path";
34256
35339
  var SKILL_VERSION = 7;
34257
- var SKILL_RELATIVE_PATH = path18.join("skills", "codexhost-delegation", "SKILL.md");
35340
+ var SKILL_RELATIVE_PATH = path19.join("skills", "codexhost-delegation", "SKILL.md");
34258
35341
  var PREVIOUS_MANAGED_DIGESTS = [
34259
35342
  "9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
34260
35343
  "2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
@@ -34327,8 +35410,8 @@ async function readOptional(filePath) {
34327
35410
  }
34328
35411
  }
34329
35412
  async function atomicWrite(filePath, content) {
34330
- await mkdir7(path18.dirname(filePath), { recursive: true, mode: 448 });
34331
- const temporaryPath = path18.join(path18.dirname(filePath), `.SKILL.md.${randomUUID11()}.tmp`);
35413
+ await mkdir7(path19.dirname(filePath), { recursive: true, mode: 448 });
35414
+ const temporaryPath = path19.join(path19.dirname(filePath), `.SKILL.md.${randomUUID11()}.tmp`);
34332
35415
  const handle = await open6(temporaryPath, "wx", 384);
34333
35416
  try {
34334
35417
  await handle.writeFile(content, "utf8");
@@ -34345,8 +35428,8 @@ async function atomicWrite(filePath, content) {
34345
35428
  async function installDelegationSkills(input = {}) {
34346
35429
  const home = input.homeDirectory ?? os4.homedir();
34347
35430
  const destinations = [
34348
- path18.join(home, ".agents", SKILL_RELATIVE_PATH),
34349
- path18.join(home, ".claude", SKILL_RELATIVE_PATH)
35431
+ path19.join(home, ".agents", SKILL_RELATIVE_PATH),
35432
+ path19.join(home, ".claude", SKILL_RELATIVE_PATH)
34350
35433
  ];
34351
35434
  const knownDigests = /* @__PURE__ */ new Set([
34352
35435
  CURRENT_DIGEST,
@@ -34413,7 +35496,7 @@ async function installDelegationSkills(input = {}) {
34413
35496
  // packages/host-runtime/src/remote-control-app-server.ts
34414
35497
  import { randomUUID as randomUUID12 } from "node:crypto";
34415
35498
  import { mkdir as mkdir8, open as open7, rename as rename5, rm as rm8 } from "node:fs/promises";
34416
- import path19 from "node:path";
35499
+ import path20 from "node:path";
34417
35500
  var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
34418
35501
  var REMOTE_CONTROL_BRIDGE_NODE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_NODE_PATH";
34419
35502
  var REMOTE_CONTROL_BRIDGE_RUNTIME_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_RUNTIME_PATH";
@@ -34424,8 +35507,8 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
34424
35507
  function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
34425
35508
  const value2 = environment[name] ?? fallback;
34426
35509
  if (!value2) return null;
34427
- if (path19.isAbsolute(value2)) return path19.normalize(value2);
34428
- return platform === "win32" && path19.win32.isAbsolute(value2) ? path19.win32.normalize(value2) : null;
35510
+ if (path20.isAbsolute(value2)) return path20.normalize(value2);
35511
+ return platform === "win32" && path20.win32.isAbsolute(value2) ? path20.win32.normalize(value2) : null;
34429
35512
  }
34430
35513
  function nodeCompatibleWindowsPath(value2) {
34431
35514
  if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
@@ -34439,13 +35522,13 @@ function remoteControlBridgePipePath(processId = process.pid, instanceId = rando
34439
35522
  }
34440
35523
  function remoteControlBridgeDescriptorPath(environment) {
34441
35524
  const root = environment.LOCALAPPDATA;
34442
- if (!root || !path19.isAbsolute(root)) return null;
34443
- return path19.join(path19.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
35525
+ if (!root || !path20.isAbsolute(root)) return null;
35526
+ return path20.join(path20.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
34444
35527
  }
34445
35528
  async function publishRemoteControlAppServerDescriptor(plan) {
34446
- const directory = path19.dirname(plan.descriptorPath);
35529
+ const directory = path20.dirname(plan.descriptorPath);
34447
35530
  await mkdir8(directory, { recursive: true, mode: 448 });
34448
- const temporaryPath = path19.join(
35531
+ const temporaryPath = path20.join(
34449
35532
  directory,
34450
35533
  `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID12()}.tmp`
34451
35534
  );
@@ -34746,9 +35829,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
34746
35829
  if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
34747
35830
  const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
34748
35831
  if (!npmPackageRoot || !hostRuntimePath) return true;
34749
- if (!path20.isAbsolute(npmPackageRoot) || !path20.isAbsolute(hostRuntimePath)) return false;
34750
- const runtimePackageRoot = path20.dirname(path20.dirname(path20.normalize(hostRuntimePath)));
34751
- return path20.relative(path20.normalize(npmPackageRoot), runtimePackageRoot) === "";
35832
+ if (!path21.isAbsolute(npmPackageRoot) || !path21.isAbsolute(hostRuntimePath)) return false;
35833
+ const runtimePackageRoot = path21.dirname(path21.dirname(path21.normalize(hostRuntimePath)));
35834
+ return path21.relative(path21.normalize(npmPackageRoot), runtimePackageRoot) === "";
34752
35835
  }
34753
35836
  function requiredRuntimeConfiguration(environment) {
34754
35837
  const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
@@ -34894,8 +35977,8 @@ async function runHostRuntime(input) {
34894
35977
  const socketPath = remoteAppServerSocketPath(delegationEnvironment, listenUrl);
34895
35978
  const officialPlan = createRemoteOfficialAppServerPlan(input.arguments, socketPath);
34896
35979
  const officialRuntimeScope = new OfficialRuntimeScope({
34897
- permanentHome: path20.resolve(
34898
- delegationEnvironment.CODEX_HOME ?? path20.join(homedir2(), ".codex")
35980
+ permanentHome: path21.resolve(
35981
+ delegationEnvironment.CODEX_HOME ?? path21.join(homedir2(), ".codex")
34899
35982
  ),
34900
35983
  diagnosticOutput: process.stderr,
34901
35984
  createBackend: () => createOwnedUnixBackend({
@@ -34991,7 +36074,7 @@ import {
34991
36074
  stat as stat4,
34992
36075
  writeFile as writeFile3
34993
36076
  } from "node:fs/promises";
34994
- import path21 from "node:path";
36077
+ import path22 from "node:path";
34995
36078
  var MANIFEST_FORMAT = 1;
34996
36079
  var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
34997
36080
  var PROFILE_START = "# >>> codexhost remote SSH >>>";
@@ -35002,25 +36085,25 @@ function resolvePaths(options2) {
35002
36085
  if (!configuredHome) {
35003
36086
  throw new Error("A non-root HOME is required for remote Host installation");
35004
36087
  }
35005
- const home = path21.resolve(configuredHome);
35006
- if (!home || home === path21.parse(home).root) {
36088
+ const home = path22.resolve(configuredHome);
36089
+ if (!home || home === path22.parse(home).root) {
35007
36090
  throw new Error("A non-root HOME is required for remote Host installation");
35008
36091
  }
35009
- const installRoot = path21.resolve(options2.installRoot ?? path21.join(home, ".codexhost", "remote"));
35010
- const profilePath = path21.resolve(
35011
- options2.profilePath ?? path21.join(
36092
+ const installRoot = path22.resolve(options2.installRoot ?? path22.join(home, ".codexhost", "remote"));
36093
+ const profilePath = path22.resolve(
36094
+ options2.profilePath ?? path22.join(
35012
36095
  home,
35013
- path21.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path21.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
36096
+ path22.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path22.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
35014
36097
  )
35015
36098
  );
35016
- const binDirectory = path21.join(installRoot, "bin");
36099
+ const binDirectory = path22.join(installRoot, "bin");
35017
36100
  return {
35018
36101
  home,
35019
36102
  installRoot,
35020
36103
  binDirectory,
35021
- wrapperPath: path21.join(binDirectory, "codex"),
35022
- manifestPath: path21.join(installRoot, "manifest.json"),
35023
- dataDirectory: path21.join(installRoot, "data"),
36104
+ wrapperPath: path22.join(binDirectory, "codex"),
36105
+ manifestPath: path22.join(installRoot, "manifest.json"),
36106
+ dataDirectory: path22.join(installRoot, "data"),
35024
36107
  profilePath
35025
36108
  };
35026
36109
  }
@@ -35039,7 +36122,7 @@ async function fileSha256(filePath) {
35039
36122
  return createHash9("sha256").update(await readFile8(filePath)).digest("hex");
35040
36123
  }
35041
36124
  async function executable(filePath, label) {
35042
- const absolute = path21.resolve(filePath);
36125
+ const absolute = path22.resolve(filePath);
35043
36126
  try {
35044
36127
  if (!(await stat4(absolute)).isFile()) throw new Error("not a regular file");
35045
36128
  await access(absolute, fsConstants.X_OK);
@@ -35049,7 +36132,7 @@ async function executable(filePath, label) {
35049
36132
  return absolute;
35050
36133
  }
35051
36134
  async function existingFile(filePath, label) {
35052
- const absolute = path21.resolve(filePath);
36135
+ const absolute = path22.resolve(filePath);
35053
36136
  try {
35054
36137
  const metadata = await stat4(absolute);
35055
36138
  if (!metadata.isFile()) throw new Error("not a regular file");
@@ -35059,9 +36142,9 @@ async function existingFile(filePath, label) {
35059
36142
  return absolute;
35060
36143
  }
35061
36144
  async function discoverExecutable(name, environment) {
35062
- for (const directory of (environment.PATH ?? "").split(path21.delimiter)) {
36145
+ for (const directory of (environment.PATH ?? "").split(path22.delimiter)) {
35063
36146
  if (!directory) continue;
35064
- const candidate = path21.resolve(directory, name);
36147
+ const candidate = path22.resolve(directory, name);
35065
36148
  try {
35066
36149
  await access(candidate, fsConstants.X_OK);
35067
36150
  return candidate;
@@ -35072,10 +36155,10 @@ async function discoverExecutable(name, environment) {
35072
36155
  return null;
35073
36156
  }
35074
36157
  async function writeAtomic(filePath, contents, mode) {
35075
- await mkdir9(path21.dirname(filePath), { recursive: true, mode: 448 });
35076
- const temporary = path21.join(
35077
- path21.dirname(filePath),
35078
- `.${path21.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
36158
+ await mkdir9(path22.dirname(filePath), { recursive: true, mode: 448 });
36159
+ const temporary = path22.join(
36160
+ path22.dirname(filePath),
36161
+ `.${path22.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
35079
36162
  );
35080
36163
  try {
35081
36164
  if (typeof contents === "string") {
@@ -35096,10 +36179,10 @@ async function writeAtomic(filePath, contents, mode) {
35096
36179
  }
35097
36180
  }
35098
36181
  async function writeAtomicExecutable(filePath, sourcePath) {
35099
- await mkdir9(path21.dirname(filePath), { recursive: true, mode: 448 });
35100
- const temporary = path21.join(
35101
- path21.dirname(filePath),
35102
- `.${path21.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
36182
+ await mkdir9(path22.dirname(filePath), { recursive: true, mode: 448 });
36183
+ const temporary = path22.join(
36184
+ path22.dirname(filePath),
36185
+ `.${path22.basename(filePath)}.${process.pid}.${randomUUID13()}.tmp`
35103
36186
  );
35104
36187
  try {
35105
36188
  await copyFile3(sourcePath, temporary);
@@ -35140,8 +36223,8 @@ function removeManagedProfileBlock(contents) {
35140
36223
  function installManagedProfileBlock(contents, manifest) {
35141
36224
  const base = removeManagedProfileBlock(contents);
35142
36225
  const environment = [
35143
- `export CODEX_INSTALL_DIR=${shellQuote(path21.dirname(manifest.wrapperPath))}`,
35144
- `export PATH=${shellQuote(path21.dirname(manifest.wrapperPath))}:${shellQuote(path21.dirname(manifest.nodePath))}:${shellQuote(path21.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
36226
+ `export CODEX_INSTALL_DIR=${shellQuote(path22.dirname(manifest.wrapperPath))}`,
36227
+ `export PATH=${shellQuote(path22.dirname(manifest.wrapperPath))}:${shellQuote(path22.dirname(manifest.nodePath))}:${shellQuote(path22.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
35145
36228
  `export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
35146
36229
  `export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
35147
36230
  `export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
@@ -35158,7 +36241,7 @@ function installManagedProfileBlock(contents, manifest) {
35158
36241
  PROFILE_END,
35159
36242
  ""
35160
36243
  ].join("\n");
35161
- if (path21.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
36244
+ if (path22.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
35162
36245
  const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
35163
36246
  return `${base}${separator}${block}`;
35164
36247
  }
@@ -35223,9 +36306,9 @@ async function readManifest(filePath) {
35223
36306
  ];
35224
36307
  const optionalPaths = ["claudeCommand", "profileBackupPath"];
35225
36308
  if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
35226
- (key) => typeof manifest[key] !== "string" || !path21.isAbsolute(manifest[key])
36309
+ (key) => typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key])
35227
36310
  ) || optionalPaths.some(
35228
- (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path21.isAbsolute(manifest[key]))
36311
+ (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key]))
35229
36312
  ) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
35230
36313
  throw new Error("Remote Host manifest has an unsupported format");
35231
36314
  }
@@ -35454,7 +36537,7 @@ async function uninstallRemoteHost(options2) {
35454
36537
  import { spawn as spawn5 } from "node:child_process";
35455
36538
  import { stat as stat5 } from "node:fs/promises";
35456
36539
  import net3 from "node:net";
35457
- import path22 from "node:path";
36540
+ import path23 from "node:path";
35458
36541
  import { Duplex } from "node:stream";
35459
36542
 
35460
36543
  // packages/host-runtime/src/app-server-websocket-options.ts
@@ -35481,9 +36564,9 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
35481
36564
  }
35482
36565
  var lifecycleDependencyOverrides = {};
35483
36566
  function socketPathFor(environment) {
35484
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path22.join(environment.HOME, ".codex") : void 0);
36567
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path23.join(environment.HOME, ".codex") : void 0);
35485
36568
  if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
35486
- return path22.join(codexHome, "app-server-control", "app-server-control.sock");
36569
+ return path23.join(codexHome, "app-server-control", "app-server-control.sock");
35487
36570
  }
35488
36571
  async function defaultSocketExists(socketPath) {
35489
36572
  const metadata = await stat5(socketPath).catch((error51) => {
@@ -35613,7 +36696,7 @@ function installedManifest(status) {
35613
36696
  function managedEnvironment(manifest, environment) {
35614
36697
  return {
35615
36698
  ...environment,
35616
- CODEX_INSTALL_DIR: path22.dirname(manifest.wrapperPath),
36699
+ CODEX_INSTALL_DIR: path23.dirname(manifest.wrapperPath),
35617
36700
  CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
35618
36701
  CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
35619
36702
  CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
@@ -35621,7 +36704,7 @@ function managedEnvironment(manifest, environment) {
35621
36704
  CODEXHOST_DEFAULT_AGENT: "codex",
35622
36705
  CODEXHOST_REMOTE_SSH_MANAGED: "1",
35623
36706
  ...manifest.claudeCommand ? { CODEXHOST_CLAUDE_COMMAND: manifest.claudeCommand } : {},
35624
- PATH: `${path22.dirname(manifest.wrapperPath)}${path22.delimiter}${path22.dirname(manifest.stockCodexPath)}${path22.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
36707
+ PATH: `${path23.dirname(manifest.wrapperPath)}${path23.delimiter}${path23.dirname(manifest.stockCodexPath)}${path23.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
35625
36708
  };
35626
36709
  }
35627
36710
  async function defaultRunTerminator(manifest, socketPath, role, environment) {
@@ -35963,25 +37046,25 @@ function consumeBrokerFrames(socket, onFrame, onError) {
35963
37046
 
35964
37047
  // packages/harness-broker/dist/paths.js
35965
37048
  import os5 from "node:os";
35966
- import path23 from "node:path";
37049
+ import path24 from "node:path";
35967
37050
  var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
35968
37051
  var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
35969
37052
  var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
35970
37053
  function defaultHarnessBrokerDirectory(environment = process.env) {
35971
37054
  const home = environment.HOME || os5.homedir();
35972
- return path23.join(home, ".codexhost", "harness-broker");
37055
+ return path24.join(home, ".codexhost", "harness-broker");
35973
37056
  }
35974
37057
  function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
35975
37058
  harnessPluginIdSchema.parse(harnessId);
35976
37059
  if (harnessId !== "claude-code")
35977
- return path23.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
35978
- return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path23.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
37060
+ return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
37061
+ return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
35979
37062
  }
35980
37063
  function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
35981
37064
  harnessPluginIdSchema.parse(harnessId);
35982
37065
  if (harnessId !== "claude-code")
35983
- return path23.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
35984
- return path23.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
37066
+ return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
37067
+ return path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
35985
37068
  }
35986
37069
 
35987
37070
  // packages/harness-broker/dist/validation.js
@@ -36218,7 +37301,7 @@ var harnessOutputSchema = external_exports.custom((value2) => {
36218
37301
  import { randomBytes as randomBytes3, randomUUID as randomUUID14 } from "node:crypto";
36219
37302
  import { chmod as chmod5, lstat as lstat9, mkdir as mkdir10, open as open8, readFile as readFile9, rename as rename7, rm as rm10 } from "node:fs/promises";
36220
37303
  import net4, {} from "node:net";
36221
- import path24 from "node:path";
37304
+ import path25 from "node:path";
36222
37305
  function harnessError(message, retryable = true) {
36223
37306
  return { code: "unavailable", message, retryable, stage: "harnessBroker" };
36224
37307
  }
@@ -36341,13 +37424,13 @@ async function prepareUnixSocketPath(socketPath) {
36341
37424
  }
36342
37425
  async function startHarnessBrokerServer(input) {
36343
37426
  harnessPluginIdSchema.parse(input.adapter.harnessId);
36344
- if (process.platform !== "win32" && path24.dirname(input.descriptorPath) !== path24.dirname(input.socketPath)) {
37427
+ if (process.platform !== "win32" && path25.dirname(input.descriptorPath) !== path25.dirname(input.socketPath)) {
36345
37428
  throw new Error("Harness broker descriptor and socket must share one private directory");
36346
37429
  }
36347
37430
  if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
36348
37431
  throw new Error("Harness broker Unix socket path is too long for macOS");
36349
37432
  }
36350
- await privateDirectory(path24.dirname(input.descriptorPath));
37433
+ await privateDirectory(path25.dirname(input.descriptorPath));
36351
37434
  await assertNoLiveDescriptor(input.descriptorPath);
36352
37435
  if (process.platform !== "win32")
36353
37436
  await prepareUnixSocketPath(input.socketPath);