@codexhost/cli-darwin-x64 0.9.1 → 0.10.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.
@@ -2278,7 +2278,7 @@ var require_websocket = __commonJS({
2278
2278
  var http = __require("http");
2279
2279
  var net5 = __require("net");
2280
2280
  var tls = __require("tls");
2281
- var { randomBytes: randomBytes4, createHash: createHash10 } = __require("crypto");
2281
+ var { randomBytes: randomBytes4, createHash: createHash11 } = __require("crypto");
2282
2282
  var { Duplex: Duplex2, Readable } = __require("stream");
2283
2283
  var { URL: URL2 } = __require("url");
2284
2284
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -2946,7 +2946,7 @@ var require_websocket = __commonJS({
2946
2946
  abortHandshake(websocket, socket, "Invalid Upgrade header");
2947
2947
  return;
2948
2948
  }
2949
- const digest2 = createHash10("sha1").update(key + GUID).digest("base64");
2949
+ const digest2 = createHash11("sha1").update(key + GUID).digest("base64");
2950
2950
  if (res.headers["sec-websocket-accept"] !== digest2) {
2951
2951
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2952
2952
  return;
@@ -3315,7 +3315,7 @@ var require_websocket_server = __commonJS({
3315
3315
  var EventEmitter = __require("events");
3316
3316
  var http = __require("http");
3317
3317
  var { Duplex: Duplex2 } = __require("stream");
3318
- var { createHash: createHash10 } = __require("crypto");
3318
+ var { createHash: createHash11 } = __require("crypto");
3319
3319
  var extension2 = require_extension();
3320
3320
  var PerMessageDeflate2 = require_permessage_deflate();
3321
3321
  var subprotocol2 = require_subprotocol();
@@ -3622,7 +3622,7 @@ var require_websocket_server = __commonJS({
3622
3622
  );
3623
3623
  }
3624
3624
  if (this._state > RUNNING) return abortHandshake(socket, 503);
3625
- const digest2 = createHash10("sha1").update(key + GUID).digest("base64");
3625
+ const digest2 = createHash11("sha1").update(key + GUID).digest("base64");
3626
3626
  const headers = [
3627
3627
  "HTTP/1.1 101 Switching Protocols",
3628
3628
  "Upgrade: websocket",
@@ -4283,7 +4283,7 @@ async function runDelegationCli(input) {
4283
4283
 
4284
4284
  // packages/host-runtime/src/run-host-runtime.ts
4285
4285
  import { randomBytes as randomBytes2 } from "node:crypto";
4286
- import path21 from "node:path";
4286
+ import path23 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, path26) {
5982
- if (!path26)
5981
+ function getElementAtPath(obj, path28) {
5982
+ if (!path28)
5983
5983
  return obj;
5984
- return path26.reduce((acc, key) => acc?.[key], obj);
5984
+ return path28.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(path26, issues) {
6393
+ function prefixIssues(path28, issues) {
6394
6394
  return issues.map((iss) => {
6395
6395
  var _a3;
6396
6396
  (_a3 = iss).path ?? (_a3.path = []);
6397
- iss.path.unshift(path26);
6397
+ iss.path.unshift(path28);
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, path26 = []) => {
6544
+ const processError = (error52, path28 = []) => {
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 }, [...path26, ...issue2.path]));
6547
+ issue2.errors.map((issues) => processError({ issues }, [...path28, ...issue2.path]));
6548
6548
  } else if (issue2.code === "invalid_key") {
6549
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6549
+ processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
6550
6550
  } else if (issue2.code === "invalid_element") {
6551
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6551
+ processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
6552
6552
  } else {
6553
- const fullpath = [...path26, ...issue2.path];
6553
+ const fullpath = [...path28, ...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, path26 = []) => {
6580
+ const processError = (error52, path28 = []) => {
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 }, [...path26, ...issue2.path]));
6584
+ issue2.errors.map((issues) => processError({ issues }, [...path28, ...issue2.path]));
6585
6585
  } else if (issue2.code === "invalid_key") {
6586
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6586
+ processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
6587
6587
  } else if (issue2.code === "invalid_element") {
6588
- processError({ issues: issue2.issues }, [...path26, ...issue2.path]);
6588
+ processError({ issues: issue2.issues }, [...path28, ...issue2.path]);
6589
6589
  } else {
6590
- const fullpath = [...path26, ...issue2.path];
6590
+ const fullpath = [...path28, ...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 path26 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6623
- for (const seg of path26) {
6622
+ const path28 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
6623
+ for (const seg of path28) {
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 path26 = ref.slice(1).split("/").filter(Boolean);
19316
- if (path26.length === 0) {
19315
+ const path28 = ref.slice(1).split("/").filter(Boolean);
19316
+ if (path28.length === 0) {
19317
19317
  return ctx.rootSchema;
19318
19318
  }
19319
19319
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
19320
- if (path26[0] === defsKey) {
19321
- const key = path26[1];
19320
+ if (path28[0] === defsKey) {
19321
+ const key = path28[1];
19322
19322
  if (!key || !ctx.defs[key]) {
19323
19323
  throw new Error(`Reference not found: ${ref}`);
19324
19324
  }
@@ -19726,6 +19726,62 @@ function date4(params) {
19726
19726
  // node_modules/zod/v4/classic/external.js
19727
19727
  config(en_default());
19728
19728
 
19729
+ // packages/shared-contracts/dist/credential-imports.js
19730
+ var credentialSourceSchema = external_exports.object({
19731
+ id: external_exports.string().min(1).max(256),
19732
+ harnessId: external_exports.string().min(1),
19733
+ label: external_exports.string().min(1).max(512),
19734
+ provider: external_exports.enum(["openai-codex", "xai"])
19735
+ }).strict();
19736
+ var credentialImportNameSchema = external_exports.string().regex(/^[a-z][a-z0-9-]{0,47}$/);
19737
+ var credentialImportRecordSchema = external_exports.object({
19738
+ name: credentialImportNameSchema,
19739
+ source: credentialSourceSchema,
19740
+ importedAt: external_exports.string()
19741
+ }).strict();
19742
+ var credentialImportsRequestSchema = external_exports.discriminatedUnion("action", [
19743
+ external_exports.object({ action: external_exports.literal("list") }).strict(),
19744
+ external_exports.object({
19745
+ action: external_exports.literal("import"),
19746
+ sourceId: external_exports.string().min(1).max(256),
19747
+ name: credentialImportNameSchema,
19748
+ confirmed: external_exports.literal(true)
19749
+ }).strict(),
19750
+ external_exports.object({
19751
+ action: external_exports.literal("reimport"),
19752
+ sourceId: external_exports.string().min(1).max(256),
19753
+ name: credentialImportNameSchema,
19754
+ confirmed: external_exports.literal(true)
19755
+ }).strict(),
19756
+ external_exports.object({
19757
+ action: external_exports.literal("remove"),
19758
+ name: credentialImportNameSchema,
19759
+ confirmed: external_exports.literal(true)
19760
+ }).strict()
19761
+ ]);
19762
+ var credentialOtherLoginSchema = external_exports.object({
19763
+ provider: external_exports.string().min(1).max(128),
19764
+ type: external_exports.enum(["oauth", "api_key", "unknown"]),
19765
+ /** Best-effort account label (e.g. the email in a Codex token), derived locally when present. */
19766
+ label: external_exports.string().min(1).max(512).optional(),
19767
+ /** Recognized credential vendor, derived from the OAuth token issuer. Absent when unknown. */
19768
+ vendor: external_exports.enum(["openai-codex", "xai"]).optional()
19769
+ }).strict();
19770
+ var credentialImportsResultSchema = external_exports.object({
19771
+ sources: external_exports.array(credentialSourceSchema),
19772
+ targets: external_exports.array(external_exports.object({
19773
+ harnessId: external_exports.string(),
19774
+ providers: external_exports.array(external_exports.enum(["openai-codex", "xai"])),
19775
+ imports: external_exports.array(credentialImportRecordSchema),
19776
+ others: external_exports.array(credentialOtherLoginSchema).default([])
19777
+ }).strict())
19778
+ }).strict();
19779
+ var credentialImportsParamsSchema = external_exports.object({
19780
+ targetHarnessId: external_exports.string().min(1).max(128).optional(),
19781
+ request: credentialImportsRequestSchema
19782
+ }).strict();
19783
+ var CREDENTIAL_IMPORTS_METHOD = "codexhost/harness/credential-imports";
19784
+
19729
19785
  // packages/shared-contracts/dist/version.js
19730
19786
  var WORKSPACE_CONTRACT_VERSION = 1;
19731
19787
 
@@ -20466,10 +20522,21 @@ var harnessCommandDescriptorSchema = external_exports.object({
20466
20522
  invocation: commandInvocationSchema,
20467
20523
  label: commandLabelSchema,
20468
20524
  description: commandDescriptionSchema.optional(),
20469
- argumentMode: external_exports.enum(["none", "text"])
20525
+ argumentMode: external_exports.enum(["none", "text"]),
20526
+ /**
20527
+ * Native distinction reported by the Harness. Omitted when the Harness does
20528
+ * not tell skills and commands apart; consumers treat that as "command".
20529
+ */
20530
+ kind: external_exports.enum(["command", "skill"]).optional()
20470
20531
  }).strict();
20471
20532
  var harnessCommandCatalogSchema = external_exports.object({
20472
- commands: external_exports.array(harnessCommandDescriptorSchema)
20533
+ commands: external_exports.array(harnessCommandDescriptorSchema),
20534
+ /**
20535
+ * `live` when the catalog includes what a native Session reports for its
20536
+ * workspace (custom commands, skills); `static` for Adapter built-ins only.
20537
+ * Omitted by Adapters; set by the Host on inspection results.
20538
+ */
20539
+ source: external_exports.enum(["live", "static"]).optional()
20473
20540
  }).strict().superRefine((catalog, context) => {
20474
20541
  const ids = /* @__PURE__ */ new Set();
20475
20542
  for (const [index, command] of catalog.commands.entries()) {
@@ -20483,7 +20550,11 @@ var harnessCommandCatalogSchema = external_exports.object({
20483
20550
  ids.add(command.id);
20484
20551
  }
20485
20552
  });
20486
- var harnessCommandsInspectParamsSchema = external_exports.object({ harnessId: harnessIdSchema }).strict();
20553
+ var harnessCommandsInspectParamsSchema = external_exports.object({
20554
+ harnessId: harnessIdSchema,
20555
+ /** Workspace of a draft without a Thread, for its live catalog when known. */
20556
+ cwd: external_exports.string().min(1).optional()
20557
+ }).strict();
20487
20558
  var threadCommandsInspectParamsSchema = external_exports.object({
20488
20559
  threadId: hostThreadIdSchema
20489
20560
  }).strict();
@@ -20627,9 +20698,360 @@ var updateStatusResultSchema = external_exports.strictObject({
20627
20698
  status: updateStatusSchema.nullable()
20628
20699
  });
20629
20700
 
20701
+ // packages/shared-contracts/dist/delegation-mention.js
20702
+ var DELEGATION_MENTION_PATH_PREFIX = "subagent://codexhost.";
20703
+ var MENTION_LINK_PATTERN = /\[@([^\]\n]+)\]\(<?subagent:\/\/codexhost\.([a-z0-9][a-z0-9-]*)>?\)/gu;
20704
+ function stripDelegationMentions(text) {
20705
+ const mentions = [];
20706
+ const seen = /* @__PURE__ */ new Set();
20707
+ const rewritten = text.replace(MENTION_LINK_PATTERN, (_match, label, harnessId) => {
20708
+ const trimmed = label.trim();
20709
+ if (!seen.has(harnessId)) {
20710
+ seen.add(harnessId);
20711
+ mentions.push({ harnessId, label: trimmed });
20712
+ }
20713
+ return `@${trimmed}`;
20714
+ });
20715
+ return { text: rewritten, mentions };
20716
+ }
20717
+ var COMMAND_LINK_PATTERN = /([ \t]*)\[@([^\]\n]+)\]\(<?subagent:\/\/codexhost-command\.([^)\s>]+)>?\)([ \t]*)/gu;
20718
+ function restoreHarnessCommandMentions(text) {
20719
+ let invocation = null;
20720
+ const rest = text.replace(COMMAND_LINK_PATTERN, (match, before, _label, encoded, after) => {
20721
+ if (invocation === null) {
20722
+ try {
20723
+ invocation = `/${decodeURIComponent(encoded)}`;
20724
+ } catch {
20725
+ return match;
20726
+ }
20727
+ }
20728
+ return before || after ? " " : "";
20729
+ });
20730
+ if (invocation === null)
20731
+ return text;
20732
+ const argumentsText = rest.trim();
20733
+ return argumentsText ? `${invocation} ${argumentsText}` : invocation;
20734
+ }
20735
+
20630
20736
  // packages/shared-contracts/dist/index.js
20631
20737
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
20632
20738
 
20739
+ // packages/host-runtime/src/account/codex-credential-export.ts
20740
+ import { createHash as createHash2 } from "node:crypto";
20741
+ import { readFile as readFile4 } from "node:fs/promises";
20742
+ import os from "node:os";
20743
+ import path5 from "node:path";
20744
+ async function readCodexCredential(environment) {
20745
+ try {
20746
+ const home = environment.CODEX_HOME ?? path5.join(environment.HOME ?? os.homedir(), ".codex");
20747
+ const auth = JSON.parse(await readFile4(path5.join(home, "auth.json"), "utf8"));
20748
+ if (auth.OPENAI_API_KEY || auth.auth_mode && auth.auth_mode !== "chatgpt") return [];
20749
+ const t = auth.tokens;
20750
+ if (!t || ![t.access_token, t.refresh_token, t.account_id].every(
20751
+ (v) => typeof v === "string" && v.length
20752
+ ))
20753
+ return [];
20754
+ const claims = JSON.parse(Buffer.from(t.access_token.split(".")[1], "base64url").toString());
20755
+ if (claims.client_id !== "app_EMoamEEZ73f0CkXaXp7hrann" || !Number.isFinite(claims.exp * 1e3))
20756
+ return [];
20757
+ const account = claims["https://api.openai.com/auth"]?.chatgpt_account_id;
20758
+ if (account !== t.account_id) return [];
20759
+ let email3;
20760
+ try {
20761
+ email3 = JSON.parse(Buffer.from(t.id_token.split(".")[1], "base64url").toString()).email;
20762
+ } catch {
20763
+ }
20764
+ const identity = `${t.account_id}:${claims.sub ?? ""}`;
20765
+ return [
20766
+ {
20767
+ source: {
20768
+ id: `codex:${createHash2("sha256").update(identity).digest("hex")}`,
20769
+ harnessId: "codex",
20770
+ provider: "openai-codex",
20771
+ label: typeof email3 === "string" && email3 ? email3 : "Codex"
20772
+ },
20773
+ oauth: {
20774
+ access: t.access_token,
20775
+ refresh: t.refresh_token,
20776
+ expires: claims.exp * 1e3,
20777
+ accountId: t.account_id
20778
+ }
20779
+ }
20780
+ ];
20781
+ } catch {
20782
+ return [];
20783
+ }
20784
+ }
20785
+
20786
+ // packages/host-runtime/src/credential-imports.ts
20787
+ async function handleCredentialImports(params, adapters, environment) {
20788
+ const input = credentialImportsParamsSchema.parse(params);
20789
+ const installed = [...adapters];
20790
+ const sources = await readCodexCredential(environment);
20791
+ for (const adapter of installed) {
20792
+ if (adapter.credentialExport) sources.push(...await adapter.credentialExport.read());
20793
+ }
20794
+ const request = input.request;
20795
+ if (request.action !== "list") {
20796
+ const target = installed.find((a) => a.harnessId === input.targetHarnessId)?.credentialImports;
20797
+ if (!target) throw new Error("Target Harness does not support credential imports");
20798
+ if (request.action === "remove") await target.remove(request.name);
20799
+ else {
20800
+ const source = sources.find((s) => s.source.id === request.sourceId);
20801
+ if (!source || !target.providers.includes(source.source.provider))
20802
+ throw new Error("Source login changed or is unavailable; refresh and confirm again");
20803
+ if (request.action === "reimport") await target.reimport(request.name, source);
20804
+ else await target.add(request.name, source);
20805
+ }
20806
+ }
20807
+ const targets = [];
20808
+ for (const adapter of installed) {
20809
+ if (!adapter.credentialImports) continue;
20810
+ try {
20811
+ targets.push({
20812
+ harnessId: adapter.harnessId,
20813
+ providers: [...adapter.credentialImports.providers],
20814
+ imports: await adapter.credentialImports.list(),
20815
+ others: await listOthers(adapter)
20816
+ });
20817
+ } catch {
20818
+ }
20819
+ }
20820
+ return credentialImportsResultSchema.parse({ sources: sources.map((s) => s.source), targets });
20821
+ }
20822
+ async function listOthers(adapter) {
20823
+ try {
20824
+ return await adapter.credentialImports?.listOthers?.() ?? [];
20825
+ } catch {
20826
+ return [];
20827
+ }
20828
+ }
20829
+
20830
+ // packages/host-runtime/src/delegation-skill.ts
20831
+ import { createHash as createHash3, randomUUID as randomUUID2 } from "node:crypto";
20832
+ import { mkdir as mkdir3, open as open3, readFile as readFile5, rename as rename2, rm as rm3, stat } from "node:fs/promises";
20833
+ import os2 from "node:os";
20834
+ import path6 from "node:path";
20835
+ var SKILL_VERSION = 7;
20836
+ var DELEGATION_SKILL_NAME = "codexhost-delegation";
20837
+ var SKILL_RELATIVE_PATH = path6.join("skills", DELEGATION_SKILL_NAME, "SKILL.md");
20838
+ var PREVIOUS_MANAGED_DIGESTS = [
20839
+ "9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
20840
+ "2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
20841
+ "aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
20842
+ "ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
20843
+ "d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
20844
+ "15eb63519ff867e1536c97188a0c43738d7a49d38d4d6adeb7a1036726e7246d"
20845
+ ];
20846
+ var CODEXHOST_DELEGATION_SKILL = `---
20847
+ name: codexhost-delegation
20848
+ version: ${SKILL_VERSION}
20849
+ description: >
20850
+ Delegate tasks to other coding agents, or read and follow up on existing
20851
+ external agent sessions. Use when the user asks another agent (including
20852
+ @agent) to independently perform a task, or asks to view a specified external
20853
+ session's content, progress, or results, send follow-up messages, wait, or
20854
+ cancel a task. Not for recapping the current conversation, discussing or
20855
+ configuring agents, or role-playing.
20856
+ ---
20857
+
20858
+ # Execute the task
20859
+
20860
+ Before acting, run:
20861
+
20862
+ \`codexhost delegate --help\`
20863
+
20864
+ Use CLI help as the authoritative source for commands and behavior. Consult
20865
+ command-specific help for options and the Harness listing command when the
20866
+ target is unknown. Prefer compact output when supported, and use its task links
20867
+ directly for subsequent commands.
20868
+
20869
+ Use the Harness native defaults. Inspect the target when a Model or Thinking
20870
+ selection is needed or the default is unavailable.
20871
+
20872
+ For a new delegation, create an independent child session and submit the
20873
+ requested task. For an existing external session, resolve the target from the
20874
+ user-provided session link, identifier, or context and operate on that Thread
20875
+ directly; it need not have been created by the current assistant. If the target
20876
+ is ambiguous, ask the user to identify it. Keep requests to view or summarize a
20877
+ session read-only.
20878
+
20879
+ For a new or existing task, choose the appropriate next action based on the
20880
+ user’s request and the task:
20881
+
20882
+ - send a follow-up message to the same Thread;
20883
+ - cancel its current Turn;
20884
+ - read its current state immediately;
20885
+ - wait for a bounded period;
20886
+ - check it again later;
20887
+ - leave it running in the background.
20888
+
20889
+ Report the result returned by read or a completed wait, together with the target
20890
+ agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
20891
+ `;
20892
+ var CURRENT_DIGEST = createHash3("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
20893
+ function digest(value2) {
20894
+ return createHash3("sha256").update(value2).digest("hex");
20895
+ }
20896
+ function managedVersion(value2) {
20897
+ const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
20898
+ return match ? Number(match[1]) : null;
20899
+ }
20900
+ async function readOptional(filePath) {
20901
+ try {
20902
+ return await readFile5(filePath, "utf8");
20903
+ } catch (error51) {
20904
+ if (error51.code === "ENOENT") return null;
20905
+ throw error51;
20906
+ }
20907
+ }
20908
+ async function atomicWrite(filePath, content) {
20909
+ await mkdir3(path6.dirname(filePath), { recursive: true, mode: 448 });
20910
+ const temporaryPath = path6.join(path6.dirname(filePath), `.SKILL.md.${randomUUID2()}.tmp`);
20911
+ const handle = await open3(temporaryPath, "wx", 384);
20912
+ try {
20913
+ await handle.writeFile(content, "utf8");
20914
+ await handle.sync();
20915
+ } finally {
20916
+ await handle.close();
20917
+ }
20918
+ try {
20919
+ await rename2(temporaryPath, filePath);
20920
+ } finally {
20921
+ await rm3(temporaryPath, { force: true });
20922
+ }
20923
+ }
20924
+ async function installDelegationSkills(input = {}) {
20925
+ const home = input.homeDirectory ?? os2.homedir();
20926
+ const destinations = [
20927
+ path6.join(home, ".agents", SKILL_RELATIVE_PATH),
20928
+ path6.join(home, ".claude", SKILL_RELATIVE_PATH)
20929
+ ];
20930
+ const knownDigests = /* @__PURE__ */ new Set([
20931
+ CURRENT_DIGEST,
20932
+ ...PREVIOUS_MANAGED_DIGESTS,
20933
+ ...input.previousManagedDigests ?? []
20934
+ ]);
20935
+ const results = [];
20936
+ for (const destination of destinations) {
20937
+ const current = await readOptional(destination);
20938
+ if (current === CODEXHOST_DELEGATION_SKILL) {
20939
+ results.push({
20940
+ path: destination,
20941
+ status: "current",
20942
+ version: SKILL_VERSION,
20943
+ digest: CURRENT_DIGEST
20944
+ });
20945
+ continue;
20946
+ }
20947
+ if (current !== null) {
20948
+ const currentDigest = digest(current);
20949
+ const version2 = managedVersion(current);
20950
+ if (!knownDigests.has(currentDigest)) {
20951
+ results.push({ path: destination, status: "conflict", version: version2, digest: currentDigest });
20952
+ continue;
20953
+ }
20954
+ await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
20955
+ results.push({
20956
+ path: destination,
20957
+ status: "updated",
20958
+ version: SKILL_VERSION,
20959
+ digest: CURRENT_DIGEST
20960
+ });
20961
+ continue;
20962
+ }
20963
+ await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
20964
+ results.push({
20965
+ path: destination,
20966
+ status: "installed",
20967
+ version: SKILL_VERSION,
20968
+ digest: CURRENT_DIGEST
20969
+ });
20970
+ }
20971
+ for (const result of results) {
20972
+ if (result.status === "conflict") continue;
20973
+ const source = await readFile5(result.path, "utf8");
20974
+ const metadata = await stat(result.path);
20975
+ if (!metadata.isFile() || source !== CODEXHOST_DELEGATION_SKILL) {
20976
+ throw new Error(`Delegation Skill verification failed: ${result.path}`);
20977
+ }
20978
+ }
20979
+ const managed = results.filter((result) => result.status !== "conflict");
20980
+ if (managed.some((result) => result.digest !== CURRENT_DIGEST)) {
20981
+ throw new Error("Delegation Skill copies are inconsistent");
20982
+ }
20983
+ if (results.every((result) => result.status !== "conflict")) {
20984
+ const copies = await Promise.all(results.map((result) => readFile5(result.path, "utf8")));
20985
+ if (copies.some((copy) => copy !== copies[0])) {
20986
+ throw new Error("Delegation Skill copies are inconsistent");
20987
+ }
20988
+ }
20989
+ return results;
20990
+ }
20991
+ async function managedDelegationSkillReference(input = {}) {
20992
+ const filePath = path6.join(input.homeDirectory ?? os2.homedir(), ".agents", SKILL_RELATIVE_PATH);
20993
+ try {
20994
+ return await readOptional(filePath) === CODEXHOST_DELEGATION_SKILL ? { name: DELEGATION_SKILL_NAME, path: filePath } : null;
20995
+ } catch {
20996
+ return null;
20997
+ }
20998
+ }
20999
+
21000
+ // packages/host-runtime/src/delegation-mention-rewrite.ts
21001
+ function describeTargets(mentions) {
21002
+ return mentions.map(({ harnessId, label }) => `@${label} (Harness \`${harnessId}\`)`).join(", ");
21003
+ }
21004
+ function delegationMentionInstruction(mentions) {
21005
+ const plural = mentions.length > 1;
21006
+ return [
21007
+ `[codexhost delegation] The user mentioned ${describeTargets(mentions)}.`,
21008
+ `Use the ${DELEGATION_SKILL_NAME} skill to delegate this request to ${plural ? "each mentioned Harness" : "that Harness"}`,
21009
+ "with `codexhost delegate start --harness <id>`, instead of doing the task yourself."
21010
+ ].join(" ");
21011
+ }
21012
+ function appendInstruction(text, mentions) {
21013
+ const instruction = delegationMentionInstruction(mentions);
21014
+ return text.trim().length === 0 ? instruction : `${text}
21015
+
21016
+ ${instruction}`;
21017
+ }
21018
+ function rewriteDelegationMentionText(text) {
21019
+ const { text: stripped, mentions } = stripDelegationMentions(text);
21020
+ return mentions.length === 0 ? text : appendInstruction(stripped, mentions);
21021
+ }
21022
+ function isRecord(value2) {
21023
+ return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
21024
+ }
21025
+ function rewriteDelegationMentionInput(input, skill) {
21026
+ const mentions = [];
21027
+ const seen = /* @__PURE__ */ new Set();
21028
+ let lastTextIndex = -1;
21029
+ const rewritten = input.map((item, index) => {
21030
+ if (!isRecord(item) || item.type !== "text" || typeof item.text !== "string") return item;
21031
+ lastTextIndex = index;
21032
+ const result = stripDelegationMentions(item.text);
21033
+ for (const mention of result.mentions) {
21034
+ if (seen.has(mention.harnessId)) continue;
21035
+ seen.add(mention.harnessId);
21036
+ mentions.push(mention);
21037
+ }
21038
+ return result.mentions.length === 0 ? item : { ...item, text: result.text };
21039
+ });
21040
+ if (mentions.length === 0) return null;
21041
+ const target = rewritten[lastTextIndex];
21042
+ if (isRecord(target) && typeof target.text === "string") {
21043
+ rewritten[lastTextIndex] = {
21044
+ ...target,
21045
+ text: appendInstruction(target.text, mentions)
21046
+ };
21047
+ }
21048
+ const hasSkill = rewritten.some(
21049
+ (item) => isRecord(item) && item.type === "skill" && item.name === skill?.name
21050
+ );
21051
+ if (skill && !hasSkill) rewritten.push({ type: "skill", name: skill.name, path: skill.path });
21052
+ return rewritten;
21053
+ }
21054
+
20633
21055
  // packages/harness-adapter/dist/output-channel.js
20634
21056
  var HarnessOutputChannel = class {
20635
21057
  outputs;
@@ -20708,11 +21130,11 @@ var usageFields = /* @__PURE__ */ new Set([
20708
21130
  "totalCredits",
20709
21131
  "contextUsagePercent"
20710
21132
  ]);
20711
- function isRecord(value2) {
21133
+ function isRecord2(value2) {
20712
21134
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
20713
21135
  }
20714
21136
  function parseHostUsage(value2) {
20715
- if (!isRecord(value2))
21137
+ if (!isRecord2(value2))
20716
21138
  throw new Error("Harness Usage must be an object");
20717
21139
  const keys = Object.keys(value2);
20718
21140
  if (keys.length === 0)
@@ -20769,6 +21191,82 @@ function parseHostUsage(value2) {
20769
21191
  return { ...value2 };
20770
21192
  }
20771
21193
 
21194
+ // packages/harness-adapter/dist/live-command-catalog.js
21195
+ var COMMON_EXCLUDED_LIVE_COMMANDS = /* @__PURE__ */ new Set([
21196
+ // Session lifecycle
21197
+ "branch",
21198
+ "clear",
21199
+ "exit",
21200
+ "fork",
21201
+ "fresh",
21202
+ "new",
21203
+ "quit",
21204
+ "rename",
21205
+ "rename-chat",
21206
+ "reset",
21207
+ "resume",
21208
+ "rewind",
21209
+ "session",
21210
+ "sessions",
21211
+ // Desktop-owned configuration
21212
+ "autocompact",
21213
+ "color",
21214
+ "config",
21215
+ "effort",
21216
+ "fast",
21217
+ "keybindings",
21218
+ "model",
21219
+ "models",
21220
+ "output-style",
21221
+ "permissions",
21222
+ "settings",
21223
+ "statusline",
21224
+ "terminal-setup",
21225
+ "theme",
21226
+ "vim",
21227
+ // Trust and approval policy
21228
+ "always-approve",
21229
+ "auto-mode-setup",
21230
+ // Native login
21231
+ "login",
21232
+ "logout",
21233
+ // Work outliving the Turn
21234
+ "autopilot",
21235
+ "background",
21236
+ "bg",
21237
+ "goal",
21238
+ "jobs",
21239
+ "loop",
21240
+ "multitask",
21241
+ "queue",
21242
+ "remote-control",
21243
+ "schedule",
21244
+ "steer",
21245
+ // Native terminal UI
21246
+ "copy",
21247
+ "debug",
21248
+ "feedback",
21249
+ "heapdump",
21250
+ "share",
21251
+ "shell",
21252
+ // Plugin and MCP management
21253
+ "marketplace",
21254
+ "mcp",
21255
+ "plugins",
21256
+ "reload-plugins"
21257
+ ]);
21258
+ var COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES = ["__", "hooks-"];
21259
+ function isExcludedLiveCommand(name, kind, extra = {}) {
21260
+ const normalized = name.trim().replace(/^\//u, "");
21261
+ if (new Set(extra.names ?? []).has(normalized))
21262
+ return true;
21263
+ if (extra.prefixes?.some((prefix) => normalized.startsWith(prefix)))
21264
+ return true;
21265
+ if (kind === "skill")
21266
+ return false;
21267
+ return COMMON_EXCLUDED_LIVE_COMMANDS.has(normalized) || COMMON_EXCLUDED_LIVE_COMMAND_PREFIXES.some((prefix) => normalized.startsWith(prefix));
21268
+ }
21269
+
20772
21270
  // packages/harness-adapter/dist/index.js
20773
21271
  var packageMetadata = {
20774
21272
  name: "@codexhost/harness-adapter",
@@ -20777,10 +21275,10 @@ var packageMetadata = {
20777
21275
 
20778
21276
  // packages/mapping-store/dist/mapping-store.js
20779
21277
  import { execFileSync } from "node:child_process";
20780
- import { randomUUID as randomUUID2 } from "node:crypto";
21278
+ import { randomUUID as randomUUID3 } from "node:crypto";
20781
21279
  import { constants } from "node:fs";
20782
- import { copyFile as copyFile2, mkdir as mkdir3, open as open3, readFile as readFile4, readdir as readdir2, rename as rename2, rm as rm3, stat } from "node:fs/promises";
20783
- import path5 from "node:path";
21280
+ import { copyFile as copyFile2, mkdir as mkdir4, open as open4, readFile as readFile6, readdir as readdir2, rename as rename3, rm as rm4, stat as stat2 } from "node:fs/promises";
21281
+ import path7 from "node:path";
20784
21282
 
20785
21283
  // packages/mapping-store/dist/records.js
20786
21284
  var nonBlankTextSchema6 = external_exports.string().refine((value2) => value2.trim().length > 0, {
@@ -20931,7 +21429,7 @@ function systemErrorCode2(error51) {
20931
21429
  }
20932
21430
  async function exists(file2) {
20933
21431
  try {
20934
- await stat(file2);
21432
+ await stat2(file2);
20935
21433
  return true;
20936
21434
  } catch (error51) {
20937
21435
  if (systemErrorCode2(error51) === "ENOENT")
@@ -21041,13 +21539,13 @@ var MappingStore = class {
21041
21539
  #initialized = false;
21042
21540
  #lockHandle = null;
21043
21541
  constructor(options2) {
21044
- this.#directory = path5.resolve(options2.directory);
21045
- this.#threadsDirectory = path5.join(this.#directory, "threads");
21046
- this.#delegationsDirectory = path5.join(this.#directory, "delegations");
21047
- this.#backupsDirectory = path5.join(this.#directory, "backups");
21048
- this.#quarantineDirectory = path5.join(this.#directory, "quarantine");
21049
- this.#lockPath = path5.join(this.#directory, "store.lock");
21050
- this.#instanceId = options2.instanceId ?? randomUUID2();
21542
+ this.#directory = path7.resolve(options2.directory);
21543
+ this.#threadsDirectory = path7.join(this.#directory, "threads");
21544
+ this.#delegationsDirectory = path7.join(this.#directory, "delegations");
21545
+ this.#backupsDirectory = path7.join(this.#directory, "backups");
21546
+ this.#quarantineDirectory = path7.join(this.#directory, "quarantine");
21547
+ this.#lockPath = path7.join(this.#directory, "store.lock");
21548
+ this.#instanceId = options2.instanceId ?? randomUUID3();
21051
21549
  this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
21052
21550
  this.#beforeReplace = options2.beforeReplace;
21053
21551
  }
@@ -21055,18 +21553,18 @@ var MappingStore = class {
21055
21553
  if (this.#initialized)
21056
21554
  return;
21057
21555
  await Promise.all([
21058
- mkdir3(this.#threadsDirectory, { recursive: true }),
21059
- mkdir3(this.#delegationsDirectory, { recursive: true }),
21060
- mkdir3(this.#backupsDirectory, { recursive: true }),
21061
- mkdir3(this.#quarantineDirectory, { recursive: true })
21556
+ mkdir4(this.#threadsDirectory, { recursive: true }),
21557
+ mkdir4(this.#delegationsDirectory, { recursive: true }),
21558
+ mkdir4(this.#backupsDirectory, { recursive: true }),
21559
+ mkdir4(this.#quarantineDirectory, { recursive: true })
21062
21560
  ]);
21063
21561
  await this.#acquireLock();
21064
21562
  try {
21065
21563
  await this.#cleanupResidue();
21066
21564
  const names = (await readdir2(this.#threadsDirectory)).filter((name) => name.endsWith(".json"));
21067
21565
  for (const name of names) {
21068
- const primary = path5.join(this.#threadsDirectory, name);
21069
- const backup = path5.join(this.#backupsDirectory, name);
21566
+ const primary = path7.join(this.#threadsDirectory, name);
21567
+ const backup = path7.join(this.#backupsDirectory, name);
21070
21568
  let record3 = null;
21071
21569
  try {
21072
21570
  record3 = await this.#readRecord(primary, name);
@@ -21075,31 +21573,31 @@ var MappingStore = class {
21075
21573
  record3 = await this.#readRecord(backup, name);
21076
21574
  await this.#replaceFile(primary, record3, false);
21077
21575
  } catch (backupError) {
21078
- const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
21079
- await rename2(primary, quarantine).catch(() => void 0);
21576
+ const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid`);
21577
+ await rename3(primary, quarantine).catch(() => void 0);
21080
21578
  void primaryError;
21081
21579
  void backupError;
21082
21580
  continue;
21083
21581
  }
21084
21582
  }
21085
21583
  if (record3.state === "creating" && !record3.nativeSessionRef) {
21086
- await rm3(primary, { force: true });
21087
- await rm3(backup, { force: true });
21584
+ await rm4(primary, { force: true });
21585
+ await rm4(backup, { force: true });
21088
21586
  continue;
21089
21587
  }
21090
21588
  this.#records.set(record3.hostThreadId, record3);
21091
21589
  }
21092
21590
  const delegationNames = (await readdir2(this.#delegationsDirectory)).filter((name) => name.endsWith(".json"));
21093
21591
  for (const name of delegationNames) {
21094
- const file2 = path5.join(this.#delegationsDirectory, name);
21592
+ const file2 = path7.join(this.#delegationsDirectory, name);
21095
21593
  try {
21096
- const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile4(file2, "utf8")));
21594
+ const parsed = storedDelegationRecordV1Schema.parse(JSON.parse(await readFile6(file2, "utf8")));
21097
21595
  if (`${parsed.delegationId}.json` !== name)
21098
21596
  throw new Error("filename mismatch");
21099
21597
  this.#delegations.set(parsed.delegationId, parsed);
21100
21598
  } catch {
21101
- const quarantine = path5.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
21102
- await rename2(file2, quarantine).catch(() => void 0);
21599
+ const quarantine = path7.join(this.#quarantineDirectory, `${name}.${this.#now().getTime()}.invalid-delegation`);
21600
+ await rename3(file2, quarantine).catch(() => void 0);
21103
21601
  }
21104
21602
  }
21105
21603
  this.#rebuildIndexes();
@@ -21197,7 +21695,7 @@ var MappingStore = class {
21197
21695
  }
21198
21696
  async removeDelegation(delegationId) {
21199
21697
  this.#requireInitialized();
21200
- await rm3(this.#delegationPath(delegationId), { force: true });
21698
+ await rm4(this.#delegationPath(delegationId), { force: true });
21201
21699
  this.#delegations.delete(delegationId);
21202
21700
  this.#rebuildIndexes();
21203
21701
  }
@@ -21370,8 +21868,8 @@ var MappingStore = class {
21370
21868
  if (!this.#records.has(hostThreadId))
21371
21869
  return;
21372
21870
  await Promise.all([
21373
- rm3(this.#recordPath(hostThreadId), { force: true }),
21374
- rm3(this.#backupPath(hostThreadId), { force: true })
21871
+ rm4(this.#recordPath(hostThreadId), { force: true }),
21872
+ rm4(this.#backupPath(hostThreadId), { force: true })
21375
21873
  ]);
21376
21874
  this.#records.delete(hostThreadId);
21377
21875
  this.#rebuildIndexes();
@@ -21384,9 +21882,9 @@ var MappingStore = class {
21384
21882
  if (handle)
21385
21883
  await handle.close().catch(() => void 0);
21386
21884
  try {
21387
- const current = JSON.parse(await readFile4(this.#lockPath, "utf8"));
21885
+ const current = JSON.parse(await readFile6(this.#lockPath, "utf8"));
21388
21886
  if (current.instanceId === this.#instanceId)
21389
- await rm3(this.#lockPath, { force: true });
21887
+ await rm4(this.#lockPath, { force: true });
21390
21888
  } catch {
21391
21889
  }
21392
21890
  }
@@ -21453,11 +21951,11 @@ var MappingStore = class {
21453
21951
  this.#rebuildIndexes();
21454
21952
  }
21455
21953
  async #replaceFile(target, record3, preserveBackup) {
21456
- const temp = `${target}.tmp-${randomUUID2()}`;
21954
+ const temp = `${target}.tmp-${randomUUID3()}`;
21457
21955
  let handle = null;
21458
21956
  try {
21459
21957
  await this.#beforeReplace?.(cloneRecord(record3));
21460
- handle = await open3(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
21958
+ handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
21461
21959
  await handle.writeFile(`${JSON.stringify(record3, null, 2)}
21462
21960
  `, "utf8");
21463
21961
  await handle.sync();
@@ -21466,10 +21964,10 @@ var MappingStore = class {
21466
21964
  if (preserveBackup && await exists(target)) {
21467
21965
  await copyFile2(target, this.#backupPath(record3.hostThreadId));
21468
21966
  }
21469
- await rename2(temp, target);
21967
+ await rename3(temp, target);
21470
21968
  } catch (error51) {
21471
21969
  await handle?.close().catch(() => void 0);
21472
- await rm3(temp, { force: true }).catch(() => void 0);
21970
+ await rm4(temp, { force: true }).catch(() => void 0);
21473
21971
  if (error51 instanceof MappingStoreError)
21474
21972
  throw error51;
21475
21973
  throw new MappingStoreError("IO_ERROR", "Mapping Store atomic replacement failed", {
@@ -21479,19 +21977,19 @@ var MappingStore = class {
21479
21977
  }
21480
21978
  async #replaceDelegationFile(record3) {
21481
21979
  const target = this.#delegationPath(record3.delegationId);
21482
- const temp = `${target}.tmp-${randomUUID2()}`;
21980
+ const temp = `${target}.tmp-${randomUUID3()}`;
21483
21981
  let handle = null;
21484
21982
  try {
21485
- handle = await open3(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
21983
+ handle = await open4(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
21486
21984
  await handle.writeFile(`${JSON.stringify(record3, null, 2)}
21487
21985
  `, "utf8");
21488
21986
  await handle.sync();
21489
21987
  await handle.close();
21490
21988
  handle = null;
21491
- await rename2(temp, target);
21989
+ await rename3(temp, target);
21492
21990
  } catch (error51) {
21493
21991
  await handle?.close().catch(() => void 0);
21494
- await rm3(temp, { force: true }).catch(() => void 0);
21992
+ await rm4(temp, { force: true }).catch(() => void 0);
21495
21993
  if (error51 instanceof MappingStoreError)
21496
21994
  throw error51;
21497
21995
  throw new MappingStoreError("IO_ERROR", "Delegation atomic replacement failed", {
@@ -21500,7 +21998,7 @@ var MappingStore = class {
21500
21998
  }
21501
21999
  }
21502
22000
  async #readRecord(file2, expectedName) {
21503
- const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await readFile4(file2, "utf8")));
22001
+ const parsed = storedThreadRecordV1Schema.safeParse(JSON.parse(await readFile6(file2, "utf8")));
21504
22002
  if (!parsed.success) {
21505
22003
  throw new MappingStoreError("INVALID_RECORD", "Mapping Store record is invalid", {
21506
22004
  cause: parsed.error
@@ -21518,15 +22016,15 @@ var MappingStore = class {
21518
22016
  readdir2(this.#directory)
21519
22017
  ]);
21520
22018
  await Promise.all([
21521
- ...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#threadsDirectory, name), { force: true })),
21522
- ...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm3(path5.join(this.#delegationsDirectory, name), { force: true })),
22019
+ ...threadNames.filter((name) => name.includes(".tmp-")).map((name) => rm4(path7.join(this.#threadsDirectory, name), { force: true })),
22020
+ ...delegationNames.filter((name) => name.includes(".tmp-")).map((name) => rm4(path7.join(this.#delegationsDirectory, name), { force: true })),
21523
22021
  // Renamed aside by #acquireLock; nothing reads them back, and they accumulate one per run.
21524
- ...rootNames.filter((name) => name.startsWith(`${path5.basename(this.#lockPath)}.stale-`)).map((name) => rm3(path5.join(this.#directory, name), { force: true }))
22022
+ ...rootNames.filter((name) => name.startsWith(`${path7.basename(this.#lockPath)}.stale-`)).map((name) => rm4(path7.join(this.#directory, name), { force: true }))
21525
22023
  ]);
21526
22024
  }
21527
22025
  async #acquireLock() {
21528
22026
  const attempt = async () => {
21529
- const handle = await open3(this.#lockPath, "wx", constants.S_IRUSR | constants.S_IWUSR);
22027
+ const handle = await open4(this.#lockPath, "wx", constants.S_IRUSR | constants.S_IWUSR);
21530
22028
  const lock = {
21531
22029
  pid: process.pid,
21532
22030
  instanceId: this.#instanceId,
@@ -21548,13 +22046,13 @@ var MappingStore = class {
21548
22046
  }
21549
22047
  let existing = {};
21550
22048
  try {
21551
- existing = JSON.parse(await readFile4(this.#lockPath, "utf8"));
22049
+ existing = JSON.parse(await readFile6(this.#lockPath, "utf8"));
21552
22050
  } catch {
21553
22051
  }
21554
22052
  if (typeof existing.pid === "number" && lockOwnerIsLive(existing)) {
21555
22053
  throw new MappingStoreError("STORE_LOCKED", "Another codexhost process owns Mapping Store");
21556
22054
  }
21557
- await rename2(this.#lockPath, `${this.#lockPath}.stale-${this.#now().getTime()}`).catch(() => void 0);
22055
+ await rename3(this.#lockPath, `${this.#lockPath}.stale-${this.#now().getTime()}`).catch(() => void 0);
21558
22056
  try {
21559
22057
  this.#lockHandle = await attempt();
21560
22058
  } catch (error51) {
@@ -21622,13 +22120,13 @@ var MappingStore = class {
21622
22120
  await next;
21623
22121
  }
21624
22122
  #recordPath(hostThreadId) {
21625
- return path5.join(this.#threadsDirectory, `${hostThreadId}.json`);
22123
+ return path7.join(this.#threadsDirectory, `${hostThreadId}.json`);
21626
22124
  }
21627
22125
  #delegationPath(delegationId) {
21628
- return path5.join(this.#delegationsDirectory, `${delegationId}.json`);
22126
+ return path7.join(this.#delegationsDirectory, `${delegationId}.json`);
21629
22127
  }
21630
22128
  #backupPath(hostThreadId) {
21631
- return path5.join(this.#backupsDirectory, `${hostThreadId}.json`);
22129
+ return path7.join(this.#backupsDirectory, `${hostThreadId}.json`);
21632
22130
  }
21633
22131
  #requireInitialized() {
21634
22132
  if (!this.#initialized) {
@@ -21648,7 +22146,7 @@ var TITLE_MAX_LENGTH = 150;
21648
22146
  var DESCRIPTION_MAX_LENGTH = 500;
21649
22147
  var SERVER_NAME_MAX_LENGTH = 80;
21650
22148
  var ELLIPSIS = "…";
21651
- function isRecord2(value2) {
22149
+ function isRecord3(value2) {
21652
22150
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
21653
22151
  }
21654
22152
  function boundedText(value2, field, maxLength) {
@@ -21702,7 +22200,7 @@ function responseError(message) {
21702
22200
  function responsePersist(value2) {
21703
22201
  if (value2 === void 0 || value2 === null)
21704
22202
  return null;
21705
- if (!isRecord2(value2) || Object.keys(value2).length !== 1 || value2.persist !== "session" && value2.persist !== "always") {
22203
+ if (!isRecord3(value2) || Object.keys(value2).length !== 1 || value2.persist !== "session" && value2.persist !== "always") {
21706
22204
  throw responseError("contains malformed persist metadata");
21707
22205
  }
21708
22206
  return value2.persist;
@@ -21748,7 +22246,7 @@ function projectCodexApprovalRequest(input) {
21748
22246
  },
21749
22247
  denyResponse,
21750
22248
  parseResponse(result) {
21751
- if (!isRecord2(result) || typeof result.action !== "string") {
22249
+ if (!isRecord3(result) || typeof result.action !== "string") {
21752
22250
  throw responseError("missing action");
21753
22251
  }
21754
22252
  if (Object.keys(result).some((key) => key !== "action" && key !== "content" && key !== "_meta")) {
@@ -21756,7 +22254,7 @@ function projectCodexApprovalRequest(input) {
21756
22254
  }
21757
22255
  const selectedPersist = responsePersist(result._meta);
21758
22256
  if (result.action === "accept") {
21759
- if ("content" in result && (!isRecord2(result.content) || Object.keys(result.content).length !== 0)) {
22257
+ if ("content" in result && (!isRecord3(result.content) || Object.keys(result.content).length !== 0)) {
21760
22258
  throw responseError("contains non-empty accepted content");
21761
22259
  }
21762
22260
  if (selectedPersist === "session") {
@@ -21816,7 +22314,7 @@ function projectApprovalChoices(input) {
21816
22314
  },
21817
22315
  denyResponse,
21818
22316
  parseResponse(result) {
21819
- if (!isRecord2(result) || typeof result.action !== "string")
22317
+ if (!isRecord3(result) || typeof result.action !== "string")
21820
22318
  throw responseError("missing action");
21821
22319
  if (Object.keys(result).some((key) => !["action", "content", "_meta"].includes(key))) {
21822
22320
  throw responseError("contains unreviewed fields");
@@ -21831,7 +22329,7 @@ function projectApprovalChoices(input) {
21831
22329
  return denyResponse;
21832
22330
  }
21833
22331
  const content = result.content;
21834
- if (result.action !== "accept" || !isRecord2(content) || Object.keys(content).length !== 1 || !interaction.actions.some(({ id: id2 }) => id2 === content.actionId)) {
22332
+ if (result.action !== "accept" || !isRecord3(content) || Object.keys(content).length !== 1 || !interaction.actions.some(({ id: id2 }) => id2 === content.actionId)) {
21835
22333
  throw responseError("contains an undeclared approval choice");
21836
22334
  }
21837
22335
  return { type: "approval", actionId: content.actionId };
@@ -21840,7 +22338,7 @@ function projectApprovalChoices(input) {
21840
22338
  }
21841
22339
 
21842
22340
  // packages/protocol-core/dist/codex-question.js
21843
- function isRecord3(value2) {
22341
+ function isRecord4(value2) {
21844
22342
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
21845
22343
  }
21846
22344
  function responseError2(message) {
@@ -21909,7 +22407,7 @@ function projectCodexQuestionRequest(input) {
21909
22407
  }
21910
22408
  },
21911
22409
  parseResponse(result) {
21912
- if (!isRecord3(result) || !isRecord3(result.answers)) {
22410
+ if (!isRecord4(result) || !isRecord4(result.answers)) {
21913
22411
  throw responseError2("missing answers object");
21914
22412
  }
21915
22413
  const rawAnswers = result.answers;
@@ -21922,7 +22420,7 @@ function projectCodexQuestionRequest(input) {
21922
22420
  const question = interaction.questions.find(({ id: id2 }) => id2 === questionId);
21923
22421
  if (!question)
21924
22422
  throw responseError2("contains an unknown Question ID");
21925
- if (!isRecord3(answerValue) || !Array.isArray(answerValue.answers)) {
22423
+ if (!isRecord4(answerValue) || !Array.isArray(answerValue.answers)) {
21926
22424
  throw responseError2("answer entry has no answers array");
21927
22425
  }
21928
22426
  const values = answerValue.answers;
@@ -22004,7 +22502,7 @@ function projectCodexThreadUsage(input) {
22004
22502
  }
22005
22503
 
22006
22504
  // packages/protocol-core/dist/codex-native-usage.js
22007
- function isRecord4(value2) {
22505
+ function isRecord5(value2) {
22008
22506
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
22009
22507
  }
22010
22508
  function nonNegativeSafeInteger(value2) {
@@ -22034,20 +22532,20 @@ function addBreakdown(target, source) {
22034
22532
  }
22035
22533
  }
22036
22534
  function observeCodexTokenUsage(value2) {
22037
- if (!isRecord4(value2) || value2.method !== "thread/tokenUsage/updated")
22535
+ if (!isRecord5(value2) || value2.method !== "thread/tokenUsage/updated")
22038
22536
  return null;
22039
22537
  const params = value2.params;
22040
- if (!isRecord4(params))
22538
+ if (!isRecord5(params))
22041
22539
  return null;
22042
22540
  const threadId2 = hostThreadIdSchema.safeParse(params.threadId);
22043
22541
  const turnId = hostTurnIdSchema.safeParse(params.turnId);
22044
22542
  if (!threadId2.success || !turnId.success)
22045
22543
  return null;
22046
22544
  const tokenUsage = params.tokenUsage;
22047
- if (!isRecord4(tokenUsage))
22545
+ if (!isRecord5(tokenUsage))
22048
22546
  return null;
22049
- const total = isRecord4(tokenUsage.total) ? tokenUsage.total : void 0;
22050
- const last = isRecord4(tokenUsage.last) ? tokenUsage.last : void 0;
22547
+ const total = isRecord5(tokenUsage.total) ? tokenUsage.total : void 0;
22548
+ const last = isRecord5(tokenUsage.last) ? tokenUsage.last : void 0;
22051
22549
  const usage = {};
22052
22550
  addBreakdown(usage, total);
22053
22551
  const contextUsedTokens = nonNegativeSafeInteger(last?.totalTokens);
@@ -22072,7 +22570,7 @@ function observeCodexTokenUsage(value2) {
22072
22570
  }
22073
22571
  }
22074
22572
  function parseRateLimitWindow(value2) {
22075
- if (!isRecord4(value2))
22573
+ if (!isRecord5(value2))
22076
22574
  return null;
22077
22575
  const usedPercent = finitePercent(value2.usedPercent);
22078
22576
  const windowDurationMins = nonNegativeSafeInteger(value2.windowDurationMins);
@@ -22083,7 +22581,7 @@ function parseRateLimitWindow(value2) {
22083
22581
  return { usedPercent, windowDurationMins, ...resetsAt !== void 0 ? { resetsAt } : {} };
22084
22582
  }
22085
22583
  function parseRateLimitCandidate(value2, options2 = {}) {
22086
- if (!isRecord4(value2))
22584
+ if (!isRecord5(value2))
22087
22585
  return null;
22088
22586
  if (options2.genericOnly && value2.limitId !== void 0 && value2.limitId !== null && value2.limitId !== "codex") {
22089
22587
  return null;
@@ -22093,16 +22591,16 @@ function parseRateLimitCandidate(value2, options2 = {}) {
22093
22591
  return primary || secondary ? { primary, secondary } : null;
22094
22592
  }
22095
22593
  function rateLimitCandidates(value2) {
22096
- if (!isRecord4(value2))
22594
+ if (!isRecord5(value2))
22097
22595
  return [];
22098
- const result = isRecord4(value2.result) ? value2.result : value2;
22099
- if (!isRecord4(result))
22596
+ const result = isRecord5(value2.result) ? value2.result : value2;
22597
+ if (!isRecord5(result))
22100
22598
  return [];
22101
22599
  const candidates = [];
22102
22600
  const base = parseRateLimitCandidate(result.rateLimits, { genericOnly: true });
22103
22601
  if (base)
22104
22602
  candidates.push(base);
22105
- const notificationParams = isRecord4(value2.params) ? value2.params : void 0;
22603
+ const notificationParams = isRecord5(value2.params) ? value2.params : void 0;
22106
22604
  const notificationSnapshot = parseRateLimitCandidate(notificationParams?.rateLimits, {
22107
22605
  genericOnly: true
22108
22606
  });
@@ -22146,14 +22644,14 @@ function parseAvailableCount(value2) {
22146
22644
  return void 0;
22147
22645
  }
22148
22646
  function rateLimitResetCreditsSummary(value2) {
22149
- if (!isRecord4(value2))
22647
+ if (!isRecord5(value2))
22150
22648
  return null;
22151
- const result = isRecord4(value2.result) ? value2.result : value2;
22152
- const fromResult = isRecord4(result) && isRecord4(result.rateLimitResetCredits) ? result.rateLimitResetCredits : null;
22649
+ const result = isRecord5(value2.result) ? value2.result : value2;
22650
+ const fromResult = isRecord5(result) && isRecord5(result.rateLimitResetCredits) ? result.rateLimitResetCredits : null;
22153
22651
  if (fromResult)
22154
22652
  return fromResult;
22155
- const params = isRecord4(value2.params) ? value2.params : void 0;
22156
- return isRecord4(params?.rateLimitResetCredits) ? params.rateLimitResetCredits : null;
22653
+ const params = isRecord5(value2.params) ? value2.params : void 0;
22654
+ return isRecord5(params?.rateLimitResetCredits) ? params.rateLimitResetCredits : null;
22157
22655
  }
22158
22656
  function observeCodexRateLimitResetCredits(value2) {
22159
22657
  const summary = rateLimitResetCreditsSummary(value2);
@@ -22165,7 +22663,7 @@ function observeCodexRateLimitResetCredits(value2) {
22165
22663
  const expiresAtUnix = [];
22166
22664
  if (Array.isArray(summary.credits)) {
22167
22665
  for (const credit of summary.credits) {
22168
- if (!isRecord4(credit))
22666
+ if (!isRecord5(credit))
22169
22667
  continue;
22170
22668
  if (credit.status !== void 0 && credit.status !== "available")
22171
22669
  continue;
@@ -22316,16 +22814,16 @@ var Diff = class {
22316
22814
  }
22317
22815
  }
22318
22816
  }
22319
- addToPath(path26, added, removed, oldPosInc, options2) {
22320
- const last = path26.lastComponent;
22817
+ addToPath(path28, added, removed, oldPosInc, options2) {
22818
+ const last = path28.lastComponent;
22321
22819
  if (last && !options2.oneChangePerToken && last.added === added && last.removed === removed) {
22322
22820
  return {
22323
- oldPos: path26.oldPos + oldPosInc,
22821
+ oldPos: path28.oldPos + oldPosInc,
22324
22822
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
22325
22823
  };
22326
22824
  } else {
22327
22825
  return {
22328
- oldPos: path26.oldPos + oldPosInc,
22826
+ oldPos: path28.oldPos + oldPosInc,
22329
22827
  lastComponent: { count: 1, added, removed, previousComponent: last }
22330
22828
  };
22331
22829
  }
@@ -22754,10 +23252,10 @@ function splitLines(text) {
22754
23252
  }
22755
23253
 
22756
23254
  // packages/protocol-core/dist/file-change-summary.js
22757
- import path6 from "node:path";
23255
+ import path8 from "node:path";
22758
23256
  function filePathKey(file2, cwd) {
22759
23257
  const windows = /^[a-z]:[/\\]/i.test(cwd) || /^[a-z]:[/\\]/i.test(file2);
22760
- const paths = windows ? path6.win32 : path6.posix;
23258
+ const paths = windows ? path8.win32 : path8.posix;
22761
23259
  const resolved = paths.resolve(cwd, file2).replaceAll("\\", "/");
22762
23260
  return windows ? resolved.toLowerCase() : resolved;
22763
23261
  }
@@ -22908,11 +23406,11 @@ function itemStatus(outcome) {
22908
23406
  return "inProgress";
22909
23407
  return outcome.status === "succeeded" ? "completed" : "failed";
22910
23408
  }
22911
- function isRecord5(value2) {
23409
+ function isRecord6(value2) {
22912
23410
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
22913
23411
  }
22914
23412
  function nestedString(value2, keys, preserveText = false) {
22915
- if (!isRecord5(value2))
23413
+ if (!isRecord6(value2))
22916
23414
  return void 0;
22917
23415
  for (const key of keys) {
22918
23416
  const field = value2[key];
@@ -23026,8 +23524,8 @@ function projectFileChangeKind(kind) {
23026
23524
  return { type: kind };
23027
23525
  }
23028
23526
  function projectFileChanges(changes) {
23029
- return changes.map(({ path: path26, kind, unifiedDiff }) => ({
23030
- path: path26,
23527
+ return changes.map(({ path: path28, kind, unifiedDiff }) => ({
23528
+ path: path28,
23031
23529
  kind: projectFileChangeKind(kind),
23032
23530
  diff: unifiedDiff
23033
23531
  }));
@@ -23067,7 +23565,7 @@ function planFromTodoValue(value2) {
23067
23565
  const record3 = unwrapToolRecord(value2);
23068
23566
  if (!record3)
23069
23567
  return planFromChecklistText(typeof value2 === "string" ? value2 : null);
23070
- if (isRecord5(record3.TodosUpdated)) {
23568
+ if (isRecord6(record3.TodosUpdated)) {
23071
23569
  const nested = planFromTodoValue(record3.TodosUpdated);
23072
23570
  if (nested)
23073
23571
  return nested;
@@ -23082,7 +23580,7 @@ function planFromTodoValue(value2) {
23082
23580
  plan.push({ step: entry.trim(), status: "pending" });
23083
23581
  continue;
23084
23582
  }
23085
- if (!isRecord5(entry))
23583
+ if (!isRecord6(entry))
23086
23584
  continue;
23087
23585
  const step = nestedString(entry, ["content", "step", "text", "title", "description", "task"]);
23088
23586
  if (!step)
@@ -23137,7 +23635,7 @@ function unwrapToolRecord(value2) {
23137
23635
  }
23138
23636
  if (Array.isArray(value2))
23139
23637
  return { todos: value2 };
23140
- if (!isRecord5(value2))
23638
+ if (!isRecord6(value2))
23141
23639
  return null;
23142
23640
  for (const wrapper of ["input", "arguments", "params"]) {
23143
23641
  if (value2[wrapper] === void 0)
@@ -23927,7 +24425,7 @@ var CodexTurnProjector = class {
23927
24425
  };
23928
24426
 
23929
24427
  // packages/protocol-core/dist/thread-fork.js
23930
- function isRecord6(value2) {
24428
+ function isRecord7(value2) {
23931
24429
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
23932
24430
  }
23933
24431
  function optionalText(params, name, options2 = {}) {
@@ -23950,7 +24448,7 @@ function optionalBoolean(params, name) {
23950
24448
  function decodeThreadForkRequest(request) {
23951
24449
  if (request.method !== "thread/fork")
23952
24450
  return null;
23953
- if (!isRecord6(request.params))
24451
+ if (!isRecord7(request.params))
23954
24452
  throw new Error("thread/fork params must be an object");
23955
24453
  const params = request.params;
23956
24454
  const threadId2 = optionalText(params, "threadId");
@@ -23965,13 +24463,13 @@ function decodeThreadForkRequest(request) {
23965
24463
  if (runtimeWorkspaceRoots !== void 0 && runtimeWorkspaceRoots !== null && (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.some((root) => typeof root !== "string" || root.length === 0))) {
23966
24464
  throw new Error("thread/fork params.runtimeWorkspaceRoots must be text paths or null");
23967
24465
  }
23968
- const path26 = optionalText(params, "path", { allowEmpty: true });
24466
+ const path28 = optionalText(params, "path", { allowEmpty: true });
23969
24467
  const ephemeral = optionalBoolean(params, "ephemeral");
23970
24468
  return {
23971
24469
  threadId: threadId2,
23972
24470
  ...lastTurnText ? { lastTurnId: hostTurnIdSchema.parse(lastTurnText) } : {},
23973
24471
  ...beforeTurnText ? { beforeTurnId: hostTurnIdSchema.parse(beforeTurnText) } : {},
23974
- ...path26 ? { path: path26 } : {},
24472
+ ...path28 ? { path: path28 } : {},
23975
24473
  ...optionalField(params, "model"),
23976
24474
  ...optionalField(params, "modelProvider"),
23977
24475
  ...optionalField(params, "cwd"),
@@ -23986,7 +24484,7 @@ function decodeThreadForkRequest(request) {
23986
24484
  function decodeThreadRevertRequest(request) {
23987
24485
  if (request.method !== "thread/revert")
23988
24486
  return null;
23989
- if (!isRecord6(request.params))
24487
+ if (!isRecord7(request.params))
23990
24488
  throw new Error("thread/revert params must be an object");
23991
24489
  const { threadId: threadId2, beforeTurnId } = request.params;
23992
24490
  if (typeof threadId2 !== "string" || threadId2.length === 0) {
@@ -24000,7 +24498,7 @@ function decodeThreadRevertRequest(request) {
24000
24498
  function decodeThreadRollbackRequest(request) {
24001
24499
  if (request.method !== "thread/rollback")
24002
24500
  return null;
24003
- if (!isRecord6(request.params))
24501
+ if (!isRecord7(request.params))
24004
24502
  throw new Error("thread/rollback params must be an object");
24005
24503
  const { threadId: threadId2, numTurns } = request.params;
24006
24504
  if (typeof threadId2 !== "string" || threadId2.length === 0) {
@@ -24064,7 +24562,7 @@ function threadForkResult(thread, input) {
24064
24562
  }
24065
24563
 
24066
24564
  // packages/protocol-core/dist/thread-management.js
24067
- import { createHash as createHash2 } from "node:crypto";
24565
+ import { createHash as createHash4 } from "node:crypto";
24068
24566
  var HOST_CURSOR_PREFIX = "codexhost:thread-list:v1:";
24069
24567
  var MAX_CURSOR_LENGTH = 65536;
24070
24568
  var DEFAULT_PAGE_SIZE = 25;
@@ -24097,13 +24595,13 @@ var THREAD_SOURCE_KINDS = /* @__PURE__ */ new Set([
24097
24595
  "subAgentOther",
24098
24596
  "unknown"
24099
24597
  ]);
24100
- function isRecord7(value2) {
24598
+ function isRecord8(value2) {
24101
24599
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
24102
24600
  }
24103
24601
  function paramsObject(request, method) {
24104
24602
  if (request.params === void 0 && method === "thread/list")
24105
24603
  return {};
24106
- if (!isRecord7(request.params))
24604
+ if (!isRecord8(request.params))
24107
24605
  throw new Error(`${method} params must be an object`);
24108
24606
  return request.params;
24109
24607
  }
@@ -24161,7 +24659,7 @@ function decodeSortKey(value2) {
24161
24659
  return value2;
24162
24660
  }
24163
24661
  function queryFingerprint(value2) {
24164
- return createHash2("sha256").update(JSON.stringify(value2)).digest("hex");
24662
+ return createHash4("sha256").update(JSON.stringify(value2)).digest("hex");
24165
24663
  }
24166
24664
  function cursorPayload(value2) {
24167
24665
  return {
@@ -24175,7 +24673,7 @@ function cursorPayload(value2) {
24175
24673
  };
24176
24674
  }
24177
24675
  function parseCursorPayload(value2) {
24178
- if (!isRecord7(value2) || value2.formatVersion !== 1)
24676
+ if (!isRecord8(value2) || value2.formatVersion !== 1)
24179
24677
  throw new Error("Host cursor is invalid");
24180
24678
  const { queryFingerprint: fingerprint, sortDirection: sortDirection2, officialCursor, officialDone } = value2;
24181
24679
  const { externalAnchor: externalAnchor2, externalDone } = value2;
@@ -24184,7 +24682,7 @@ function parseCursorPayload(value2) {
24184
24682
  }
24185
24683
  let anchor = null;
24186
24684
  if (externalAnchor2 !== null) {
24187
- if (!isRecord7(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
24685
+ if (!isRecord8(externalAnchor2) || !Number.isSafeInteger(externalAnchor2.timestamp) || typeof externalAnchor2.threadId !== "string" || externalAnchor2.threadId.length === 0) {
24188
24686
  throw new Error("Host cursor is invalid");
24189
24687
  }
24190
24688
  anchor = {
@@ -24307,7 +24805,7 @@ function decodeThreadMetadataUpdateRequest(request) {
24307
24805
  if (params.gitInfo === null) {
24308
24806
  gitInfo = null;
24309
24807
  } else if (params.gitInfo !== void 0) {
24310
- if (!isRecord7(params.gitInfo)) {
24808
+ if (!isRecord8(params.gitInfo)) {
24311
24809
  throw new Error("thread/metadata/update params.gitInfo must be an object or null");
24312
24810
  }
24313
24811
  gitInfo = {};
@@ -24335,7 +24833,7 @@ function optionalCursor(value2, name) {
24335
24833
  return value2;
24336
24834
  }
24337
24835
  function decodeOfficialThreadListPage(value2) {
24338
- if (!isRecord7(value2) || !Array.isArray(value2.data) || value2.data.some((row) => !isRecord7(row))) {
24836
+ if (!isRecord8(value2) || !Array.isArray(value2.data) || value2.data.some((row) => !isRecord8(row))) {
24339
24837
  throw new Error("Official thread/list response is invalid");
24340
24838
  }
24341
24839
  return {
@@ -25147,22 +25645,22 @@ var HarnessAccountInspectionCache = class {
25147
25645
  };
25148
25646
 
25149
25647
  // packages/host-runtime/src/app-server-host.ts
25150
- import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
25151
- import os3 from "node:os";
25152
- import path12 from "node:path";
25648
+ import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
25649
+ import os5 from "node:os";
25650
+ import path15 from "node:path";
25153
25651
 
25154
25652
  // packages/host-runtime/src/external-thread-fork.ts
25155
25653
  import nodePath from "node:path";
25156
25654
 
25157
25655
  // packages/host-runtime/src/external-thread-repository.ts
25158
- import { randomUUID as randomUUID4 } from "node:crypto";
25159
- import os from "node:os";
25160
- import path7 from "node:path";
25656
+ import { randomUUID as randomUUID5 } from "node:crypto";
25657
+ import os3 from "node:os";
25658
+ import path9 from "node:path";
25161
25659
 
25162
25660
  // packages/host-runtime/src/external-subagent-threads.ts
25163
- import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
25661
+ import { createHash as createHash5, randomUUID as randomUUID4 } from "node:crypto";
25164
25662
  function childCreateRequest(parent, nativeRef, id2) {
25165
- const key = createHash3("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
25663
+ const key = createHash5("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
25166
25664
  return `subagent:${key}`;
25167
25665
  }
25168
25666
  function subagentMaterializer(store, parent, previousParent) {
@@ -25235,7 +25733,7 @@ function subagentMaterializer(store, parent, previousParent) {
25235
25733
  return rebind(existing, parent);
25236
25734
  }
25237
25735
  const provisional = existing ?? await store.createProvisional({
25238
- hostThreadId: hostThreadIdSchema.parse(randomUUID3()),
25736
+ hostThreadId: hostThreadIdSchema.parse(randomUUID4()),
25239
25737
  createRequestId,
25240
25738
  harnessId: parent.harnessId,
25241
25739
  cwd: parent.cwd,
@@ -25297,8 +25795,8 @@ function sameMapping(left, right) {
25297
25795
  }
25298
25796
  function defaultMappingStoreDirectory(environment) {
25299
25797
  const dataDirectory = environment.CODEXHOST_DATA_DIR;
25300
- return path7.join(
25301
- dataDirectory ? path7.resolve(dataDirectory) : path7.join(os.homedir(), ".codexhost"),
25798
+ return path9.join(
25799
+ dataDirectory ? path9.resolve(dataDirectory) : path9.join(os3.homedir(), ".codexhost"),
25302
25800
  "mapping-store"
25303
25801
  );
25304
25802
  }
@@ -25395,7 +25893,7 @@ var ExternalThreadRepository = class {
25395
25893
  throw new Error("Derived Snapshot identity does not belong to its Native Session");
25396
25894
  }
25397
25895
  return {
25398
- hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
25896
+ hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
25399
25897
  nativeTurnRef: turn.nativeTurnRef,
25400
25898
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
25401
25899
  };
@@ -25515,7 +26013,7 @@ var ExternalThreadRepository = class {
25515
26013
  const aligned = snapshot.turns.map((turn) => {
25516
26014
  const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
25517
26015
  const mapping = existing ?? {
25518
- hostTurnId: hostTurnIdSchema.parse(randomUUID4()),
26016
+ hostTurnId: hostTurnIdSchema.parse(randomUUID5()),
25519
26017
  nativeTurnRef: turn.nativeTurnRef,
25520
26018
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
25521
26019
  };
@@ -25542,8 +26040,8 @@ var ExternalThreadRepository = class {
25542
26040
  };
25543
26041
  function createExternalThreadRecordInput(input) {
25544
26042
  return {
25545
- hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID4()),
25546
- createRequestId: input.createRequestId ?? randomUUID4(),
26043
+ hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID5()),
26044
+ createRequestId: input.createRequestId ?? randomUUID5(),
25547
26045
  harnessId: input.harnessId,
25548
26046
  cwd: input.cwd,
25549
26047
  ...input.title ? { title: input.title } : {},
@@ -25704,6 +26202,7 @@ async function executeExternalThreadFork(input) {
25704
26202
  return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
25705
26203
  }
25706
26204
  const session = opened.value;
26205
+ const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
25707
26206
  try {
25708
26207
  const derivedNativeRef = session.initialState.nativeRef;
25709
26208
  if (!derivedNativeRef || derivedNativeRef.nativeSessionId === nativeSessionRef.nativeSessionId) {
@@ -25731,7 +26230,8 @@ async function executeExternalThreadFork(input) {
25731
26230
  sessionId: source.sessionId,
25732
26231
  thread,
25733
26232
  turns: aligned.turns,
25734
- ...snapshot.value.state ? { restoredState: snapshot.value.state } : {}
26233
+ ...snapshot.value.state ? { restoredState: snapshot.value.state } : {},
26234
+ ...inheritedPermissionModeId ? { requestedPermissionModeId: inheritedPermissionModeId } : {}
25735
26235
  });
25736
26236
  return {
25737
26237
  ok: true,
@@ -25749,6 +26249,23 @@ async function executeExternalThreadFork(input) {
25749
26249
  };
25750
26250
  }
25751
26251
  }
26252
+ async function inheritSourcePermissionMode(source, session) {
26253
+ const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
26254
+ if (!sourceModeId) return void 0;
26255
+ const configuration = session.capabilities.configuration;
26256
+ if (!configuration.selectPermissionMode || permissionModeFixedAtCreate(configuration)) {
26257
+ return void 0;
26258
+ }
26259
+ try {
26260
+ const selected = await session.execute({
26261
+ type: "permissionMode.select",
26262
+ permissionModeId: sourceModeId
26263
+ });
26264
+ return selected.ok ? sourceModeId : void 0;
26265
+ } catch {
26266
+ return void 0;
26267
+ }
26268
+ }
25752
26269
 
25753
26270
  // packages/host-runtime/src/harness-session-import.ts
25754
26271
  function fixedError(code, message) {
@@ -27313,9 +27830,12 @@ var ExternalTurnSteering = class {
27313
27830
  if (!cancelled.ok) throw new ExternalSteerError(-32074, cancelled.error.message);
27314
27831
  const outcome = await Promise.race([terminal2.promise, failure.promise]);
27315
27832
  clearTimeout(timeout);
27316
- if (failureReason) throw failureReason;
27317
- if (this.#closed)
27318
- throw new ExternalSteerError(-32074, "External steering connection is closed");
27833
+ const assertActive = () => {
27834
+ if (failureReason) throw failureReason;
27835
+ if (this.#closed)
27836
+ throw new ExternalSteerError(-32074, "External steering connection is closed");
27837
+ };
27838
+ assertActive();
27319
27839
  if (outcome.status === "failed") throw new ExternalSteerError(-32074, outcome.error.message);
27320
27840
  if (thread.persistenceError)
27321
27841
  throw new ExternalSteerError(
@@ -27325,7 +27845,7 @@ var ExternalTurnSteering = class {
27325
27845
  if (thread.running || thread.activeTurnId) {
27326
27846
  throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
27327
27847
  }
27328
- return await start(input.text);
27848
+ return await start(input.text, assertActive);
27329
27849
  } finally {
27330
27850
  clearTimeout(timeout);
27331
27851
  if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
@@ -27333,16 +27853,98 @@ var ExternalTurnSteering = class {
27333
27853
  }
27334
27854
  };
27335
27855
 
27856
+ // packages/host-runtime/src/external-command-routing.ts
27857
+ var ExternalCommandError = class extends Error {
27858
+ constructor(code, message) {
27859
+ super(message);
27860
+ this.code = code;
27861
+ }
27862
+ code;
27863
+ };
27864
+ function isExternalCommandCandidate(text) {
27865
+ return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
27866
+ }
27867
+ async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
27868
+ let timeout;
27869
+ try {
27870
+ const result = await Promise.race([
27871
+ commands.list(),
27872
+ new Promise((resolve) => {
27873
+ timeout = setTimeout(() => resolve(null), timeoutMs);
27874
+ })
27875
+ ]);
27876
+ return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
27877
+ } catch {
27878
+ return null;
27879
+ } finally {
27880
+ if (timeout !== void 0) clearTimeout(timeout);
27881
+ }
27882
+ }
27883
+ async function resolveExternalCommand(commands, text, options2 = {}) {
27884
+ const catalog = await commands.list();
27885
+ if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
27886
+ const commandText = text.trim();
27887
+ const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
27888
+ if (commandText === command.invocation) return true;
27889
+ return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
27890
+ });
27891
+ if (!matched) {
27892
+ const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
27893
+ if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
27894
+ return null;
27895
+ }
27896
+ throw new ExternalCommandError(
27897
+ -32078,
27898
+ "External Harness does not expose the requested command"
27899
+ );
27900
+ }
27901
+ const argumentText = commandText.slice(matched.invocation.length).trimStart();
27902
+ return {
27903
+ commandId: matched.id,
27904
+ ...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
27905
+ };
27906
+ }
27907
+
27908
+ // packages/host-runtime/src/live-command-catalog-cache.ts
27909
+ import path10 from "node:path";
27910
+ var MAX_ENTRIES = 64;
27911
+ function isLiveCommandCatalog(catalog, staticCatalog) {
27912
+ const staticIds = new Set(staticCatalog.commands.map(({ id: id2 }) => id2));
27913
+ return catalog.commands.some(({ id: id2 }) => !staticIds.has(id2));
27914
+ }
27915
+ var LiveCommandCatalogCache = class {
27916
+ #entries = /* @__PURE__ */ new Map();
27917
+ #key(harnessId, cwd) {
27918
+ return `${harnessId}\0${path10.resolve(cwd)}`;
27919
+ }
27920
+ remember(harnessId, cwd, catalog) {
27921
+ const key = this.#key(harnessId, cwd);
27922
+ this.#entries.delete(key);
27923
+ this.#entries.set(key, catalog);
27924
+ while (this.#entries.size > MAX_ENTRIES) {
27925
+ const oldest = this.#entries.keys().next().value;
27926
+ if (oldest === void 0) break;
27927
+ this.#entries.delete(oldest);
27928
+ }
27929
+ }
27930
+ lookup(harnessId, cwd) {
27931
+ return this.#entries.get(this.#key(harnessId, cwd));
27932
+ }
27933
+ };
27934
+ function sameWorkspace(left, right) {
27935
+ return path10.resolve(left) === path10.resolve(right);
27936
+ }
27937
+
27336
27938
  // packages/host-runtime/src/harness-delegation-coordinator.ts
27337
- import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
27338
- import path8 from "node:path";
27939
+ import { createHash as createHash7, randomUUID as randomUUID6 } from "node:crypto";
27940
+ import path11 from "node:path";
27339
27941
 
27340
27942
  // packages/host-runtime/src/delegation-snapshot.ts
27341
- import { createHash as createHash4 } from "node:crypto";
27943
+ import { createHash as createHash6 } from "node:crypto";
27342
27944
  var CURSOR_PREFIX = "codexhost:thread-messages:v1:";
27343
27945
  var DEFAULT_MESSAGE_LIMIT = 25;
27344
27946
  var MAX_MESSAGE_LIMIT = 100;
27345
- function isRecord8(value2) {
27947
+ function isRecord9(value2) {
27346
27948
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
27347
27949
  }
27348
27950
  function stringValue(value2) {
@@ -27351,12 +27953,12 @@ function stringValue(value2) {
27351
27953
  function textFromUserItem(item) {
27352
27954
  if (!Array.isArray(item.content)) return "";
27353
27955
  return item.content.flatMap(
27354
- (part) => isRecord8(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []
27956
+ (part) => isRecord9(part) && part.type === "text" && typeof part.text === "string" ? [part.text] : []
27355
27957
  ).join("\n");
27356
27958
  }
27357
27959
  function threadStatus(value2, running) {
27358
27960
  if (running) return "running";
27359
- if (isRecord8(value2)) {
27961
+ if (isRecord9(value2)) {
27360
27962
  if (value2.type === "active") return "running";
27361
27963
  }
27362
27964
  return "completed";
@@ -27373,10 +27975,10 @@ function allVisibleMessages(turns) {
27373
27975
  const turnId = stringValue(turn.id);
27374
27976
  if (!turnId || !Array.isArray(turn.items)) continue;
27375
27977
  const agentItems = turn.items.filter(
27376
- (item) => isRecord8(item) && item.type === "agentMessage"
27978
+ (item) => isRecord9(item) && item.type === "agentMessage"
27377
27979
  );
27378
27980
  for (const item of turn.items) {
27379
- if (!isRecord8(item)) continue;
27981
+ if (!isRecord9(item)) continue;
27380
27982
  const id2 = stringValue(item.id);
27381
27983
  if (!id2) continue;
27382
27984
  if (item.type === "userMessage") {
@@ -27392,7 +27994,7 @@ function allVisibleMessages(turns) {
27392
27994
  return messages;
27393
27995
  }
27394
27996
  function cursorFingerprint(threadId2) {
27395
- return createHash4("sha256").update(threadId2).digest("hex");
27997
+ return createHash6("sha256").update(threadId2).digest("hex");
27396
27998
  }
27397
27999
  function encodeCursor(threadId2, offset) {
27398
28000
  const payload = JSON.stringify({ version: 1, fingerprint: cursorFingerprint(threadId2), offset });
@@ -27451,7 +28053,7 @@ function projectDelegationThreadSnapshot(input) {
27451
28053
  const progress = latestTurnMessages.filter((message) => message.phase !== "final" && message.text.trim()).map(({ id: id2, turnId, text }) => ({ id: id2, turnId, text }));
27452
28054
  const result = input.running ? { availability: "pending" } : final ? { availability: "available", text: final.text } : {
27453
28055
  availability: "unavailable",
27454
- ...isRecord8(latestTurn?.error) && typeof latestTurn.error.message === "string" ? { message: latestTurn.error.message } : {}
28056
+ ...isRecord9(latestTurn?.error) && typeof latestTurn.error.message === "string" ? { message: latestTurn.error.message } : {}
27455
28057
  };
27456
28058
  const offset = options2.view === "messages" ? decodeCursor(input.threadId, options2.cursor) : visible.length;
27457
28059
  const page = options2.view === "messages" ? [] : void 0;
@@ -27487,10 +28089,10 @@ function terminal(status) {
27487
28089
  return status === "completed" || status === "failed" || status === "interrupted";
27488
28090
  }
27489
28091
  function taskDigest(input) {
27490
- return createHash5("sha256").update(
28092
+ return createHash7("sha256").update(
27491
28093
  JSON.stringify({
27492
28094
  task: input.task,
27493
- cwd: path8.resolve(input.cwd),
28095
+ cwd: path11.resolve(input.cwd),
27494
28096
  modelId: input.model?.id ?? null,
27495
28097
  thinkingOptionId: input.thinkingOptionId ?? null
27496
28098
  })
@@ -27561,7 +28163,7 @@ var HarnessDelegationCoordinator = class {
27561
28163
  return {
27562
28164
  harnessId: input.harnessId,
27563
28165
  inspection: await adapter.inspect({
27564
- ...input.cwd ? { cwd: path8.resolve(input.cwd) } : {},
28166
+ ...input.cwd ? { cwd: path11.resolve(input.cwd) } : {},
27565
28167
  ...input.refresh !== void 0 ? { refresh: input.refresh } : {}
27566
28168
  })
27567
28169
  };
@@ -27575,7 +28177,7 @@ var HarnessDelegationCoordinator = class {
27575
28177
  const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
27576
28178
  return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
27577
28179
  }
27578
- const startInput = { ...input, parentThreadId, cwd: path8.resolve(selectedCwd) };
28180
+ const startInput = { ...input, parentThreadId, cwd: path11.resolve(selectedCwd) };
27579
28181
  if (!this.#adapters.has(input.harnessId)) {
27580
28182
  throw new DelegationControlError(
27581
28183
  "HARNESS_NOT_FOUND",
@@ -27615,10 +28217,10 @@ var HarnessDelegationCoordinator = class {
27615
28217
  });
27616
28218
  this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
27617
28219
  }
27618
- const delegationId = hostThreadIdSchema.parse(randomUUID5());
27619
- const childThreadId = hostThreadIdSchema.parse(randomUUID5());
27620
- const turnId = hostTurnIdSchema.parse(randomUUID5());
27621
- const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID5();
28220
+ const delegationId = hostThreadIdSchema.parse(randomUUID6());
28221
+ const childThreadId = hostThreadIdSchema.parse(randomUUID6());
28222
+ const turnId = hostTurnIdSchema.parse(randomUUID6());
28223
+ const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID6();
27622
28224
  let record3 = await this.#repository.createProvisional(
27623
28225
  createExternalThreadRecordInput({
27624
28226
  hostThreadId: childThreadId,
@@ -27750,7 +28352,7 @@ var HarnessDelegationCoordinator = class {
27750
28352
  if (thread.running || thread.activeTurnId) {
27751
28353
  throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
27752
28354
  }
27753
- const turnId = hostTurnIdSchema.parse(randomUUID5());
28355
+ const turnId = hostTurnIdSchema.parse(randomUUID6());
27754
28356
  try {
27755
28357
  await this.#startExternalTurn(thread, input.message, turnId);
27756
28358
  } catch (error51) {
@@ -28004,7 +28606,7 @@ var HarnessDelegationCoordinator = class {
28004
28606
 
28005
28607
  // packages/host-runtime/src/harness-plugin-loader.ts
28006
28608
  import { readdir as readdir3, realpath as realpath2 } from "node:fs/promises";
28007
- import path10 from "node:path";
28609
+ import path13 from "node:path";
28008
28610
  import { pathToFileURL } from "node:url";
28009
28611
 
28010
28612
  // packages/host-runtime/src/harness-plugin-registry.ts
@@ -28041,25 +28643,25 @@ var HarnessPluginRegistry = class {
28041
28643
  };
28042
28644
 
28043
28645
  // packages/host-runtime/src/plugin-files.ts
28044
- import { open as open4, realpath, stat as stat2 } from "node:fs/promises";
28045
- import path9 from "node:path";
28646
+ import { open as open5, realpath, stat as stat3 } from "node:fs/promises";
28647
+ import path12 from "node:path";
28046
28648
  function inside(root, candidate) {
28047
- const relative = path9.relative(root, candidate);
28048
- return relative !== "" && !path9.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path9.sep}`);
28649
+ const relative = path12.relative(root, candidate);
28650
+ return relative !== "" && !path12.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path12.sep}`);
28049
28651
  }
28050
28652
  async function pluginResourcePath(root, relative) {
28051
- if (path9.isAbsolute(relative) || !inside(root, path9.resolve(root, relative))) {
28653
+ if (path12.isAbsolute(relative) || !inside(root, path12.resolve(root, relative))) {
28052
28654
  throw new Error("Plugin resource escapes its root");
28053
28655
  }
28054
- const resolved = await realpath(path9.resolve(root, relative));
28055
- if (!inside(root, resolved) || !(await stat2(resolved)).isFile()) {
28656
+ const resolved = await realpath(path12.resolve(root, relative));
28657
+ if (!inside(root, resolved) || !(await stat3(resolved)).isFile()) {
28056
28658
  throw new Error("Plugin resource must be a regular file inside its root");
28057
28659
  }
28058
28660
  return resolved;
28059
28661
  }
28060
28662
  async function readPluginFile(file2, maximum) {
28061
- if (!(await stat2(file2)).isFile()) throw new Error("Plugin resource is not a regular file");
28062
- const handle = await open4(file2, "r");
28663
+ if (!(await stat3(file2)).isFile()) throw new Error("Plugin resource is not a regular file");
28664
+ const handle = await open5(file2, "r");
28063
28665
  try {
28064
28666
  const info = await handle.stat();
28065
28667
  if (!info.isFile() || info.size > maximum) throw new Error("Plugin resource exceeds its limit");
@@ -28213,7 +28815,7 @@ async function loadHarnessPlugins(options2) {
28213
28815
  const enabledIds = /* @__PURE__ */ new Set();
28214
28816
  const roots = /* @__PURE__ */ new Set();
28215
28817
  for (const configuredRoot of options2.roots) {
28216
- if (!path10.isAbsolute(configuredRoot)) {
28818
+ if (!path13.isAbsolute(configuredRoot)) {
28217
28819
  diagnose({ code: "invalidRoot" });
28218
28820
  continue;
28219
28821
  }
@@ -28243,7 +28845,7 @@ async function loadHarnessPlugins(options2) {
28243
28845
  for (const directory of directories) {
28244
28846
  try {
28245
28847
  const file2 = await pluginResourcePath(root, `${directory.name}/manifest.json`);
28246
- const pluginRoot = await realpath2(path10.join(root, directory.name));
28848
+ const pluginRoot = await realpath2(path13.join(root, directory.name));
28247
28849
  await pluginResourcePath(pluginRoot, "manifest.json");
28248
28850
  const manifest = harnessPluginManifestSchema.parse(
28249
28851
  JSON.parse(
@@ -28338,28 +28940,28 @@ async function loadHarnessPlugins(options2) {
28338
28940
  }
28339
28941
 
28340
28942
  // packages/host-runtime/src/harness-launch-settings.ts
28341
- import { randomUUID as randomUUID6 } from "node:crypto";
28342
- import { mkdir as mkdir4, readFile as readFile5, rename as rename3, rm as rm4, stat as stat3, writeFile as writeFile3 } from "node:fs/promises";
28343
- import os2 from "node:os";
28344
- import path11 from "node:path";
28943
+ import { randomUUID as randomUUID7 } from "node:crypto";
28944
+ import { mkdir as mkdir5, readFile as readFile7, rename as rename4, rm as rm5, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
28945
+ import os4 from "node:os";
28946
+ import path14 from "node:path";
28345
28947
  var HarnessLaunchSettingsStore = class {
28346
28948
  #directory;
28347
28949
  #initial = /* @__PURE__ */ new Map();
28348
28950
  constructor(environment) {
28349
- this.#directory = path11.join(
28350
- environment.CODEXHOST_DATA_DIR ? path11.resolve(environment.CODEXHOST_DATA_DIR) : path11.join(os2.homedir(), ".codexhost"),
28951
+ this.#directory = path14.join(
28952
+ environment.CODEXHOST_DATA_DIR ? path14.resolve(environment.CODEXHOST_DATA_DIR) : path14.join(os4.homedir(), ".codexhost"),
28351
28953
  "harness-launch-settings"
28352
28954
  );
28353
28955
  }
28354
28956
  #file(id2) {
28355
- return path11.join(this.#directory, `${harnessPluginIdSchema.parse(id2)}.json`);
28957
+ return path14.join(this.#directory, `${harnessPluginIdSchema.parse(id2)}.json`);
28356
28958
  }
28357
28959
  async #read(id2) {
28358
28960
  try {
28359
28961
  const value2 = harnessLaunchPathSchema.parse(
28360
- JSON.parse(await readFile5(this.#file(id2), "utf8"))
28962
+ JSON.parse(await readFile7(this.#file(id2), "utf8"))
28361
28963
  );
28362
- if (!path11.isAbsolute(value2)) throw new Error("Expected an absolute entrypoint path");
28964
+ if (!path14.isAbsolute(value2)) throw new Error("Expected an absolute entrypoint path");
28363
28965
  return value2;
28364
28966
  } catch (error51) {
28365
28967
  if (error51 && typeof error51 === "object" && "code" in error51 && error51.code === "ENOENT")
@@ -28385,22 +28987,22 @@ var HarnessLaunchSettingsStore = class {
28385
28987
  const initial = await this.initialCommand(id2) ?? null;
28386
28988
  const file2 = this.#file(id2);
28387
28989
  if (value2 === null) {
28388
- await rm4(file2, { force: true });
28990
+ await rm5(file2, { force: true });
28389
28991
  } else {
28390
28992
  value2 = harnessLaunchPathSchema.parse(value2);
28391
- if (!path11.isAbsolute(value2))
28993
+ if (!path14.isAbsolute(value2))
28392
28994
  throw new Error("Use an absolute entrypoint path without arguments");
28393
- const metadata = await stat3(value2).catch(() => void 0);
28995
+ const metadata = await stat4(value2).catch(() => void 0);
28394
28996
  if (!metadata?.isDirectory() && !metadata?.isFile())
28395
28997
  throw new Error("The installation path must be an existing directory on this Host");
28396
- await mkdir4(this.#directory, { recursive: true, mode: 448 });
28397
- const temporary = `${file2}.${randomUUID6()}.tmp`;
28998
+ await mkdir5(this.#directory, { recursive: true, mode: 448 });
28999
+ const temporary = `${file2}.${randomUUID7()}.tmp`;
28398
29000
  try {
28399
29001
  await writeFile3(temporary, `${JSON.stringify(value2)}
28400
29002
  `, { mode: 384, flag: "wx" });
28401
- await rename3(temporary, file2);
29003
+ await rename4(temporary, file2);
28402
29004
  } finally {
28403
- await rm4(temporary, { force: true });
29005
+ await rm5(temporary, { force: true });
28404
29006
  }
28405
29007
  }
28406
29008
  return { path: value2, restartRequired: value2 !== initial };
@@ -28563,11 +29165,11 @@ function spawnOfficialAppServerConnection(input) {
28563
29165
  }
28564
29166
 
28565
29167
  // packages/host-runtime/src/account/codex-account-control.ts
28566
- function isRecord9(value2) {
29168
+ function isRecord10(value2) {
28567
29169
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
28568
29170
  }
28569
29171
  function currentCodexAccountFromOfficialRead(result) {
28570
- if (!isRecord9(result) || !isRecord9(result.account) || result.account.type !== "chatgpt") {
29172
+ if (!isRecord10(result) || !isRecord10(result.account) || result.account.type !== "chatgpt") {
28571
29173
  return null;
28572
29174
  }
28573
29175
  const email3 = external_exports.string().email().max(320).safeParse(result.account.email);
@@ -28597,13 +29199,13 @@ var SingleNativeCodexAccount = class {
28597
29199
  };
28598
29200
 
28599
29201
  // packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
28600
- import { randomUUID as randomUUID8 } from "node:crypto";
29202
+ import { randomUUID as randomUUID9 } from "node:crypto";
28601
29203
 
28602
29204
  // packages/host-runtime/src/official-request-broker.ts
28603
- import { randomUUID as randomUUID7 } from "node:crypto";
29205
+ import { randomUUID as randomUUID8 } from "node:crypto";
28604
29206
  var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
28605
29207
  var MAX_RETIRED_IDS = 1024;
28606
- function isRecord10(value2) {
29208
+ function isRecord11(value2) {
28607
29209
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
28608
29210
  }
28609
29211
  var OfficialRequestBroker = class {
@@ -28616,7 +29218,7 @@ var OfficialRequestBroker = class {
28616
29218
  constructor(input) {
28617
29219
  this.#send = input.send;
28618
29220
  this.#timeoutMs = input.timeoutMs ?? 3e4;
28619
- this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID7()}`);
29221
+ this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID8()}`);
28620
29222
  }
28621
29223
  get pendingCount() {
28622
29224
  return this.#pending.size;
@@ -28646,7 +29248,7 @@ var OfficialRequestBroker = class {
28646
29248
  });
28647
29249
  }
28648
29250
  handle(value2) {
28649
- if (!isRecord10(value2) || typeof value2.id !== "string") return false;
29251
+ if (!isRecord11(value2) || typeof value2.id !== "string") return false;
28650
29252
  const pending = this.#pending.get(value2.id);
28651
29253
  if (!pending) return this.#retired.has(value2.id);
28652
29254
  clearTimeout(pending.timeout);
@@ -28970,7 +29572,7 @@ var OfficialRuntimeOwner = class {
28970
29572
  }
28971
29573
  #attach(role, output, onBackendStopped) {
28972
29574
  const client = {
28973
- id: randomUUID8(),
29575
+ id: randomUUID9(),
28974
29576
  role,
28975
29577
  output,
28976
29578
  ...onBackendStopped ? { onBackendStopped } : {},
@@ -29128,7 +29730,7 @@ var OfficialRuntimeOwner = class {
29128
29730
  if (!object4(value2)) return client.output(event);
29129
29731
  if (typeof value2.id === "string" || typeof value2.id === "number") {
29130
29732
  if (typeof value2.method === "string") {
29131
- const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID8()}`;
29733
+ const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID9()}`;
29132
29734
  client.serverRequests.set(id2, value2.id);
29133
29735
  const projected = { ...value2, id: id2 };
29134
29736
  return client.output({
@@ -29366,11 +29968,11 @@ function createOwnedConnectionBackend(factory) {
29366
29968
  }
29367
29969
 
29368
29970
  // packages/host-runtime/src/route-observation.ts
29369
- function isRecord11(value2) {
29971
+ function isRecord12(value2) {
29370
29972
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
29371
29973
  }
29372
29974
  function classifyThreadPurpose(request) {
29373
- return isRecord11(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
29975
+ return isRecord12(request.params) && request.params.ephemeral === true ? "ephemeral" : "conversation";
29374
29976
  }
29375
29977
  var RequestRouteObservationTracker = class {
29376
29978
  #nextCreateOrdinal = 0;
@@ -29395,13 +29997,13 @@ var RequestRouteObservationTracker = class {
29395
29997
  this.#createByThreadId.set(threadId2, tracked);
29396
29998
  }
29397
29999
  bindOfficialResponse(response) {
29398
- if (!isRecord11(response) || !("id" in response)) return;
30000
+ if (!isRecord12(response) || !("id" in response)) return;
29399
30001
  const tracked = this.#pendingByRequestId.get(response.id);
29400
30002
  if (!tracked) return;
29401
30003
  this.#pendingByRequestId.delete(response.id);
29402
30004
  const result = response.result;
29403
- const thread = isRecord11(result) ? result.thread : null;
29404
- if (isRecord11(thread) && typeof thread.id === "string") {
30005
+ const thread = isRecord12(result) ? result.thread : null;
30006
+ if (isRecord12(thread) && typeof thread.id === "string") {
29405
30007
  this.#createByThreadId.set(thread.id, tracked);
29406
30008
  }
29407
30009
  }
@@ -29523,25 +30125,25 @@ function resolveExternalSessionTreeIds(records) {
29523
30125
  const resolve = (start) => {
29524
30126
  const cached2 = resolved.get(start.hostThreadId);
29525
30127
  if (cached2) return cached2;
29526
- const path26 = [];
30128
+ const path28 = [];
29527
30129
  const visited = /* @__PURE__ */ new Set();
29528
30130
  let current = start;
29529
30131
  while (true) {
29530
30132
  const known = resolved.get(current.hostThreadId);
29531
30133
  if (known) {
29532
- for (const record3 of path26) resolved.set(record3.hostThreadId, known);
30134
+ for (const record3 of path28) resolved.set(record3.hostThreadId, known);
29533
30135
  return known;
29534
30136
  }
29535
30137
  if (visited.has(current.hostThreadId)) {
29536
30138
  throw new Error("External Thread Fork tree contains a cycle");
29537
30139
  }
29538
30140
  visited.add(current.hostThreadId);
29539
- path26.push(current);
30141
+ path28.push(current);
29540
30142
  const sourceId = current.subagent?.parentHostThreadId ?? current.forkSource?.hostThreadId;
29541
30143
  const source = sourceId ? byId.get(sourceId) : void 0;
29542
30144
  if (!source) {
29543
30145
  const root = current.hostThreadId;
29544
- for (const record3 of path26) resolved.set(record3.hostThreadId, root);
30146
+ for (const record3 of path28) resolved.set(record3.hostThreadId, root);
29545
30147
  return root;
29546
30148
  }
29547
30149
  current = source;
@@ -29595,11 +30197,11 @@ var OfficialThreadListError = class extends Error {
29595
30197
  }
29596
30198
  rpcError;
29597
30199
  };
29598
- function isRecord12(value2) {
30200
+ function isRecord13(value2) {
29599
30201
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
29600
30202
  }
29601
30203
  function officialThreadListPageFromResponse(response) {
29602
- if (isRecord12(response.error)) {
30204
+ if (isRecord13(response.error)) {
29603
30205
  if (!Number.isSafeInteger(response.error.code) || typeof response.error.message !== "string") {
29604
30206
  throw new Error("Official thread/list error response is invalid");
29605
30207
  }
@@ -29767,14 +30369,14 @@ var THREAD_USAGE_UPDATED_METHOD = "codexhost/thread/usage/updated";
29767
30369
  function delay3(milliseconds) {
29768
30370
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
29769
30371
  }
29770
- function isRecord13(value2) {
30372
+ function isRecord14(value2) {
29771
30373
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
29772
30374
  }
29773
30375
  function isCreditsAdapter(adapter) {
29774
30376
  return typeof adapter.credits === "function";
29775
30377
  }
29776
30378
  function projectAccountCredits(value2) {
29777
- if (!isRecord13(value2)) return null;
30379
+ if (!isRecord14(value2)) return null;
29778
30380
  const rest = { ...value2 };
29779
30381
  delete rest.fetchedAt;
29780
30382
  const parsed = accountCreditsSnapshotSchema.safeParse(rest);
@@ -29897,12 +30499,12 @@ function classifyCreateRequestRoute(request, defaultAgent) {
29897
30499
  };
29898
30500
  }
29899
30501
  function requestObject(request) {
29900
- if (!isRecord13(request.params)) throw new Error(`${request.method} params must be an object`);
30502
+ if (!isRecord14(request.params)) throw new Error(`${request.method} params must be an object`);
29901
30503
  return request.params;
29902
30504
  }
29903
30505
  function requestText(params) {
29904
30506
  if (!Array.isArray(params.input)) throw new Error("turn/start input must be an array");
29905
- const text = params.input.filter((item) => isRecord13(item) && item.type === "text").map((item) => item.text).filter((value2) => typeof value2 === "string").join("\n");
30507
+ const text = params.input.filter((item) => isRecord14(item) && item.type === "text").map((item) => item.text).filter((value2) => typeof value2 === "string").join("\n");
29906
30508
  if (!text) throw new Error("turn/start must contain text input");
29907
30509
  return text;
29908
30510
  }
@@ -29956,6 +30558,7 @@ var AppServerHost = class {
29956
30558
  #accountInspections = new HarnessAccountInspectionCache();
29957
30559
  #externalRuntime;
29958
30560
  #externalSteering = new ExternalTurnSteering();
30561
+ #liveCommandCache = new LiveCommandCatalogCache();
29959
30562
  #repository;
29960
30563
  #pendingDesktopApprovals = /* @__PURE__ */ new Map();
29961
30564
  #pendingDesktopQuestions = /* @__PURE__ */ new Map();
@@ -29997,7 +30600,7 @@ var AppServerHost = class {
29997
30600
  this.#launchSettings = new HarnessLaunchSettingsStore(
29998
30601
  this.#options.pluginContext?.environment ?? environment
29999
30602
  );
30000
- const permanentHome = path12.resolve(environment.CODEX_HOME ?? path12.join(os3.homedir(), ".codex"));
30603
+ const permanentHome = path15.resolve(environment.CODEX_HOME ?? path15.join(os5.homedir(), ".codex"));
30001
30604
  this.#ownsOfficialRuntimeScope = options2.officialRuntimeScope === void 0;
30002
30605
  this.#officialRuntimeScope = options2.officialRuntimeScope ?? new OfficialRuntimeScope({
30003
30606
  diagnosticOutput: this.#options.diagnosticOutput,
@@ -30010,7 +30613,8 @@ var AppServerHost = class {
30010
30613
  ...officialEnvironment(environment),
30011
30614
  CODEX_HOME: permanentHome
30012
30615
  },
30013
- ...this.#options.spawnOfficial ? { spawnOfficial: this.#options.spawnOfficial } : {}
30616
+ ...this.#options.spawnOfficial ? { spawnOfficial: this.#options.spawnOfficial } : {},
30617
+ ...this.#options.officialCloseTimeoutMs === void 0 ? {} : { closeTimeoutMs: this.#options.officialCloseTimeoutMs }
30014
30618
  })
30015
30619
  )
30016
30620
  });
@@ -30258,12 +30862,12 @@ var AppServerHost = class {
30258
30862
  for (const resolve of waiters) resolve();
30259
30863
  }
30260
30864
  #observeOfficialTurnStartResponse(value2) {
30261
- if (!isRecord13(value2) || !("id" in value2)) return;
30865
+ if (!isRecord14(value2) || !("id" in value2)) return;
30262
30866
  const threadId2 = this.#pendingOfficialTurnStarts.get(value2.id);
30263
30867
  if (!threadId2) return;
30264
30868
  this.#pendingOfficialTurnStarts.delete(value2.id);
30265
- const result = isRecord13(value2.result) ? value2.result : null;
30266
- const turn = result && isRecord13(result.turn) ? result.turn : null;
30869
+ const result = isRecord14(value2.result) ? value2.result : null;
30870
+ const turn = result && isRecord14(result.turn) ? result.turn : null;
30267
30871
  if (turn && typeof turn.id === "string") {
30268
30872
  this.#activeOfficialTurns.set(threadId2, turn.id);
30269
30873
  }
@@ -30277,7 +30881,7 @@ var AppServerHost = class {
30277
30881
  async #forwardDesktop() {
30278
30882
  for await (const frame of readLfFrames(this.#options.desktopInput)) {
30279
30883
  const parsed = parseJsonFrame(frame);
30280
- if (isRecord13(parsed) && parsed.method === "initialized" && !("id" in parsed)) {
30884
+ if (isRecord14(parsed) && parsed.method === "initialized" && !("id" in parsed)) {
30281
30885
  continue;
30282
30886
  }
30283
30887
  if (await this.#handleDesktopApprovalResponse(parsed)) continue;
@@ -30301,7 +30905,7 @@ var AppServerHost = class {
30301
30905
  }
30302
30906
  continue;
30303
30907
  }
30304
- const threadId2 = isRecord13(request.params) && typeof request.params.threadId === "string" ? request.params.threadId : void 0;
30908
+ const threadId2 = isRecord14(request.params) && typeof request.params.threadId === "string" ? request.params.threadId : void 0;
30305
30909
  this.#dispatchDesktopRequest(
30306
30910
  () => this.#desktopRequests.run(
30307
30911
  threadId2,
@@ -30346,6 +30950,32 @@ var AppServerHost = class {
30346
30950
  this.#dispatchDesktopRequest(() => this.#handleCodexAccountRequest(request));
30347
30951
  return;
30348
30952
  }
30953
+ if (request.method === CREDENTIAL_IMPORTS_METHOD) {
30954
+ this.#dispatchDesktopRequest(async () => {
30955
+ if (!credentialImportsParamsSchema.safeParse(request.params).success) {
30956
+ await this.#writer.json(rpcError(request, -32602, "Invalid credential import request"));
30957
+ return;
30958
+ }
30959
+ await this.#waitForPlugins();
30960
+ try {
30961
+ const result = await handleCredentialImports(
30962
+ request.params,
30963
+ this.#externalAdapters.values(),
30964
+ this.#options.environment ?? process.env
30965
+ );
30966
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
30967
+ } catch {
30968
+ await this.#writer.json(
30969
+ rpcError(
30970
+ request,
30971
+ -32077,
30972
+ "Credential operation failed. Check the source login, choose an unused Provider name, and verify Pi configuration access."
30973
+ )
30974
+ );
30975
+ }
30976
+ });
30977
+ return;
30978
+ }
30349
30979
  if (request.method === "codexhost/harness/accounts/sources") {
30350
30980
  this.#dispatchDesktopRequest(async () => {
30351
30981
  if (!harnessAccountSourceListParamsSchema.safeParse(request.params).success) {
@@ -30503,7 +31133,7 @@ var AppServerHost = class {
30503
31133
  rpcError(request, -32602, "Invalid Harness command inspection params")
30504
31134
  );
30505
31135
  } else {
30506
- await this.#writeHarnessCommandCatalog(request, params.data.harnessId);
31136
+ await this.#writeHarnessCommandCatalog(request, params.data.harnessId, params.data.cwd);
30507
31137
  }
30508
31138
  return;
30509
31139
  }
@@ -30600,7 +31230,7 @@ var AppServerHost = class {
30600
31230
  return;
30601
31231
  }
30602
31232
  if (request.method === "thread/fork") {
30603
- const params = isRecord13(request.params) ? request.params : {};
31233
+ const params = isRecord14(request.params) ? request.params : {};
30604
31234
  const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30605
31235
  if (resolution.kind === "error") {
30606
31236
  await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
@@ -30621,7 +31251,7 @@ var AppServerHost = class {
30621
31251
  }
30622
31252
  }
30623
31253
  if (request.method === "thread/revert") {
30624
- const params = isRecord13(request.params) ? request.params : {};
31254
+ const params = isRecord14(request.params) ? request.params : {};
30625
31255
  const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30626
31256
  if (resolution.kind === "error") {
30627
31257
  await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
@@ -30642,7 +31272,7 @@ var AppServerHost = class {
30642
31272
  }
30643
31273
  }
30644
31274
  if (request.method === "thread/rollback") {
30645
- const params = isRecord13(request.params) ? request.params : {};
31275
+ const params = isRecord14(request.params) ? request.params : {};
30646
31276
  const resolution = typeof params.threadId === "string" ? await this.#resolveExternalThread(params.threadId) : { kind: "official" };
30647
31277
  if (resolution.kind === "error") {
30648
31278
  await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
@@ -30798,7 +31428,7 @@ var AppServerHost = class {
30798
31428
  return;
30799
31429
  }
30800
31430
  }
30801
- if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord13(request.params) && typeof request.params.threadId === "string") {
31431
+ if (request.method.startsWith("thread/") && !EXPLICIT_EXTERNAL_THREAD_METHODS.has(request.method) && isRecord14(request.params) && typeof request.params.threadId === "string") {
30802
31432
  const location = await this.#locateExternalThread(request.params.threadId);
30803
31433
  if (await this.#writeResolutionError(request, location)) return;
30804
31434
  if (location.kind === "external") {
@@ -30808,10 +31438,30 @@ var AppServerHost = class {
30808
31438
  return;
30809
31439
  }
30810
31440
  }
30811
- await this.#forwardOfficialRequest(request, frame);
31441
+ await this.#forwardOfficialRequest(
31442
+ request,
31443
+ await this.#rewriteOfficialDelegationMentions(request, frame)
31444
+ );
31445
+ }
31446
+ /** Native Codex Turns: turn `#` delegation chips into an explicit Skill-backed request. */
31447
+ async #rewriteOfficialDelegationMentions(request, frame) {
31448
+ if (request.method !== "turn/start" && request.method !== "turn/steer") return frame;
31449
+ if (!isRecord14(request.params) || !Array.isArray(request.params.input)) return frame;
31450
+ const input = request.params.input;
31451
+ if (!input.some(
31452
+ (item) => isRecord14(item) && typeof item.text === "string" && item.text.includes(DELEGATION_MENTION_PATH_PREFIX)
31453
+ )) {
31454
+ return frame;
31455
+ }
31456
+ const rewritten = rewriteDelegationMentionInput(input, await managedDelegationSkillReference());
31457
+ if (!rewritten) return frame;
31458
+ return encodeJsonFrame({
31459
+ ...request,
31460
+ params: { ...request.params, input: rewritten }
31461
+ });
30812
31462
  }
30813
31463
  async #forwardOfficialNonRequest(value2, frame) {
30814
- const response = isRecord13(value2) ? value2 : null;
31464
+ const response = isRecord14(value2) ? value2 : null;
30815
31465
  const request = response && (typeof response.id === "string" || typeof response.id === "number") ? this.#officialServerRequests.get(response.id) : null;
30816
31466
  if (request !== void 0 && response) {
30817
31467
  this.#officialServerRequests.delete(response.id);
@@ -30840,7 +31490,7 @@ var AppServerHost = class {
30840
31490
  const parsed = input.value;
30841
31491
  this.#observeOfficialTurnStartResponse(parsed);
30842
31492
  let forwarded = parsed;
30843
- if (isRecord13(parsed) && typeof parsed.method === "string" && "id" in parsed) {
31493
+ if (isRecord14(parsed) && typeof parsed.method === "string" && "id" in parsed) {
30844
31494
  const originalId = parsed.id;
30845
31495
  if (typeof originalId === "string" || typeof originalId === "number") {
30846
31496
  const forwardedId = `codexhost:official:${++this.#nextOfficialServerRequestId}`;
@@ -30848,7 +31498,7 @@ var AppServerHost = class {
30848
31498
  forwarded = { ...parsed, id: forwardedId };
30849
31499
  }
30850
31500
  }
30851
- const accountScopedNotification = isRecord13(parsed) && typeof parsed.method === "string" && (parsed.method === "account/updated" || parsed.method.startsWith("account/rateLimits/"));
31501
+ const accountScopedNotification = isRecord14(parsed) && typeof parsed.method === "string" && (parsed.method === "account/updated" || parsed.method.startsWith("account/rateLimits/"));
30852
31502
  if (accountScopedNotification) {
30853
31503
  if (parsed.method === "account/updated") this.#officialRateLimits.reset(input.accountId);
30854
31504
  }
@@ -30917,10 +31567,10 @@ var AppServerHost = class {
30917
31567
  }
30918
31568
  }
30919
31569
  async #observeOfficialTurnLifecycle(value2) {
30920
- if (!isRecord13(value2) || !isRecord13(value2.params)) return;
31570
+ if (!isRecord14(value2) || !isRecord14(value2.params)) return;
30921
31571
  const params = value2.params;
30922
31572
  if (value2.method === "turn/started" && typeof params.threadId === "string") {
30923
- const turn = isRecord13(params.turn) ? params.turn : null;
31573
+ const turn = isRecord14(params.turn) ? params.turn : null;
30924
31574
  if (turn && typeof turn.id === "string") {
30925
31575
  this.#forgetPendingOfficialTurnStarts(params.threadId);
30926
31576
  this.#activeOfficialTurns.set(params.threadId, turn.id);
@@ -30933,7 +31583,7 @@ var AppServerHost = class {
30933
31583
  const delegation = await this.#repository.getDelegationByChild(
30934
31584
  hostThreadIdSchema.parse(params.threadId)
30935
31585
  );
30936
- const turn = isRecord13(params.turn) ? params.turn : null;
31586
+ const turn = isRecord14(params.turn) ? params.turn : null;
30937
31587
  const status = turn?.status === "failed" ? "failed" : turn?.status === "interrupted" || turn?.status === "cancelled" ? "interrupted" : "completed";
30938
31588
  if (this.#pendingOfficialDelegationThreads.has(params.threadId)) {
30939
31589
  this.#pendingOfficialTerminalStatuses.set(params.threadId, status);
@@ -30963,28 +31613,28 @@ var AppServerHost = class {
30963
31613
  }
30964
31614
  async #readOfficialThreadCwd(threadId2) {
30965
31615
  const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
30966
- if (isRecord13(response.error)) return void 0;
30967
- const result = isRecord13(response.result) ? response.result : null;
30968
- const thread = result && isRecord13(result.thread) ? result.thread : null;
31616
+ if (isRecord14(response.error)) return void 0;
31617
+ const result = isRecord14(response.result) ? response.result : null;
31618
+ const thread = result && isRecord14(result.thread) ? result.thread : null;
30969
31619
  return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
30970
31620
  }
30971
31621
  async #inspectOfficialDelegationTarget(input) {
30972
31622
  const response = await this.#requestOfficial("model/list", {});
30973
- if (isRecord13(response.error)) {
31623
+ if (isRecord14(response.error)) {
30974
31624
  throw new DelegationControlError(
30975
31625
  "DELEGATION_FAILED",
30976
31626
  typeof response.error.message === "string" ? response.error.message : "Official Model catalog could not be read"
30977
31627
  );
30978
31628
  }
30979
- const result = isRecord13(response.result) ? response.result : null;
31629
+ const result = isRecord14(response.result) ? response.result : null;
30980
31630
  const data = result && Array.isArray(result.data) ? result.data : [];
30981
31631
  const thinkingById = /* @__PURE__ */ new Map();
30982
31632
  const models = data.flatMap((candidate) => {
30983
- if (!isRecord13(candidate) || typeof candidate.model !== "string" || !candidate.model.trim()) {
31633
+ if (!isRecord14(candidate) || typeof candidate.model !== "string" || !candidate.model.trim()) {
30984
31634
  return [];
30985
31635
  }
30986
31636
  const supportedThinkingOptionIds = Array.isArray(candidate.supportedReasoningEfforts) ? candidate.supportedReasoningEfforts.flatMap((option) => {
30987
- if (!isRecord13(option) || typeof option.reasoningEffort !== "string" || !option.reasoningEffort.trim()) {
31637
+ if (!isRecord14(option) || typeof option.reasoningEffort !== "string" || !option.reasoningEffort.trim()) {
30988
31638
  return [];
30989
31639
  }
30990
31640
  const id2 = harnessThinkingOptionIdSchema.safeParse(option.reasoningEffort);
@@ -31004,9 +31654,9 @@ var AppServerHost = class {
31004
31654
  ];
31005
31655
  });
31006
31656
  const defaultEntry = data.find(
31007
- (candidate) => isRecord13(candidate) && candidate.isDefault === true
31657
+ (candidate) => isRecord14(candidate) && candidate.isDefault === true
31008
31658
  );
31009
- const defaultModel = isRecord13(defaultEntry) && typeof defaultEntry.model === "string" ? encodeOfficialCodexModelRef(defaultEntry.model) : void 0;
31659
+ const defaultModel = isRecord14(defaultEntry) && typeof defaultEntry.model === "string" ? encodeOfficialCodexModelRef(defaultEntry.model) : void 0;
31010
31660
  return {
31011
31661
  harnessId: input.harnessId,
31012
31662
  inspection: {
@@ -31036,7 +31686,7 @@ var AppServerHost = class {
31036
31686
  throw new DelegationControlError("INVALID_ARGUMENT", "Official Model Ref is invalid");
31037
31687
  }
31038
31688
  const nativeModelId = requestedModel ? decodeOfficialCodexModelRef(requestedModel) : void 0;
31039
- const digest2 = createHash6("sha256").update(
31689
+ const digest2 = createHash8("sha256").update(
31040
31690
  JSON.stringify({
31041
31691
  task: input.task,
31042
31692
  cwd: input.cwd,
@@ -31112,8 +31762,8 @@ var AppServerHost = class {
31112
31762
  ephemeral: false,
31113
31763
  historyMode: "paginated"
31114
31764
  });
31115
- const startedResult = isRecord13(started.result) ? started.result : null;
31116
- const thread = startedResult && isRecord13(startedResult.thread) ? startedResult.thread : null;
31765
+ const startedResult = isRecord14(started.result) ? started.result : null;
31766
+ const thread = startedResult && isRecord14(startedResult.thread) ? startedResult.thread : null;
31117
31767
  const threadId2 = thread && typeof thread.id === "string" ? thread.id : null;
31118
31768
  if (!threadId2) throw new Error("Official thread/start returned no Thread identity");
31119
31769
  this.#pendingOfficialDelegationThreads.add(threadId2);
@@ -31125,8 +31775,8 @@ var AppServerHost = class {
31125
31775
  ...nativeModelId ? { model: nativeModelId } : {},
31126
31776
  ...input.thinkingOptionId ? { effort: input.thinkingOptionId } : {}
31127
31777
  });
31128
- const turnResult = isRecord13(turn.result) ? turn.result : null;
31129
- const turnValue = turnResult && isRecord13(turnResult.turn) ? turnResult.turn : null;
31778
+ const turnResult = isRecord14(turn.result) ? turn.result : null;
31779
+ const turnValue = turnResult && isRecord14(turnResult.turn) ? turnResult.turn : null;
31130
31780
  const parsedTurnId = turnValue && typeof turnValue.id === "string" ? turnValue.id : null;
31131
31781
  if (!parsedTurnId) throw new Error("Official turn/start returned no Turn identity");
31132
31782
  turnId = parsedTurnId;
@@ -31137,7 +31787,7 @@ var AppServerHost = class {
31137
31787
  throw error51;
31138
31788
  }
31139
31789
  this.#activeOfficialTurns.set(threadId2, turnId);
31140
- const delegationId = hostThreadIdSchema.parse(randomUUID9());
31790
+ const delegationId = hostThreadIdSchema.parse(randomUUID10());
31141
31791
  try {
31142
31792
  const source = await this.#repository.find(input.parentThreadId);
31143
31793
  const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
@@ -31196,27 +31846,27 @@ var AppServerHost = class {
31196
31846
  threadId: input.threadId,
31197
31847
  includeTurns: true
31198
31848
  });
31199
- if (isRecord13(current.error) || !isRecord13(current.result)) {
31849
+ if (isRecord14(current.error) || !isRecord14(current.result)) {
31200
31850
  throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
31201
31851
  }
31202
- const currentThread = isRecord13(current.result.thread) ? current.result.thread : null;
31852
+ const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
31203
31853
  const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
31204
31854
  const latestTurn = currentTurns.at(-1);
31205
- if (currentThread && isRecord13(currentThread.status) && currentThread.status.type === "active" || isRecord13(latestTurn) && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
31855
+ if (currentThread && isRecord14(currentThread.status) && currentThread.status.type === "active" || isRecord14(latestTurn) && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
31206
31856
  throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
31207
31857
  }
31208
31858
  const response = await this.#requestOfficial("turn/start", {
31209
31859
  threadId: input.threadId,
31210
31860
  input: [{ type: "text", text: input.message }]
31211
31861
  });
31212
- if (isRecord13(response.error)) {
31862
+ if (isRecord14(response.error)) {
31213
31863
  throw new DelegationControlError(
31214
31864
  "DELEGATION_FAILED",
31215
31865
  typeof response.error.message === "string" ? response.error.message : "Turn start failed"
31216
31866
  );
31217
31867
  }
31218
- const result = isRecord13(response.result) ? response.result : null;
31219
- const turn = result && isRecord13(result.turn) ? result.turn : null;
31868
+ const result = isRecord14(response.result) ? response.result : null;
31869
+ const turn = result && isRecord14(result.turn) ? result.turn : null;
31220
31870
  const turnId = turn && typeof turn.id === "string" ? turn.id : null;
31221
31871
  if (!turnId) throw new Error("Official turn/start returned no Turn identity");
31222
31872
  this.#activeOfficialTurns.set(input.threadId, turnId);
@@ -31238,13 +31888,13 @@ var AppServerHost = class {
31238
31888
  threadId: input.threadId,
31239
31889
  includeTurns: true
31240
31890
  });
31241
- if (isRecord13(current.error) || !isRecord13(current.result)) {
31891
+ if (isRecord14(current.error) || !isRecord14(current.result)) {
31242
31892
  throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
31243
31893
  }
31244
- const currentThread = isRecord13(current.result.thread) ? current.result.thread : null;
31894
+ const currentThread = isRecord14(current.result.thread) ? current.result.thread : null;
31245
31895
  const currentTurns = currentThread && Array.isArray(currentThread.turns) ? currentThread.turns : [];
31246
31896
  const latestTurn = currentTurns.at(-1);
31247
- if (isRecord13(latestTurn) && typeof latestTurn.id === "string" && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
31897
+ if (isRecord14(latestTurn) && typeof latestTurn.id === "string" && (latestTurn.status === "inProgress" || latestTurn.status === "running")) {
31248
31898
  turnId = latestTurn.id;
31249
31899
  this.#activeOfficialTurns.set(input.threadId, turnId);
31250
31900
  } else {
@@ -31255,7 +31905,7 @@ var AppServerHost = class {
31255
31905
  threadId: input.threadId,
31256
31906
  turnId
31257
31907
  });
31258
- if (isRecord13(response.error)) {
31908
+ if (isRecord14(response.error)) {
31259
31909
  throw new DelegationControlError(
31260
31910
  "DELEGATION_FAILED",
31261
31911
  typeof response.error.message === "string" ? response.error.message : "Turn cancel failed"
@@ -31268,18 +31918,18 @@ var AppServerHost = class {
31268
31918
  threadId: input.threadId,
31269
31919
  includeTurns: true
31270
31920
  });
31271
- if (isRecord13(response.error)) {
31921
+ if (isRecord14(response.error)) {
31272
31922
  throw new DelegationControlError(
31273
31923
  "THREAD_NOT_FOUND",
31274
31924
  typeof response.error.message === "string" ? response.error.message : "Official Thread was not found"
31275
31925
  );
31276
31926
  }
31277
- const result = isRecord13(response.result) ? response.result : null;
31278
- const thread = result && isRecord13(result.thread) ? result.thread : null;
31927
+ const result = isRecord14(response.result) ? response.result : null;
31928
+ const thread = result && isRecord14(result.thread) ? result.thread : null;
31279
31929
  if (!thread)
31280
31930
  throw new DelegationControlError("THREAD_NOT_FOUND", "Official Thread was not found");
31281
- const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) => isRecord13(turn)) : [];
31282
- const running = this.#activeOfficialTurns.has(input.threadId) || isRecord13(thread.status) && thread.status.type === "active";
31931
+ const turns = Array.isArray(thread.turns) ? thread.turns.filter((turn) => isRecord14(turn)) : [];
31932
+ const running = this.#activeOfficialTurns.has(input.threadId) || isRecord14(thread.status) && thread.status.type === "active";
31283
31933
  const snapshot = projectDelegationThreadSnapshot({
31284
31934
  threadId: input.threadId,
31285
31935
  harnessId: "codex",
@@ -31301,7 +31951,7 @@ var AppServerHost = class {
31301
31951
  async #listDelegationThreads(input) {
31302
31952
  const [sortKey, sortDirection2] = input.sort.split("-");
31303
31953
  const request = {
31304
- id: `codexhost:delegation-list:${randomUUID9()}`,
31954
+ id: `codexhost:delegation-list:${randomUUID10()}`,
31305
31955
  method: "thread/list",
31306
31956
  params: {
31307
31957
  cwd: input.cwd ? [input.cwd] : null,
@@ -31329,7 +31979,7 @@ var AppServerHost = class {
31329
31979
  threads: result.data.flatMap((entry) => {
31330
31980
  if (typeof entry.id !== "string") return [];
31331
31981
  const record3 = records.find((candidate) => candidate.hostThreadId === entry.id);
31332
- const status = isRecord13(entry.status) && entry.status.type === "active" ? "running" : "completed";
31982
+ const status = isRecord14(entry.status) && entry.status.type === "active" ? "running" : "completed";
31333
31983
  return [
31334
31984
  {
31335
31985
  threadId: entry.id,
@@ -31649,21 +32299,67 @@ var AppServerHost = class {
31649
32299
  await this.#writer.json(rpcEnvelope(request, { result: { commands: [] } }));
31650
32300
  return;
31651
32301
  }
31652
- await this.#writeHarnessCommandCatalog(request, location.record.harnessId);
32302
+ const loaded = this.#externalRuntime.get(params.data.threadId);
32303
+ if (loaded) {
32304
+ const catalog = await this.#inspectLoadedCommands(loaded);
32305
+ if (catalog) {
32306
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
32307
+ return;
32308
+ }
32309
+ }
32310
+ await this.#writeHarnessCommandCatalog(
32311
+ request,
32312
+ location.record.harnessId,
32313
+ loaded?.cwd ?? location.record.cwd,
32314
+ params.data.threadId
32315
+ );
31653
32316
  }
31654
- async #writeHarnessCommandCatalog(request, harnessId) {
32317
+ /**
32318
+ * Catalog of a loaded Session, marked live or static. A live catalog is
32319
+ * remembered for its Harness and workspace so later drafts there can show it.
32320
+ */
32321
+ async #inspectLoadedCommands(thread) {
32322
+ if (!thread.session.commands) return null;
32323
+ const catalog = await inspectLiveCommandCatalog(thread.session.commands);
32324
+ if (!catalog) return null;
32325
+ const staticCatalog = this.#externalAdapters.get(thread.harnessId)?.commandCatalog;
32326
+ if (staticCatalog && !isLiveCommandCatalog(catalog, staticCatalog)) return null;
32327
+ const live = { ...catalog, source: "live" };
32328
+ this.#liveCommandCache.remember(thread.harnessId, thread.cwd, live);
32329
+ return live;
32330
+ }
32331
+ async #writeHarnessCommandCatalog(request, harnessId, cwd, inspectedThreadId) {
31655
32332
  await this.#waitForPlugins();
31656
32333
  const adapter = this.#externalAdapters.get(harnessId);
31657
32334
  if (!adapter) {
31658
32335
  await this.#writer.json(rpcError(request, -32077, `Harness '${harnessId}' is unavailable`));
31659
32336
  return;
31660
32337
  }
32338
+ let catalog;
31661
32339
  try {
31662
- const catalog = harnessCommandCatalogSchema.parse(adapter.commandCatalog ?? { commands: [] });
31663
- await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
32340
+ catalog = harnessCommandCatalogSchema.parse({
32341
+ ...adapter.commandCatalog ?? { commands: [] },
32342
+ ...adapter.liveCommandCatalog ? { source: "static" } : {}
32343
+ });
31664
32344
  } catch {
31665
32345
  await this.#writer.json(rpcError(request, -32078, "Harness command catalog is invalid"));
32346
+ return;
31666
32347
  }
32348
+ if (cwd && adapter.liveCommandCatalog) {
32349
+ for (const thread of this.#externalRuntime.values()) {
32350
+ if (thread.id === inspectedThreadId) continue;
32351
+ if (thread.harnessId !== harnessId || !sameWorkspace(thread.cwd, cwd)) continue;
32352
+ const live = await this.#inspectLoadedCommands(thread);
32353
+ if (live) {
32354
+ catalog = live;
32355
+ break;
32356
+ }
32357
+ }
32358
+ if (catalog.source === "static") {
32359
+ catalog = this.#liveCommandCache.lookup(harnessId, cwd) ?? catalog;
32360
+ }
32361
+ }
32362
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(catalog) }));
31667
32363
  }
31668
32364
  async #executeThreadCommand(request) {
31669
32365
  const params = threadCommandExecuteParamsSchema.safeParse(request.params);
@@ -31715,39 +32411,43 @@ var AppServerHost = class {
31715
32411
  return;
31716
32412
  }
31717
32413
  try {
31718
- await this.#startExternalCommand(
31719
- request,
32414
+ const started = await this.#beginExternalCommand(
31720
32415
  thread,
31721
32416
  params.commandId,
31722
32417
  params.arguments,
31723
- params.turnId,
31724
- "command"
32418
+ params.turnId
31725
32419
  );
32420
+ try {
32421
+ const result = threadCommandExecuteResultSchema.parse({
32422
+ accepted: true,
32423
+ turnId: started.turnId
32424
+ });
32425
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
32426
+ } finally {
32427
+ started.gate.resolve();
32428
+ }
31726
32429
  } catch (error51) {
31727
32430
  this.#diagnose(error51);
31728
32431
  await this.#writer.json(
31729
- rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
32432
+ error51 instanceof ExternalCommandError ? rpcError(request, error51.code, error51.message) : rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
31730
32433
  );
31731
32434
  }
31732
32435
  } finally {
31733
32436
  this.#pendingExternalCommandRequests.delete(thread.id);
31734
32437
  }
31735
32438
  }
31736
- async #startExternalCommand(request, thread, commandId, arguments_2, requestedTurnId, responseKind) {
32439
+ async #beginExternalCommand(thread, commandId, arguments_2, requestedTurnId) {
31737
32440
  const commands = thread.session.commands;
31738
32441
  if (!commands) {
31739
- await this.#writer.json(
31740
- rpcError(request, -32078, "External Harness does not expose commands")
31741
- );
31742
- return;
32442
+ throw new ExternalCommandError(-32078, "External Harness does not expose commands");
31743
32443
  }
31744
- if (thread.running || this.#externalSteering.hasPending(thread.id)) {
31745
- await this.#writer.json(
31746
- rpcError(request, -32072, "External Thread already has an active operation")
31747
- );
31748
- return;
32444
+ if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
32445
+ throw new ExternalCommandError(-32073, "External Thread is no longer available");
32446
+ }
32447
+ if (thread.running || thread.activeTurnId) {
32448
+ throw new ExternalCommandError(-32072, "External Thread already has an active operation");
31749
32449
  }
31750
- const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID9());
32450
+ const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID10());
31751
32451
  const projection = {
31752
32452
  projector: new CodexTurnProjector({
31753
32453
  threadId: thread.id,
@@ -31762,13 +32462,14 @@ var AppServerHost = class {
31762
32462
  thread.projectedTurns.set(turnId, projection);
31763
32463
  thread.responseGates.set(turnId, gate);
31764
32464
  thread.ephemeralTurnIds.add(turnId);
31765
- let result;
31766
32465
  try {
31767
- result = await commands.execute({
32466
+ const result = await commands.execute({
31768
32467
  turnId,
31769
32468
  commandId,
31770
32469
  ...arguments_2 ? { arguments: arguments_2 } : {}
31771
32470
  });
32471
+ if (!result.ok) throw new ExternalCommandError(-32073, result.error.message);
32472
+ return { turnId: result.value.turnId, turn: projection.projector.pendingTurn(), gate };
31772
32473
  } catch (error51) {
31773
32474
  thread.running = false;
31774
32475
  thread.activeTurnId = null;
@@ -31779,28 +32480,6 @@ var AppServerHost = class {
31779
32480
  this.#signalActiveWorkChanged();
31780
32481
  throw error51;
31781
32482
  }
31782
- if (!result.ok) {
31783
- thread.running = false;
31784
- thread.activeTurnId = null;
31785
- thread.projectedTurns.delete(turnId);
31786
- thread.responseGates.delete(turnId);
31787
- thread.ephemeralTurnIds.delete(turnId);
31788
- gate.resolve();
31789
- this.#signalActiveWorkChanged();
31790
- await this.#writer.json(rpcError(request, -32073, result.error.message));
31791
- return;
31792
- }
31793
- try {
31794
- const response = responseKind === "command" ? jsonValueSchema.parse(
31795
- threadCommandExecuteResultSchema.parse({
31796
- accepted: true,
31797
- turnId: result.value.turnId
31798
- })
31799
- ) : { turn: projection.projector.pendingTurn() };
31800
- await this.#writer.json(rpcEnvelope(request, { result: response }));
31801
- } finally {
31802
- gate.resolve();
31803
- }
31804
32483
  }
31805
32484
  async #selectThreadModel(request) {
31806
32485
  const params = threadModelSelectParamsSchema.safeParse(request.params);
@@ -32423,10 +33102,10 @@ var AppServerHost = class {
32423
33102
  ...typeof params.serviceTier === "string" ? { serviceTier: params.serviceTier } : {}
32424
33103
  });
32425
33104
  try {
32426
- if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord13(params.initialTurnsPage)) {
33105
+ if (params.initialTurnsPage !== void 0 && params.initialTurnsPage !== null && !isRecord14(params.initialTurnsPage)) {
32427
33106
  throw new ExternalHistoryRequestError("initialTurnsPage must be an object");
32428
33107
  }
32429
- const initialPageParams = isRecord13(params.initialTurnsPage) ? params.initialTurnsPage : null;
33108
+ const initialPageParams = isRecord14(params.initialTurnsPage) ? params.initialTurnsPage : null;
32430
33109
  const initialTurnsPage = initialPageParams ? listExternalTurns(turns, initialPageParams) : null;
32431
33110
  const paginated = thread.record.historyMode === "paginated";
32432
33111
  const turnsBackwardsCursor = paginated ? listExternalTurns(turns, { limit: 1, itemsView: "notLoaded" }).backwardsCursor : null;
@@ -32521,53 +33200,8 @@ var AppServerHost = class {
32521
33200
  await this.#writer.json(rpcError(request, -32602, errorMessage3(error51)));
32522
33201
  return;
32523
33202
  }
32524
- const commandCandidate = text.trimStart();
32525
- if (thread.session.commands && /^\/[^\s/]+(?:\s|$)/u.test(commandCandidate)) {
32526
- const commandText = commandCandidate.trimEnd();
32527
- this.#pendingExternalCommandRequests.add(thread.id);
32528
- try {
32529
- const catalog = await thread.session.commands.list();
32530
- if (!catalog.ok) {
32531
- await this.#writer.json(rpcError(request, -32073, catalog.error.message));
32532
- return;
32533
- }
32534
- const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
32535
- if (commandText === command.invocation) return true;
32536
- return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
32537
- });
32538
- if (matched) {
32539
- const argumentText = commandText.slice(matched.invocation.length).trimStart();
32540
- try {
32541
- await this.#startExternalCommand(
32542
- request,
32543
- thread,
32544
- matched.id,
32545
- argumentText.length > 0 ? { text: argumentText } : void 0,
32546
- void 0,
32547
- "turn"
32548
- );
32549
- } catch (error51) {
32550
- this.#diagnose(error51);
32551
- await this.#writer.json(
32552
- rpcError(request, -32073, `External Harness command failed: ${errorMessage3(error51)}`)
32553
- );
32554
- }
32555
- return;
32556
- }
32557
- await this.#writer.json(
32558
- rpcError(request, -32078, "External Harness does not expose the requested command")
32559
- );
32560
- return;
32561
- } finally {
32562
- this.#pendingExternalCommandRequests.delete(thread.id);
32563
- }
32564
- }
32565
- if (this.#externalSteering.hasPending(thread.id)) {
32566
- await this.#writer.json(rpcError(request, -32072, "External Thread is changing direction"));
32567
- return;
32568
- }
32569
33203
  try {
32570
- const started = await this.#beginExternalTurn(thread, text);
33204
+ const started = await this.#beginExternalInputTurn(thread, text);
32571
33205
  try {
32572
33206
  await this.#writer.json(rpcEnvelope(request, { result: { turn: started.turn } }));
32573
33207
  } finally {
@@ -32577,7 +33211,7 @@ var AppServerHost = class {
32577
33211
  await this.#writer.json(
32578
33212
  rpcError(
32579
33213
  request,
32580
- error51 instanceof ExternalSteerError ? error51.code : -32073,
33214
+ error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32073,
32581
33215
  errorMessage3(error51)
32582
33216
  )
32583
33217
  );
@@ -32588,7 +33222,7 @@ var AppServerHost = class {
32588
33222
  const started = await this.#externalSteering.run(
32589
33223
  thread,
32590
33224
  requestObject(request),
32591
- (text) => this.#beginExternalTurn(thread, text)
33225
+ (text, assertActive) => this.#beginExternalInputTurn(thread, text, assertActive)
32592
33226
  );
32593
33227
  try {
32594
33228
  await this.#writer.json(rpcEnvelope(request, { result: { turnId: started.turnId } }));
@@ -32599,7 +33233,7 @@ var AppServerHost = class {
32599
33233
  await this.#writer.json(
32600
33234
  rpcError(
32601
33235
  request,
32602
- error51 instanceof ExternalSteerError ? error51.code : -32074,
33236
+ error51 instanceof ExternalSteerError || error51 instanceof ExternalCommandError ? error51.code : -32074,
32603
33237
  errorMessage3(error51)
32604
33238
  )
32605
33239
  );
@@ -32607,6 +33241,37 @@ var AppServerHost = class {
32607
33241
  this.#signalActiveWorkChanged();
32608
33242
  }
32609
33243
  }
33244
+ /** Keep command restoration and dispatch identical for start and steer submissions. */
33245
+ async #beginExternalInputTurn(thread, inputText, assertActive) {
33246
+ const text = restoreHarnessCommandMentions(inputText);
33247
+ const commands = thread.session.commands;
33248
+ if (!commands || !isExternalCommandCandidate(text)) {
33249
+ assertActive?.();
33250
+ return this.#beginExternalTurn(thread, text);
33251
+ }
33252
+ this.#pendingExternalCommandRequests.add(thread.id);
33253
+ try {
33254
+ const adapter = this.#externalAdapters.get(thread.harnessId);
33255
+ const command = await resolveExternalCommand(commands, text, {
33256
+ liveCatalogPending: (catalog) => adapter?.liveCommandCatalog === true && !isLiveCommandCatalog(catalog, adapter.commandCatalog ?? { commands: [] })
33257
+ });
33258
+ assertActive?.();
33259
+ if (!command) {
33260
+ this.#pendingExternalCommandRequests.delete(thread.id);
33261
+ return await this.#beginExternalTurn(thread, text);
33262
+ }
33263
+ return await this.#beginExternalCommand(thread, command.commandId, command.arguments);
33264
+ } catch (error51) {
33265
+ if (error51 instanceof ExternalCommandError || error51 instanceof ExternalSteerError) throw error51;
33266
+ this.#diagnose(error51);
33267
+ throw new ExternalCommandError(
33268
+ -32073,
33269
+ `External Harness command failed: ${errorMessage3(error51)}`
33270
+ );
33271
+ } finally {
33272
+ this.#pendingExternalCommandRequests.delete(thread.id);
33273
+ }
33274
+ }
32610
33275
  async #beginExternalTurn(thread, text) {
32611
33276
  if (this.#closeRequested || this.#externalRuntime.get(thread.id) !== thread) {
32612
33277
  throw new ExternalSteerError(-32073, "External Thread is no longer available");
@@ -32614,7 +33279,7 @@ var AppServerHost = class {
32614
33279
  if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
32615
33280
  throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
32616
33281
  }
32617
- const turnId = hostTurnIdSchema.parse(randomUUID9());
33282
+ const turnId = hostTurnIdSchema.parse(randomUUID10());
32618
33283
  const startedAtMs = Date.now();
32619
33284
  const projection = {
32620
33285
  projector: new CodexTurnProjector({
@@ -32633,7 +33298,7 @@ var AppServerHost = class {
32633
33298
  const result = await thread.session.execute({
32634
33299
  type: "turn.start",
32635
33300
  turnId,
32636
- input: [{ type: "text", text }]
33301
+ input: [{ type: "text", text: rewriteDelegationMentionText(text) }]
32637
33302
  });
32638
33303
  if (!result.ok) throw new ExternalSteerError(-32073, result.error.message);
32639
33304
  return { turnId, turn: projection.projector.pendingTurn(), gate };
@@ -32935,7 +33600,7 @@ var AppServerHost = class {
32935
33600
  const previousItems = new Map(
32936
33601
  child.turns.flatMap(
32937
33602
  (turn) => Array.isArray(turn.items) ? turn.items.flatMap(
32938
- (item) => isRecord13(item) && typeof item.id === "string" ? [[item.id, JSON.stringify(item)]] : []
33603
+ (item) => isRecord14(item) && typeof item.id === "string" ? [[item.id, JSON.stringify(item)]] : []
32939
33604
  ) : []
32940
33605
  )
32941
33606
  );
@@ -32948,7 +33613,7 @@ var AppServerHost = class {
32948
33613
  for (const turn of child.turns) {
32949
33614
  if (typeof turn.id !== "string" || !Array.isArray(turn.items)) continue;
32950
33615
  const changedItems = turn.items.filter(
32951
- (item) => isRecord13(item) && typeof item.id === "string" && previousItems.get(item.id) !== JSON.stringify(item)
33616
+ (item) => isRecord14(item) && typeof item.id === "string" && previousItems.get(item.id) !== JSON.stringify(item)
32952
33617
  );
32953
33618
  if (changedItems.length > 0) {
32954
33619
  await this.#writer.json({
@@ -33080,7 +33745,7 @@ var AppServerHost = class {
33080
33745
  }
33081
33746
  }
33082
33747
  async #handleDesktopApprovalResponse(value2) {
33083
- if (!isRecord13(value2) || !isHostApprovalRequestId(value2.id)) return false;
33748
+ if (!isRecord14(value2) || !isHostApprovalRequestId(value2.id)) return false;
33084
33749
  const requestId = value2.id;
33085
33750
  const pending = this.#pendingDesktopApprovals.get(requestId);
33086
33751
  if (!pending) return true;
@@ -33162,7 +33827,7 @@ var AppServerHost = class {
33162
33827
  try {
33163
33828
  result = projection.projector.projectQuestion(
33164
33829
  interaction,
33165
- hostItemIdSchema.parse(randomUUID9())
33830
+ hostItemIdSchema.parse(randomUUID10())
33166
33831
  );
33167
33832
  } catch (error51) {
33168
33833
  this.#diagnose(error51);
@@ -33207,7 +33872,7 @@ var AppServerHost = class {
33207
33872
  }
33208
33873
  }
33209
33874
  async #handleDesktopQuestionResponse(value2) {
33210
- if (!isRecord13(value2) || !isHostQuestionRequestId(value2.id)) return false;
33875
+ if (!isRecord14(value2) || !isHostQuestionRequestId(value2.id)) return false;
33211
33876
  const requestId = value2.id;
33212
33877
  const pending = this.#pendingDesktopQuestions.get(requestId);
33213
33878
  if (!pending) return true;
@@ -33328,19 +33993,19 @@ var AppServerHost = class {
33328
33993
  };
33329
33994
 
33330
33995
  // packages/host-runtime/src/native-account-host.ts
33331
- import { mkdir as mkdir7, realpath as realpath3 } from "node:fs/promises";
33996
+ import { mkdir as mkdir8, realpath as realpath3 } from "node:fs/promises";
33332
33997
  import { homedir } from "node:os";
33333
- import path16 from "node:path";
33998
+ import path19 from "node:path";
33334
33999
 
33335
34000
  // packages/host-runtime/src/codex-runtime/owned-official-backends.ts
33336
- import { createHash as createHash7, randomBytes } from "node:crypto";
34001
+ import { createHash as createHash9, randomBytes } from "node:crypto";
33337
34002
  import { Writable as Writable2 } from "node:stream";
33338
34003
 
33339
34004
  // packages/host-runtime/src/remote-app-server.ts
33340
34005
  import { createServer } from "node:http";
33341
34006
  import net from "node:net";
33342
- import { chmod as chmod3, lstat as lstat6, mkdir as mkdir6, rm as rm6 } from "node:fs/promises";
33343
- import path14 from "node:path";
34007
+ import { chmod as chmod3, lstat as lstat6, mkdir as mkdir7, rm as rm7 } from "node:fs/promises";
34008
+ import path17 from "node:path";
33344
34009
  import { PassThrough } from "node:stream";
33345
34010
 
33346
34011
  // node_modules/ws/wrapper.mjs
@@ -33355,10 +34020,10 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
33355
34020
  var wrapper_default = import_websocket.default;
33356
34021
 
33357
34022
  // packages/host-runtime/src/remote-socket-lock.ts
33358
- import { randomUUID as randomUUID10 } from "node:crypto";
33359
- import { chmod as chmod2, lstat as lstat5, mkdir as mkdir5, open as open5, readFile as readFile6, readdir as readdir4, rename as rename4, rm as rm5 } from "node:fs/promises";
34023
+ import { randomUUID as randomUUID11 } from "node:crypto";
34024
+ import { chmod as chmod2, lstat as lstat5, mkdir as mkdir6, open as open6, readFile as readFile8, readdir as readdir4, rename as rename5, rm as rm6 } from "node:fs/promises";
33360
34025
  import { uptime } from "node:os";
33361
- import path13 from "node:path";
34026
+ import path16 from "node:path";
33362
34027
  import { setTimeout as delay4 } from "node:timers/promises";
33363
34028
  var LOCK_RETRY_COUNT = 200;
33364
34029
  var LOCK_RETRY_DELAY_MS = 25;
@@ -33421,7 +34086,7 @@ async function readLockEntrySnapshot(filePath) {
33421
34086
  throw error51;
33422
34087
  });
33423
34088
  if (metadata === null || !metadata.isFile()) return null;
33424
- const source = await readFile6(filePath, "utf8").catch((error51) => {
34089
+ const source = await readFile8(filePath, "utf8").catch((error51) => {
33425
34090
  if (error51.code === "ENOENT") return null;
33426
34091
  throw error51;
33427
34092
  });
@@ -33432,7 +34097,7 @@ async function readLockEntrySnapshot(filePath) {
33432
34097
  source,
33433
34098
  identity: { dev: metadata.dev, ino: metadata.ino },
33434
34099
  mtimeMs: metadata.mtimeMs,
33435
- record: record3 && path13.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
34100
+ record: record3 && path16.basename(filePath) === lockEntryName(record3.ownerToken) ? record3 : null
33436
34101
  };
33437
34102
  }
33438
34103
  function lockEntryIsAbandoned(snapshot) {
@@ -33444,7 +34109,7 @@ async function removeAbandonedLockEntry(snapshot) {
33444
34109
  if (current === null || current.source !== snapshot.source || !sameUnixFileIdentity(current.identity, snapshot.identity) || !lockEntryIsAbandoned(current)) {
33445
34110
  return false;
33446
34111
  }
33447
- await rm5(snapshot.filePath, { force: true });
34112
+ await rm6(snapshot.filePath, { force: true });
33448
34113
  return true;
33449
34114
  }
33450
34115
  async function readLockEntryCatalog(lockDirectory) {
@@ -33453,7 +34118,7 @@ async function readLockEntryCatalog(lockDirectory) {
33453
34118
  let unsettled = false;
33454
34119
  for (const name of names) {
33455
34120
  if (!name.startsWith(LOCK_ENTRY_PREFIX) || !name.endsWith(LOCK_ENTRY_SUFFIX)) continue;
33456
- const snapshot = await readLockEntrySnapshot(path13.join(lockDirectory, name));
34121
+ const snapshot = await readLockEntrySnapshot(path16.join(lockDirectory, name));
33457
34122
  if (snapshot === null) continue;
33458
34123
  if (lockEntryIsAbandoned(snapshot)) {
33459
34124
  if (!await removeAbandonedLockEntry(snapshot)) unsettled = true;
@@ -33468,7 +34133,7 @@ async function readLockEntryCatalog(lockDirectory) {
33468
34133
  return { entries, unsettled };
33469
34134
  }
33470
34135
  async function preparePrivateLockDirectory(lockDirectory) {
33471
- await mkdir5(lockDirectory, { mode: 448 }).catch((error51) => {
34136
+ await mkdir6(lockDirectory, { mode: 448 }).catch((error51) => {
33472
34137
  if (error51.code !== "EEXIST") throw error51;
33473
34138
  });
33474
34139
  const metadata = await lstat5(lockDirectory);
@@ -33481,8 +34146,8 @@ async function preparePrivateLockDirectory(lockDirectory) {
33481
34146
  await chmod2(lockDirectory, 448);
33482
34147
  }
33483
34148
  async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
33484
- const temporary = path13.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID10()}`);
33485
- const handle = await open5(temporary, "wx", 384);
34149
+ const temporary = path16.join(lockDirectory, `.tmp-${record3.ownerToken}-${randomUUID11()}`);
34150
+ const handle = await open6(temporary, "wx", 384);
33486
34151
  try {
33487
34152
  await handle.writeFile(`${JSON.stringify(record3)}
33488
34153
  `, "utf8");
@@ -33491,15 +34156,15 @@ async function writeLockRecordAtomic(lockDirectory, entryPath, record3) {
33491
34156
  await handle.close();
33492
34157
  }
33493
34158
  try {
33494
- await rename4(temporary, entryPath);
34159
+ await rename5(temporary, entryPath);
33495
34160
  } finally {
33496
- await rm5(temporary, { force: true });
34161
+ await rm6(temporary, { force: true });
33497
34162
  }
33498
34163
  }
33499
34164
  async function removeOwnedLockEntry(entryPath, ownerToken) {
33500
34165
  const snapshot = await readLockEntrySnapshot(entryPath);
33501
34166
  if (snapshot?.record?.ownerToken !== ownerToken) return;
33502
- await rm5(entryPath, { force: true });
34167
+ await rm6(entryPath, { force: true });
33503
34168
  }
33504
34169
  async function legacyLockState(legacyPath) {
33505
34170
  const metadata = await lstat5(legacyPath).catch((error51) => {
@@ -33508,7 +34173,7 @@ async function legacyLockState(legacyPath) {
33508
34173
  });
33509
34174
  if (metadata === null) return "absent";
33510
34175
  if (!metadata.isFile()) return "blocking";
33511
- const source = await readFile6(legacyPath, "utf8").catch((error51) => {
34176
+ const source = await readFile8(legacyPath, "utf8").catch((error51) => {
33512
34177
  if (error51.code === "ENOENT") return null;
33513
34178
  throw error51;
33514
34179
  });
@@ -33519,7 +34184,7 @@ async function legacyLockState(legacyPath) {
33519
34184
  return ownerIsAbandoned(record3, metadata.mtimeMs) ? "abandoned" : "blocking";
33520
34185
  }
33521
34186
  async function tryAcquireLegacyCompatibilityGuard(legacyPath, record3) {
33522
- const handle = await open5(legacyPath, "wx", 384).catch((error51) => {
34187
+ const handle = await open6(legacyPath, "wx", 384).catch((error51) => {
33523
34188
  if (error51.code === "EEXIST") return null;
33524
34189
  throw error51;
33525
34190
  });
@@ -33545,7 +34210,7 @@ async function releaseLegacyCompatibilityGuard(legacyPath, guard) {
33545
34210
  throw error51;
33546
34211
  });
33547
34212
  if (metadata?.isFile() && sameUnixFileIdentity({ dev: metadata.dev, ino: metadata.ino }, guard.identity)) {
33548
- await rm5(legacyPath, { force: true });
34213
+ await rm6(legacyPath, { force: true });
33549
34214
  }
33550
34215
  }
33551
34216
  }
@@ -33556,8 +34221,8 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
33556
34221
  const legacyPath = `${socketPath}.initializing`;
33557
34222
  const lockDirectory = `${socketPath}.initializers`;
33558
34223
  await preparePrivateLockDirectory(lockDirectory);
33559
- const ownerToken = randomUUID10();
33560
- const entryPath = path13.join(lockDirectory, lockEntryName(ownerToken));
34224
+ const ownerToken = randomUUID11();
34225
+ const entryPath = path16.join(lockDirectory, lockEntryName(ownerToken));
33561
34226
  const baseRecord = {
33562
34227
  version: 2,
33563
34228
  ownerToken,
@@ -33731,14 +34396,14 @@ function remoteAppServerSocketPath(environment, listenUrl = "unix://") {
33731
34396
  throw new Error("Remote app-server listener must use a Unix URL");
33732
34397
  }
33733
34398
  const explicit = listenUrl.slice("unix://".length);
33734
- if (explicit.length > 0) return path14.posix.resolve(decodeURIComponent(explicit));
33735
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path14.posix.join(environment.HOME, ".codex") : void 0);
34399
+ if (explicit.length > 0) return path17.posix.resolve(decodeURIComponent(explicit));
34400
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path17.posix.join(environment.HOME, ".codex") : void 0);
33736
34401
  if (!codexHome)
33737
34402
  throw new Error("CODEX_HOME or HOME is required for the remote app-server socket");
33738
- return path14.posix.join(codexHome, "app-server-control", "app-server-control.sock");
34403
+ return path17.posix.join(codexHome, "app-server-control", "app-server-control.sock");
33739
34404
  }
33740
34405
  function officialListenerArgumentsForRemoteListener(arguments_2, socketPath) {
33741
- if (!path14.posix.isAbsolute(socketPath)) {
34406
+ if (!path17.posix.isAbsolute(socketPath)) {
33742
34407
  throw new Error("Shared official app-server socket path must be absolute");
33743
34408
  }
33744
34409
  if (remoteUnixListenerUrl(arguments_2) === null) {
@@ -33846,10 +34511,10 @@ async function removeStaleSocket(socketPath) {
33846
34511
  });
33847
34512
  });
33848
34513
  if (active) throw new Error(`Remote app-server socket is already in use at ${socketPath}`);
33849
- await rm6(socketPath, { force: true });
34514
+ await rm7(socketPath, { force: true });
33850
34515
  }
33851
34516
  async function prepareRemoteAppServerSocketDirectory(socketPath) {
33852
- const socketDirectory = path14.dirname(socketPath);
34517
+ const socketDirectory = path17.dirname(socketPath);
33853
34518
  const existing = await lstat6(socketDirectory).catch((error51) => {
33854
34519
  if (error51.code === "ENOENT") return null;
33855
34520
  throw error51;
@@ -33863,7 +34528,7 @@ async function prepareRemoteAppServerSocketDirectory(socketPath) {
33863
34528
  );
33864
34529
  }
33865
34530
  }
33866
- await mkdir6(socketDirectory, { recursive: true, mode: 448 });
34531
+ await mkdir7(socketDirectory, { recursive: true, mode: 448 });
33867
34532
  await chmod3(socketDirectory, 448);
33868
34533
  }
33869
34534
  function sendOutputFrames(socket, output) {
@@ -34036,7 +34701,7 @@ function createRemoteAppServerWebSocketListener(input) {
34036
34701
  if (ownedSocketIdentity) {
34037
34702
  const current = await unixSocketIdentity(input.socketPath);
34038
34703
  if (current && sameUnixFileIdentity2(current, ownedSocketIdentity)) {
34039
- await rm6(input.socketPath, { force: true });
34704
+ await rm7(input.socketPath, { force: true });
34040
34705
  }
34041
34706
  ownedSocketIdentity = null;
34042
34707
  }
@@ -34054,20 +34719,20 @@ function createRemoteAppServerWebSocketListener(input) {
34054
34719
 
34055
34720
  // packages/host-runtime/src/remote-official-app-server.ts
34056
34721
  import { spawn as spawn3 } from "node:child_process";
34057
- import { randomUUID as randomUUID11 } from "node:crypto";
34058
- import { lstat as lstat7, rm as rm7 } from "node:fs/promises";
34059
- import path15 from "node:path";
34722
+ import { randomUUID as randomUUID12 } from "node:crypto";
34723
+ import { lstat as lstat7, rm as rm8 } from "node:fs/promises";
34724
+ import path18 from "node:path";
34060
34725
  var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
34061
34726
  var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
34062
- function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID11()) {
34063
- if (!path15.posix.isAbsolute(desktopControlSocketPath)) {
34727
+ function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID12()) {
34728
+ if (!path18.posix.isAbsolute(desktopControlSocketPath)) {
34064
34729
  throw new Error("Desktop control socket path must be absolute");
34065
34730
  }
34066
34731
  if (!/^[A-Za-z0-9-]+$/u.test(token) || !/[A-Za-z0-9]/u.test(token)) {
34067
34732
  throw new Error("Shared official app-server socket token is invalid");
34068
34733
  }
34069
34734
  const compactToken = token.replaceAll("-", "").slice(0, 15);
34070
- return path15.posix.join(path15.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
34735
+ return path18.posix.join(path18.posix.dirname(desktopControlSocketPath), `.c-${compactToken}.sock`);
34071
34736
  }
34072
34737
  function errorMessage4(error51) {
34073
34738
  return error51 instanceof Error ? error51.message : String(error51);
@@ -34139,7 +34804,7 @@ function createRemoteOfficialAppServerListener(input) {
34139
34804
  if (ownedSocketIdentity === null) return;
34140
34805
  const current = await socketIdentity(input.socketPath).catch(() => null);
34141
34806
  if (current && sameUnixFileIdentity3(current, ownedSocketIdentity)) {
34142
- await rm7(input.socketPath, { force: true });
34807
+ await rm8(input.socketPath, { force: true });
34143
34808
  }
34144
34809
  ownedSocketIdentity = null;
34145
34810
  };
@@ -34500,7 +35165,7 @@ function createOwnedLoopbackBackend(input) {
34500
35165
  "--ws-auth",
34501
35166
  "capability-token",
34502
35167
  "--ws-token-sha256",
34503
- createHash7("sha256").update(capabilityToken).digest("hex")
35168
+ createHash9("sha256").update(capabilityToken).digest("hex")
34504
35169
  ],
34505
35170
  // Managed stderr may carry credential-bearing errors. Never forward raw bytes.
34506
35171
  diagnosticOutput: new Writable2({
@@ -34553,21 +35218,21 @@ function createOwnedUnixBackend(input) {
34553
35218
 
34554
35219
  // packages/host-runtime/src/native-account-host.ts
34555
35220
  async function canonicalCodexHome(home) {
34556
- const absolute = path16.resolve(home);
35221
+ const absolute = path19.resolve(home);
34557
35222
  try {
34558
35223
  return await realpath3(absolute);
34559
35224
  } catch (error51) {
34560
35225
  if (!(error51 instanceof Error && "code" in error51 && error51.code === "ENOENT")) throw error51;
34561
- const parent = path16.dirname(absolute);
35226
+ const parent = path19.dirname(absolute);
34562
35227
  if (parent === absolute) throw error51;
34563
- return path16.join(await canonicalCodexHome(parent), path16.basename(absolute));
35228
+ return path19.join(await canonicalCodexHome(parent), path19.basename(absolute));
34564
35229
  }
34565
35230
  }
34566
35231
  async function prepareLocalCodex(input) {
34567
35232
  const home = await canonicalCodexHome(
34568
- input.environment.CODEX_HOME ?? path16.join(homedir(), ".codex")
35233
+ input.environment.CODEX_HOME ?? path19.join(homedir(), ".codex")
34569
35234
  );
34570
- await mkdir7(home, { recursive: true });
35235
+ await mkdir8(home, { recursive: true });
34571
35236
  const scope = new OfficialRuntimeScope({
34572
35237
  permanentHome: home,
34573
35238
  diagnosticOutput: input.diagnosticOutput,
@@ -34731,18 +35396,18 @@ var DelegationControlRegistry = class {
34731
35396
  };
34732
35397
 
34733
35398
  // packages/host-runtime/src/installed-harness-plugins.ts
34734
- import os4 from "node:os";
34735
- import path18 from "node:path";
35399
+ import os6 from "node:os";
35400
+ import path21 from "node:path";
34736
35401
  import { fileURLToPath } from "node:url";
34737
35402
 
34738
35403
  // packages/host-runtime/src/launcher-url-opener.ts
34739
35404
  import { spawn as spawn4 } from "node:child_process";
34740
- import path17 from "node:path";
35405
+ import path20 from "node:path";
34741
35406
  var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "[::1]"]);
34742
35407
  var OPEN_TIMEOUT_MS = 1e4;
34743
35408
  function createLauncherUrlOpener(environment, spawnLauncher = (command, arguments_2, options2) => spawn4(command, arguments_2, options2)) {
34744
35409
  const launcher = environment.CODEXHOST_LAUNCHER_EXECUTABLE;
34745
- if (!launcher || !path17.isAbsolute(launcher)) return void 0;
35410
+ if (!launcher || !path20.isAbsolute(launcher)) return void 0;
34746
35411
  const launcherEnvironment = Object.fromEntries(
34747
35412
  Object.entries(environment).filter(([name]) => {
34748
35413
  const normalized = name.toUpperCase();
@@ -34800,9 +35465,9 @@ function installedHarnessPluginOptions(environment, managedRemoteHost = false, h
34800
35465
  const opener = managedRemoteHost ? void 0 : createLauncherUrlOpener(environment);
34801
35466
  return {
34802
35467
  pluginRoots: [
34803
- path18.join(path18.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
34804
- environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path18.join(
34805
- environment.CODEXHOST_DATA_DIR ? path18.resolve(environment.CODEXHOST_DATA_DIR) : path18.join(os4.homedir(), ".codexhost"),
35468
+ path21.join(path21.dirname(fileURLToPath(hostRuntimeUrl)), "plugins"),
35469
+ environment[HARNESS_PLUGIN_DIRECTORY_ENV] ?? path21.join(
35470
+ environment.CODEXHOST_DATA_DIR ? path21.resolve(environment.CODEXHOST_DATA_DIR) : path21.join(os6.homedir(), ".codexhost"),
34806
35471
  "plugins"
34807
35472
  )
34808
35473
  ],
@@ -34926,171 +35591,10 @@ async function startDelegationControlServer(input) {
34926
35591
  };
34927
35592
  }
34928
35593
 
34929
- // packages/host-runtime/src/delegation-skill.ts
34930
- import { createHash as createHash8, randomUUID as randomUUID12 } from "node:crypto";
34931
- import { mkdir as mkdir8, open as open6, readFile as readFile7, rename as rename5, rm as rm8, stat as stat4 } from "node:fs/promises";
34932
- import os5 from "node:os";
34933
- import path19 from "node:path";
34934
- var SKILL_VERSION = 7;
34935
- var SKILL_RELATIVE_PATH = path19.join("skills", "codexhost-delegation", "SKILL.md");
34936
- var PREVIOUS_MANAGED_DIGESTS = [
34937
- "9d2f491850fb0b4084a31ba9b5e4a550b5e833747af322090d8ed0ff80b88c30",
34938
- "2bb0aebb9b06febbc6c0c0bcdb0b32506c7cdbf8dc3b734cc6b2a86621270e4e",
34939
- "aff258622dc8ff321f32b15620d081e578cb9c9ed1134d6a57f35ca8e7762c0a",
34940
- "ba509f57e5448e796b3dfdd5031dcb08672eded50b61c0a54de84cfa02c49dd3",
34941
- "d3ddf6db9bc5c5df825479c885bbbf0ca08da66f7057a12e02e1fdf57525149e",
34942
- "15eb63519ff867e1536c97188a0c43738d7a49d38d4d6adeb7a1036726e7246d"
34943
- ];
34944
- var CODEXHOST_DELEGATION_SKILL = `---
34945
- name: codexhost-delegation
34946
- version: ${SKILL_VERSION}
34947
- description: >
34948
- Delegate tasks to other coding agents, or read and follow up on existing
34949
- external agent sessions. Use when the user asks another agent (including
34950
- @agent) to independently perform a task, or asks to view a specified external
34951
- session's content, progress, or results, send follow-up messages, wait, or
34952
- cancel a task. Not for recapping the current conversation, discussing or
34953
- configuring agents, or role-playing.
34954
- ---
34955
-
34956
- # Execute the task
34957
-
34958
- Before acting, run:
34959
-
34960
- \`codexhost delegate --help\`
34961
-
34962
- Use CLI help as the authoritative source for commands and behavior. Consult
34963
- command-specific help for options and the Harness listing command when the
34964
- target is unknown. Prefer compact output when supported, and use its task links
34965
- directly for subsequent commands.
34966
-
34967
- Use the Harness native defaults. Inspect the target when a Model or Thinking
34968
- selection is needed or the default is unavailable.
34969
-
34970
- For a new delegation, create an independent child session and submit the
34971
- requested task. For an existing external session, resolve the target from the
34972
- user-provided session link, identifier, or context and operate on that Thread
34973
- directly; it need not have been created by the current assistant. If the target
34974
- is ambiguous, ask the user to identify it. Keep requests to view or summarize a
34975
- session read-only.
34976
-
34977
- For a new or existing task, choose the appropriate next action based on the
34978
- user’s request and the task:
34979
-
34980
- - send a follow-up message to the same Thread;
34981
- - cancel its current Turn;
34982
- - read its current state immediately;
34983
- - wait for a bounded period;
34984
- - check it again later;
34985
- - leave it running in the background.
34986
-
34987
- Report the result returned by read or a completed wait, together with the target
34988
- agent, status, and a labeled task link. Keep internal tracking IDs in tool calls.
34989
- `;
34990
- var CURRENT_DIGEST = createHash8("sha256").update(CODEXHOST_DELEGATION_SKILL).digest("hex");
34991
- function digest(value2) {
34992
- return createHash8("sha256").update(value2).digest("hex");
34993
- }
34994
- function managedVersion(value2) {
34995
- const match = /^version:\s*(\d+)\s*$/mu.exec(value2);
34996
- return match ? Number(match[1]) : null;
34997
- }
34998
- async function readOptional(filePath) {
34999
- try {
35000
- return await readFile7(filePath, "utf8");
35001
- } catch (error51) {
35002
- if (error51.code === "ENOENT") return null;
35003
- throw error51;
35004
- }
35005
- }
35006
- async function atomicWrite(filePath, content) {
35007
- await mkdir8(path19.dirname(filePath), { recursive: true, mode: 448 });
35008
- const temporaryPath = path19.join(path19.dirname(filePath), `.SKILL.md.${randomUUID12()}.tmp`);
35009
- const handle = await open6(temporaryPath, "wx", 384);
35010
- try {
35011
- await handle.writeFile(content, "utf8");
35012
- await handle.sync();
35013
- } finally {
35014
- await handle.close();
35015
- }
35016
- try {
35017
- await rename5(temporaryPath, filePath);
35018
- } finally {
35019
- await rm8(temporaryPath, { force: true });
35020
- }
35021
- }
35022
- async function installDelegationSkills(input = {}) {
35023
- const home = input.homeDirectory ?? os5.homedir();
35024
- const destinations = [
35025
- path19.join(home, ".agents", SKILL_RELATIVE_PATH),
35026
- path19.join(home, ".claude", SKILL_RELATIVE_PATH)
35027
- ];
35028
- const knownDigests = /* @__PURE__ */ new Set([
35029
- CURRENT_DIGEST,
35030
- ...PREVIOUS_MANAGED_DIGESTS,
35031
- ...input.previousManagedDigests ?? []
35032
- ]);
35033
- const results = [];
35034
- for (const destination of destinations) {
35035
- const current = await readOptional(destination);
35036
- if (current === CODEXHOST_DELEGATION_SKILL) {
35037
- results.push({
35038
- path: destination,
35039
- status: "current",
35040
- version: SKILL_VERSION,
35041
- digest: CURRENT_DIGEST
35042
- });
35043
- continue;
35044
- }
35045
- if (current !== null) {
35046
- const currentDigest = digest(current);
35047
- const version2 = managedVersion(current);
35048
- if (!knownDigests.has(currentDigest)) {
35049
- results.push({ path: destination, status: "conflict", version: version2, digest: currentDigest });
35050
- continue;
35051
- }
35052
- await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
35053
- results.push({
35054
- path: destination,
35055
- status: "updated",
35056
- version: SKILL_VERSION,
35057
- digest: CURRENT_DIGEST
35058
- });
35059
- continue;
35060
- }
35061
- await atomicWrite(destination, CODEXHOST_DELEGATION_SKILL);
35062
- results.push({
35063
- path: destination,
35064
- status: "installed",
35065
- version: SKILL_VERSION,
35066
- digest: CURRENT_DIGEST
35067
- });
35068
- }
35069
- for (const result of results) {
35070
- if (result.status === "conflict") continue;
35071
- const source = await readFile7(result.path, "utf8");
35072
- const metadata = await stat4(result.path);
35073
- if (!metadata.isFile() || source !== CODEXHOST_DELEGATION_SKILL) {
35074
- throw new Error(`Delegation Skill verification failed: ${result.path}`);
35075
- }
35076
- }
35077
- const managed = results.filter((result) => result.status !== "conflict");
35078
- if (managed.some((result) => result.digest !== CURRENT_DIGEST)) {
35079
- throw new Error("Delegation Skill copies are inconsistent");
35080
- }
35081
- if (results.every((result) => result.status !== "conflict")) {
35082
- const copies = await Promise.all(results.map((result) => readFile7(result.path, "utf8")));
35083
- if (copies.some((copy) => copy !== copies[0])) {
35084
- throw new Error("Delegation Skill copies are inconsistent");
35085
- }
35086
- }
35087
- return results;
35088
- }
35089
-
35090
35594
  // packages/host-runtime/src/remote-control-app-server.ts
35091
35595
  import { randomUUID as randomUUID13 } from "node:crypto";
35092
35596
  import { mkdir as mkdir9, open as open7, rename as rename6, rm as rm9 } from "node:fs/promises";
35093
- import path20 from "node:path";
35597
+ import path22 from "node:path";
35094
35598
  var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
35095
35599
  var REMOTE_CONTROL_BRIDGE_NODE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_NODE_PATH";
35096
35600
  var REMOTE_CONTROL_BRIDGE_RUNTIME_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_RUNTIME_PATH";
@@ -35101,8 +35605,8 @@ var BRIDGE_READY_METHOD = "codexhost/remote-control-bridge/ready";
35101
35605
  function absoluteEnvironmentPath2(environment, name, fallback, platform = process.platform) {
35102
35606
  const value2 = environment[name] ?? fallback;
35103
35607
  if (!value2) return null;
35104
- if (path20.isAbsolute(value2)) return path20.normalize(value2);
35105
- return platform === "win32" && path20.win32.isAbsolute(value2) ? path20.win32.normalize(value2) : null;
35608
+ if (path22.isAbsolute(value2)) return path22.normalize(value2);
35609
+ return platform === "win32" && path22.win32.isAbsolute(value2) ? path22.win32.normalize(value2) : null;
35106
35610
  }
35107
35611
  function nodeCompatibleWindowsPath(value2) {
35108
35612
  if (value2.startsWith("\\\\?\\UNC\\")) return `\\\\${value2.slice(8)}`;
@@ -35116,13 +35620,13 @@ function remoteControlBridgePipePath(processId = process.pid, instanceId = rando
35116
35620
  }
35117
35621
  function remoteControlBridgeDescriptorPath(environment) {
35118
35622
  const root = environment.LOCALAPPDATA;
35119
- if (!root || !path20.isAbsolute(root)) return null;
35120
- return path20.join(path20.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
35623
+ if (!root || !path22.isAbsolute(root)) return null;
35624
+ return path22.join(path22.normalize(root), "codexhost", REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE);
35121
35625
  }
35122
35626
  async function publishRemoteControlAppServerDescriptor(plan) {
35123
- const directory = path20.dirname(plan.descriptorPath);
35627
+ const directory = path22.dirname(plan.descriptorPath);
35124
35628
  await mkdir9(directory, { recursive: true, mode: 448 });
35125
- const temporaryPath = path20.join(
35629
+ const temporaryPath = path22.join(
35126
35630
  directory,
35127
35631
  `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID13()}.tmp`
35128
35632
  );
@@ -35423,9 +35927,9 @@ function hasLauncherManagedUpdateRuntime(environment, hostRuntimePath) {
35423
35927
  if (!environment[UPDATE_RUNTIME_ENV.launcherPid]) return false;
35424
35928
  const npmPackageRoot = environment[UPDATE_RUNTIME_ENV.npmPackageRoot];
35425
35929
  if (!npmPackageRoot || !hostRuntimePath) return true;
35426
- if (!path21.isAbsolute(npmPackageRoot) || !path21.isAbsolute(hostRuntimePath)) return false;
35427
- const runtimePackageRoot = path21.dirname(path21.dirname(path21.normalize(hostRuntimePath)));
35428
- return path21.relative(path21.normalize(npmPackageRoot), runtimePackageRoot) === "";
35930
+ if (!path23.isAbsolute(npmPackageRoot) || !path23.isAbsolute(hostRuntimePath)) return false;
35931
+ const runtimePackageRoot = path23.dirname(path23.dirname(path23.normalize(hostRuntimePath)));
35932
+ return path23.relative(path23.normalize(npmPackageRoot), runtimePackageRoot) === "";
35429
35933
  }
35430
35934
  function requiredRuntimeConfiguration(environment) {
35431
35935
  const stockCodexPath = environment[STOCK_CODEX_PATH_ENV];
@@ -35571,8 +36075,8 @@ async function runHostRuntime(input) {
35571
36075
  const socketPath = remoteAppServerSocketPath(delegationEnvironment, listenUrl);
35572
36076
  const officialPlan = createRemoteOfficialAppServerPlan(input.arguments, socketPath);
35573
36077
  const officialRuntimeScope = new OfficialRuntimeScope({
35574
- permanentHome: path21.resolve(
35575
- delegationEnvironment.CODEX_HOME ?? path21.join(homedir2(), ".codex")
36078
+ permanentHome: path23.resolve(
36079
+ delegationEnvironment.CODEX_HOME ?? path23.join(homedir2(), ".codex")
35576
36080
  ),
35577
36081
  diagnosticOutput: process.stderr,
35578
36082
  createBackend: () => createOwnedUnixBackend({
@@ -35653,7 +36157,7 @@ async function runHostRuntime(input) {
35653
36157
  }
35654
36158
 
35655
36159
  // packages/host-runtime/src/remote-host-install.ts
35656
- import { createHash as createHash9, randomUUID as randomUUID14 } from "node:crypto";
36160
+ import { createHash as createHash10, randomUUID as randomUUID14 } from "node:crypto";
35657
36161
  import { constants as fsConstants } from "node:fs";
35658
36162
  import {
35659
36163
  access,
@@ -35661,14 +36165,14 @@ import {
35661
36165
  copyFile as copyFile3,
35662
36166
  lstat as lstat8,
35663
36167
  mkdir as mkdir10,
35664
- readFile as readFile8,
36168
+ readFile as readFile9,
35665
36169
  rename as rename7,
35666
36170
  rm as rm10,
35667
36171
  rmdir,
35668
36172
  stat as stat5,
35669
36173
  writeFile as writeFile4
35670
36174
  } from "node:fs/promises";
35671
- import path22 from "node:path";
36175
+ import path24 from "node:path";
35672
36176
  var MANIFEST_FORMAT = 1;
35673
36177
  var WRAPPER_MARKER = "# codexhost remote SSH wrapper v1";
35674
36178
  var PROFILE_START = "# >>> codexhost remote SSH >>>";
@@ -35679,25 +36183,25 @@ function resolvePaths(options2) {
35679
36183
  if (!configuredHome) {
35680
36184
  throw new Error("A non-root HOME is required for remote Host installation");
35681
36185
  }
35682
- const home = path22.resolve(configuredHome);
35683
- if (!home || home === path22.parse(home).root) {
36186
+ const home = path24.resolve(configuredHome);
36187
+ if (!home || home === path24.parse(home).root) {
35684
36188
  throw new Error("A non-root HOME is required for remote Host installation");
35685
36189
  }
35686
- const installRoot = path22.resolve(options2.installRoot ?? path22.join(home, ".codexhost", "remote"));
35687
- const profilePath = path22.resolve(
35688
- options2.profilePath ?? path22.join(
36190
+ const installRoot = path24.resolve(options2.installRoot ?? path24.join(home, ".codexhost", "remote"));
36191
+ const profilePath = path24.resolve(
36192
+ options2.profilePath ?? path24.join(
35689
36193
  home,
35690
- path22.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path22.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
36194
+ path24.basename(environment.SHELL ?? "") === "zsh" ? ".zshenv" : path24.basename(environment.SHELL ?? "") === "bash" ? ".bashrc" : ".profile"
35691
36195
  )
35692
36196
  );
35693
- const binDirectory = path22.join(installRoot, "bin");
36197
+ const binDirectory = path24.join(installRoot, "bin");
35694
36198
  return {
35695
36199
  home,
35696
36200
  installRoot,
35697
36201
  binDirectory,
35698
- wrapperPath: path22.join(binDirectory, "codex"),
35699
- manifestPath: path22.join(installRoot, "manifest.json"),
35700
- dataDirectory: path22.join(installRoot, "data"),
36202
+ wrapperPath: path24.join(binDirectory, "codex"),
36203
+ manifestPath: path24.join(installRoot, "manifest.json"),
36204
+ dataDirectory: path24.join(installRoot, "data"),
35701
36205
  profilePath
35702
36206
  };
35703
36207
  }
@@ -35706,17 +36210,17 @@ function shellQuote(value2) {
35706
36210
  }
35707
36211
  async function existingText(filePath) {
35708
36212
  try {
35709
- return await readFile8(filePath, "utf8");
36213
+ return await readFile9(filePath, "utf8");
35710
36214
  } catch (error51) {
35711
36215
  if (error51.code === "ENOENT") return null;
35712
36216
  throw error51;
35713
36217
  }
35714
36218
  }
35715
36219
  async function fileSha256(filePath) {
35716
- return createHash9("sha256").update(await readFile8(filePath)).digest("hex");
36220
+ return createHash10("sha256").update(await readFile9(filePath)).digest("hex");
35717
36221
  }
35718
36222
  async function executable(filePath, label) {
35719
- const absolute = path22.resolve(filePath);
36223
+ const absolute = path24.resolve(filePath);
35720
36224
  try {
35721
36225
  if (!(await stat5(absolute)).isFile()) throw new Error("not a regular file");
35722
36226
  await access(absolute, fsConstants.X_OK);
@@ -35726,7 +36230,7 @@ async function executable(filePath, label) {
35726
36230
  return absolute;
35727
36231
  }
35728
36232
  async function existingFile(filePath, label) {
35729
- const absolute = path22.resolve(filePath);
36233
+ const absolute = path24.resolve(filePath);
35730
36234
  try {
35731
36235
  const metadata = await stat5(absolute);
35732
36236
  if (!metadata.isFile()) throw new Error("not a regular file");
@@ -35736,9 +36240,9 @@ async function existingFile(filePath, label) {
35736
36240
  return absolute;
35737
36241
  }
35738
36242
  async function discoverExecutable(name, environment) {
35739
- for (const directory of (environment.PATH ?? "").split(path22.delimiter)) {
36243
+ for (const directory of (environment.PATH ?? "").split(path24.delimiter)) {
35740
36244
  if (!directory) continue;
35741
- const candidate = path22.resolve(directory, name);
36245
+ const candidate = path24.resolve(directory, name);
35742
36246
  try {
35743
36247
  await access(candidate, fsConstants.X_OK);
35744
36248
  return candidate;
@@ -35749,10 +36253,10 @@ async function discoverExecutable(name, environment) {
35749
36253
  return null;
35750
36254
  }
35751
36255
  async function writeAtomic(filePath, contents, mode) {
35752
- await mkdir10(path22.dirname(filePath), { recursive: true, mode: 448 });
35753
- const temporary = path22.join(
35754
- path22.dirname(filePath),
35755
- `.${path22.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
36256
+ await mkdir10(path24.dirname(filePath), { recursive: true, mode: 448 });
36257
+ const temporary = path24.join(
36258
+ path24.dirname(filePath),
36259
+ `.${path24.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
35756
36260
  );
35757
36261
  try {
35758
36262
  if (typeof contents === "string") {
@@ -35773,10 +36277,10 @@ async function writeAtomic(filePath, contents, mode) {
35773
36277
  }
35774
36278
  }
35775
36279
  async function writeAtomicExecutable(filePath, sourcePath) {
35776
- await mkdir10(path22.dirname(filePath), { recursive: true, mode: 448 });
35777
- const temporary = path22.join(
35778
- path22.dirname(filePath),
35779
- `.${path22.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
36280
+ await mkdir10(path24.dirname(filePath), { recursive: true, mode: 448 });
36281
+ const temporary = path24.join(
36282
+ path24.dirname(filePath),
36283
+ `.${path24.basename(filePath)}.${process.pid}.${randomUUID14()}.tmp`
35780
36284
  );
35781
36285
  try {
35782
36286
  await copyFile3(sourcePath, temporary);
@@ -35817,15 +36321,14 @@ function removeManagedProfileBlock(contents) {
35817
36321
  function installManagedProfileBlock(contents, manifest) {
35818
36322
  const base = removeManagedProfileBlock(contents);
35819
36323
  const environment = [
35820
- `export CODEX_INSTALL_DIR=${shellQuote(path22.dirname(manifest.wrapperPath))}`,
35821
- `export PATH=${shellQuote(path22.dirname(manifest.wrapperPath))}:${shellQuote(path22.dirname(manifest.nodePath))}:${shellQuote(path22.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
36324
+ `export CODEX_INSTALL_DIR=${shellQuote(path24.dirname(manifest.wrapperPath))}`,
36325
+ `export PATH=${shellQuote(path24.dirname(manifest.wrapperPath))}:${shellQuote(path24.dirname(manifest.nodePath))}:${shellQuote(path24.dirname(manifest.stockCodexPath))}:"\${PATH:-/usr/local/bin:/usr/bin:/bin}"`,
35822
36326
  `export CODEXHOST_STOCK_CODEX_PATH=${shellQuote(manifest.stockCodexPath)}`,
35823
36327
  `export CODEXHOST_HOST_NODE_PATH=${shellQuote(manifest.nodePath)}`,
35824
36328
  `export CODEXHOST_HOST_RUNTIME_PATH=${shellQuote(manifest.hostRuntimePath)}`,
35825
36329
  `export CODEXHOST_DATA_DIR=${shellQuote(manifest.dataDirectory)}`,
35826
36330
  "export CODEXHOST_DEFAULT_AGENT='codex'",
35827
- "export CODEXHOST_REMOTE_SSH_MANAGED='1'",
35828
- ...manifest.claudeCommand ? [`export CODEXHOST_CLAUDE_COMMAND=${shellQuote(manifest.claudeCommand)}`] : []
36331
+ "export CODEXHOST_REMOTE_SSH_MANAGED='1'"
35829
36332
  ];
35830
36333
  const block = [
35831
36334
  PROFILE_START,
@@ -35835,7 +36338,7 @@ function installManagedProfileBlock(contents, manifest) {
35835
36338
  PROFILE_END,
35836
36339
  ""
35837
36340
  ].join("\n");
35838
- if (path22.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
36341
+ if (path24.basename(manifest.profilePath) === ".bashrc") return `${block}${base}`;
35839
36342
  const separator = base.length > 0 && !base.endsWith("\n") ? "\n" : "";
35840
36343
  return `${base}${separator}${block}`;
35841
36344
  }
@@ -35847,16 +36350,16 @@ async function managedEntrypointState(manifest) {
35847
36350
  if (metadata === null) return "missing";
35848
36351
  if (!metadata.isFile()) return "modified";
35849
36352
  if (process.platform !== "win32" && (metadata.mode & 73) === 0) return "modified";
35850
- const entrypoint = await readFile8(manifest.wrapperPath);
36353
+ const entrypoint = await readFile9(manifest.wrapperPath);
35851
36354
  if (entrypoint.subarray(0, 256).toString("utf8").startsWith(`#!/usr/bin/env sh
35852
36355
  ${WRAPPER_MARKER}
35853
36356
  `)) {
35854
36357
  return "legacy-wrapper";
35855
36358
  }
35856
36359
  if (manifest.entrypointSha256 !== void 0) {
35857
- return createHash9("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
36360
+ return createHash10("sha256").update(entrypoint).digest("hex") === manifest.entrypointSha256 ? "native" : "modified";
35858
36361
  }
35859
- const shim = await readFile8(manifest.shimPath).catch((error51) => {
36362
+ const shim = await readFile9(manifest.shimPath).catch((error51) => {
35860
36363
  if (error51.code === "ENOENT") return null;
35861
36364
  throw error51;
35862
36365
  });
@@ -35887,6 +36390,7 @@ async function readManifest(filePath) {
35887
36390
  "dataDirectory",
35888
36391
  "entrypointSha256",
35889
36392
  "claudeCommand",
36393
+ // Inert metadata accepted from older format-1 manifests.
35890
36394
  "profileBackupPath"
35891
36395
  ]);
35892
36396
  const requiredPaths = [
@@ -35900,9 +36404,9 @@ async function readManifest(filePath) {
35900
36404
  ];
35901
36405
  const optionalPaths = ["claudeCommand", "profileBackupPath"];
35902
36406
  if (manifest.format !== MANIFEST_FORMAT || Object.keys(manifest).some((key) => !allowed.has(key)) || requiredPaths.some(
35903
- (key) => typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key])
36407
+ (key) => typeof manifest[key] !== "string" || !path24.isAbsolute(manifest[key])
35904
36408
  ) || optionalPaths.some(
35905
- (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path22.isAbsolute(manifest[key]))
36409
+ (key) => manifest[key] !== void 0 && (typeof manifest[key] !== "string" || !path24.isAbsolute(manifest[key]))
35906
36410
  ) || manifest.entrypointSha256 !== void 0 && (typeof manifest.entrypointSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(manifest.entrypointSha256))) {
35907
36411
  throw new Error("Remote Host manifest has an unsupported format");
35908
36412
  }
@@ -35924,7 +36428,7 @@ async function installRemoteHost(options2) {
35924
36428
  const paths = resolvePaths(options2);
35925
36429
  const previousManifest = await readManifest(paths.manifestPath);
35926
36430
  const previousManifestFile = previousManifest ? {
35927
- contents: await readFile8(paths.manifestPath),
36431
+ contents: await readFile9(paths.manifestPath),
35928
36432
  mode: (await stat5(paths.manifestPath)).mode & 511
35929
36433
  } : null;
35930
36434
  const existingEntrypoint = await lstat8(paths.wrapperPath).catch(
@@ -35949,7 +36453,7 @@ async function installRemoteHost(options2) {
35949
36453
  }
35950
36454
  const profilePath = previousManifest?.profilePath ?? paths.profilePath;
35951
36455
  const previousEntrypoint = existingEntrypoint?.isFile() ? {
35952
- contents: await readFile8(paths.wrapperPath),
36456
+ contents: await readFile9(paths.wrapperPath),
35953
36457
  mode: existingEntrypoint.mode & 511
35954
36458
  } : null;
35955
36459
  const discoveredStock = options2.stockCodexPath ?? previousManifest?.stockCodexPath ?? await discoverExecutable("codex", environment);
@@ -35966,8 +36470,6 @@ async function installRemoteHost(options2) {
35966
36470
  const nodePath2 = await executable(options2.nodePath, "Node runtime");
35967
36471
  const shimPath = await executable(options2.shimPath, "codexhost Shim");
35968
36472
  const hostRuntimePath = await existingFile(options2.hostRuntimePath, "codexhost Host Runtime");
35969
- const discoveredClaude = options2.claudeCommand ?? previousManifest?.claudeCommand ?? await discoverExecutable("claude", environment);
35970
- const claudeCommand = discoveredClaude ? await executable(discoveredClaude, "Claude Code command") : void 0;
35971
36473
  let manifest = {
35972
36474
  format: MANIFEST_FORMAT,
35973
36475
  wrapperPath: paths.wrapperPath,
@@ -35977,7 +36479,6 @@ async function installRemoteHost(options2) {
35977
36479
  shimPath,
35978
36480
  hostRuntimePath,
35979
36481
  dataDirectory: paths.dataDirectory,
35980
- ...claudeCommand ? { claudeCommand } : {},
35981
36482
  ...previousManifest?.profileBackupPath ? { profileBackupPath: previousManifest.profileBackupPath } : {}
35982
36483
  };
35983
36484
  const existingProfileSource = await existingText(profilePath);
@@ -36131,7 +36632,7 @@ async function uninstallRemoteHost(options2) {
36131
36632
  import { spawn as spawn5 } from "node:child_process";
36132
36633
  import { stat as stat6 } from "node:fs/promises";
36133
36634
  import net3 from "node:net";
36134
- import path23 from "node:path";
36635
+ import path25 from "node:path";
36135
36636
  import { Duplex } from "node:stream";
36136
36637
  var CODEXHOST_STATUS_METHOD = "codexhost/update/status";
36137
36638
  var DIRECT_PROBE_TIMEOUT_MS = 5e3;
@@ -36150,9 +36651,9 @@ function classifyRemoteHostProbeResponse(response, socketPath) {
36150
36651
  }
36151
36652
  var lifecycleDependencyOverrides = {};
36152
36653
  function socketPathFor(environment) {
36153
- const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path23.join(environment.HOME, ".codex") : void 0);
36654
+ const codexHome = environment.CODEX_HOME ?? (environment.HOME ? path25.join(environment.HOME, ".codex") : void 0);
36154
36655
  if (!codexHome) throw new Error("CODEX_HOME or HOME is required for remote Host lifecycle");
36155
- return path23.join(codexHome, "app-server-control", "app-server-control.sock");
36656
+ return path25.join(codexHome, "app-server-control", "app-server-control.sock");
36156
36657
  }
36157
36658
  async function defaultSocketExists(socketPath) {
36158
36659
  const metadata = await stat6(socketPath).catch((error51) => {
@@ -36279,15 +36780,14 @@ function installedManifest(status) {
36279
36780
  function managedEnvironment(manifest, environment) {
36280
36781
  return {
36281
36782
  ...environment,
36282
- CODEX_INSTALL_DIR: path23.dirname(manifest.wrapperPath),
36783
+ CODEX_INSTALL_DIR: path25.dirname(manifest.wrapperPath),
36283
36784
  CODEXHOST_STOCK_CODEX_PATH: manifest.stockCodexPath,
36284
36785
  CODEXHOST_HOST_NODE_PATH: manifest.nodePath,
36285
36786
  CODEXHOST_HOST_RUNTIME_PATH: manifest.hostRuntimePath,
36286
36787
  CODEXHOST_DATA_DIR: manifest.dataDirectory,
36287
36788
  CODEXHOST_DEFAULT_AGENT: "codex",
36288
36789
  CODEXHOST_REMOTE_SSH_MANAGED: "1",
36289
- ...manifest.claudeCommand ? { CODEXHOST_CLAUDE_COMMAND: manifest.claudeCommand } : {},
36290
- PATH: `${path23.dirname(manifest.wrapperPath)}${path23.delimiter}${path23.dirname(manifest.stockCodexPath)}${path23.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
36790
+ PATH: `${path25.dirname(manifest.wrapperPath)}${path25.delimiter}${path25.dirname(manifest.stockCodexPath)}${path25.delimiter}${environment.PATH ?? "/usr/bin:/bin"}`
36291
36791
  };
36292
36792
  }
36293
36793
  async function defaultRunTerminator(manifest, socketPath, role, environment) {
@@ -36435,9 +36935,6 @@ function parseRemoteCliArguments(arguments_2) {
36435
36935
  case "--stock-codex":
36436
36936
  options2.stockCodexPath = value2;
36437
36937
  break;
36438
- case "--claude-command":
36439
- options2.claudeCommand = value2;
36440
- break;
36441
36938
  case "--node":
36442
36939
  resources.nodePath = value2;
36443
36940
  break;
@@ -36464,7 +36961,7 @@ async function runRemoteHostCli(input) {
36464
36961
  output.write(
36465
36962
  [
36466
36963
  "usage:",
36467
- " codexhost remote install [--stock-codex PATH] [--claude-command PATH]",
36964
+ " codexhost remote install [--stock-codex PATH]",
36468
36965
  " codexhost remote start",
36469
36966
  " codexhost remote stop",
36470
36967
  " codexhost remote status",
@@ -36625,26 +37122,26 @@ function consumeBrokerFrames(socket, onFrame, onError) {
36625
37122
  }
36626
37123
 
36627
37124
  // packages/harness-broker/dist/paths.js
36628
- import os6 from "node:os";
36629
- import path24 from "node:path";
37125
+ import os7 from "node:os";
37126
+ import path26 from "node:path";
36630
37127
  var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
36631
37128
  var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
36632
37129
  var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
36633
37130
  function defaultHarnessBrokerDirectory(environment = process.env) {
36634
- const home = environment.HOME || os6.homedir();
36635
- return path24.join(home, ".codexhost", "harness-broker");
37131
+ const home = environment.HOME || os7.homedir();
37132
+ return path26.join(home, ".codexhost", "harness-broker");
36636
37133
  }
36637
37134
  function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
36638
37135
  harnessPluginIdSchema.parse(harnessId);
36639
37136
  if (harnessId !== "claude-code")
36640
- return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
36641
- return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
37137
+ return path26.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
37138
+ return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path26.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
36642
37139
  }
36643
37140
  function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
36644
37141
  harnessPluginIdSchema.parse(harnessId);
36645
37142
  if (harnessId !== "claude-code")
36646
- return path24.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
36647
- return path24.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
37143
+ return path26.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
37144
+ return path26.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
36648
37145
  }
36649
37146
 
36650
37147
  // packages/harness-broker/dist/validation.js
@@ -36858,9 +37355,9 @@ var harnessOutputSchema = external_exports.custom((value2) => {
36858
37355
 
36859
37356
  // packages/harness-broker/dist/server.js
36860
37357
  import { randomBytes as randomBytes3, randomUUID as randomUUID15 } from "node:crypto";
36861
- import { chmod as chmod5, lstat as lstat9, mkdir as mkdir11, open as open8, readFile as readFile9, rename as rename8, rm as rm11 } from "node:fs/promises";
37358
+ import { chmod as chmod5, lstat as lstat9, mkdir as mkdir11, open as open8, readFile as readFile10, rename as rename8, rm as rm11 } from "node:fs/promises";
36862
37359
  import net4, {} from "node:net";
36863
- import path25 from "node:path";
37360
+ import path27 from "node:path";
36864
37361
  function harnessError(message, retryable = true) {
36865
37362
  return { code: "unavailable", message, retryable, stage: "harnessBroker" };
36866
37363
  }
@@ -36906,7 +37403,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
36906
37403
  throw new Error("Harness broker descriptor is not owner-only");
36907
37404
  }
36908
37405
  }
36909
- const descriptor = harnessBrokerDescriptorSchema.parse(JSON.parse(await readFile9(descriptorPath, "utf8")));
37406
+ const descriptor = harnessBrokerDescriptorSchema.parse(JSON.parse(await readFile10(descriptorPath, "utf8")));
36910
37407
  if (processIsAlive2(descriptor.ownerPid)) {
36911
37408
  throw new Error("Harness broker descriptor already has a live owner");
36912
37409
  }
@@ -36983,13 +37480,13 @@ async function prepareUnixSocketPath(socketPath) {
36983
37480
  }
36984
37481
  async function startHarnessBrokerServer(input) {
36985
37482
  harnessPluginIdSchema.parse(input.adapter.harnessId);
36986
- if (process.platform !== "win32" && path25.dirname(input.descriptorPath) !== path25.dirname(input.socketPath)) {
37483
+ if (process.platform !== "win32" && path27.dirname(input.descriptorPath) !== path27.dirname(input.socketPath)) {
36987
37484
  throw new Error("Harness broker descriptor and socket must share one private directory");
36988
37485
  }
36989
37486
  if (process.platform === "darwin" && Buffer.byteLength(input.socketPath) > 103) {
36990
37487
  throw new Error("Harness broker Unix socket path is too long for macOS");
36991
37488
  }
36992
- await privateDirectory(path25.dirname(input.descriptorPath));
37489
+ await privateDirectory(path27.dirname(input.descriptorPath));
36993
37490
  await assertNoLiveDescriptor(input.descriptorPath);
36994
37491
  if (process.platform !== "win32")
36995
37492
  await prepareUnixSocketPath(input.socketPath);