@codexhost/cli-darwin-x64 0.13.3 → 0.14.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.
@@ -3716,8 +3716,10 @@ List Harnesses available in the active Runtime.`,
3716
3716
  "harness inspect": `codexhost harness inspect <harness> [--cwd <path>] [--refresh true|false] [--format json|compact]
3717
3717
  Read available Models, native defaults, Thinking options, and configuration capabilities.
3718
3718
  Use the returned Model and Thinking IDs for explicit selections.`,
3719
- "delegate start": `codexhost delegate start --harness <id> --task <text> [--cwd <path>] [--model <opaque-ref>] [--thinking <option-id>] [--parent-thread <thread>] [--request-id <id>] [--watch true|false] [--watch-timeout-ms <n>] [--format json|compact]
3719
+ "delegate start": `codexhost delegate start --harness <id> --task <text> [--task-name <name>] [--cwd <path>] [--model <opaque-ref>] [--thinking <option-id>] [--parent-thread <thread>] [--request-id <id>] [--watch true|false] [--watch-timeout-ms <n>] [--format json|compact]
3720
3720
  Create an independent child Thread, submit the task, and return immediately.
3721
+ --task-name supplies a short subtask name (1-120 characters); otherwise the first task line is used.
3722
+ The child title is "subtask name · parent title", fixed at creation; renaming the parent does not rename existing children.
3721
3723
  Omit --model and --thinking to use the Harness native defaults.
3722
3724
  --cwd overrides the child workspace. Otherwise use the resolved parent Thread workspace, then the Host Runtime process cwd.
3723
3725
  --parent-thread overrides caller inference. PARENT_THREAD_AMBIGUOUS requires an explicit parent.
@@ -4161,6 +4163,7 @@ async function runDelegationCli(input) {
4161
4163
  rejectUnknown(parsed2, [
4162
4164
  "--harness",
4163
4165
  "--task",
4166
+ "--task-name",
4164
4167
  "--cwd",
4165
4168
  "--model",
4166
4169
  "--thinking",
@@ -4195,6 +4198,7 @@ async function runDelegationCli(input) {
4195
4198
  body: {
4196
4199
  harnessId,
4197
4200
  task,
4201
+ ...value(parsed2, "--task-name") !== void 0 ? { taskName: value(parsed2, "--task-name") } : {},
4198
4202
  ...value(parsed2, "--cwd") ? { cwd: value(parsed2, "--cwd") } : {},
4199
4203
  ...value(parsed2, "--model") ? { model: { id: value(parsed2, "--model") } } : {},
4200
4204
  ...value(parsed2, "--thinking") ? { thinkingOptionId: value(parsed2, "--thinking") } : {},
@@ -20089,10 +20093,19 @@ var model = external_exports.string().min(1).max(512);
20089
20093
  var project = external_exports.string().min(1).max(4096);
20090
20094
  var usageStatisticsParamsSchema = external_exports.strictObject({
20091
20095
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
20096
+ /** Display timezone for ranges, dates and hourly buckets; omitted means the Host's local zone. */
20097
+ timeZone: external_exports.string().min(1).max(128).refine((value2) => {
20098
+ try {
20099
+ new Intl.DateTimeFormat("en", { timeZone: value2 });
20100
+ return true;
20101
+ } catch {
20102
+ return false;
20103
+ }
20104
+ }, "Unsupported usage statistics timezone").optional(),
20092
20105
  harness: harness.optional(),
20093
20106
  model: model.nullable().optional(),
20094
20107
  project: project.nullable().optional(),
20095
- /** One local date inside the range. */
20108
+ /** One date in the query timezone inside the range. */
20096
20109
  date: localDate.optional()
20097
20110
  });
20098
20111
  var usageStatisticsTotalsSchema = external_exports.strictObject({
@@ -20128,7 +20141,7 @@ var usageStatisticsSessionSchema = external_exports.strictObject({
20128
20141
  });
20129
20142
  var usageStatisticsResultSchema = external_exports.strictObject({
20130
20143
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
20131
- /** First local date of the range; null for all time. */
20144
+ /** First date in the query timezone (Host local when omitted); null for all time. */
20132
20145
  from: localDate.nullable(),
20133
20146
  to: localDate,
20134
20147
  /** The filters these figures apply, echoed so a late answer to older filters is recognised. */
@@ -20168,7 +20181,7 @@ var usageStatisticsResultSchema = external_exports.strictObject({
20168
20181
  totals: usageStatisticsTotalsSchema,
20169
20182
  /** Each date and Harness of the range: every filter except the day. */
20170
20183
  daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
20171
- /** Local weekday (0 = Sunday) and hour, all filters applied. */
20184
+ /** Weekday (0 = Sunday) and hour in the query timezone, all filters applied. */
20172
20185
  hourly: external_exports.array(external_exports.strictObject({
20173
20186
  weekday: external_exports.number().int().min(0).max(6),
20174
20187
  hour: external_exports.number().int().min(0).max(23),
@@ -20231,6 +20244,8 @@ var CONSOLE_HOST_METHODS = Object.freeze([
20231
20244
  "codexhost/harness/display-settings/set",
20232
20245
  "codexhost/harness/inspect",
20233
20246
  "codexhost/harness/installation",
20247
+ "codexhost/harness/installation/start",
20248
+ "codexhost/harness/installation/status",
20234
20249
  "codexhost/harness/launch-settings/get",
20235
20250
  "codexhost/harness/launch-settings/set",
20236
20251
  "codexhost/harness/web-ui/open",
@@ -20312,7 +20327,18 @@ var threadManualCompactionStartedSchema = external_exports.strictObject({
20312
20327
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
20313
20328
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
20314
20329
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
20330
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
20331
+ var composerIndicatorsSchema = external_exports.array(external_exports.object({
20332
+ kind: external_exports.literal("countdown"),
20333
+ id: external_exports.string().min(1).max(64),
20334
+ expiresAtUnix: nonNegativeSafeIntegerSchema,
20335
+ label: indicatorTextSchema(256).optional(),
20336
+ tooltip: indicatorTextSchema(1024).optional()
20337
+ }).strict()).max(2).refine((entries) => new Set(entries.map(({ id: id2 }) => id2)).size === entries.length, {
20338
+ message: "Composer indicator IDs must be unique"
20339
+ });
20315
20340
  var threadUsageSnapshotSchema = external_exports.object({
20341
+ composerIndicators: composerIndicatorsSchema.optional(),
20316
20342
  inputTokens: nonNegativeSafeIntegerSchema.optional(),
20317
20343
  cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
20318
20344
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -20728,7 +20754,9 @@ var harnessSessionCapabilitiesSchema = external_exports.object({
20728
20754
  }).strict().optional(),
20729
20755
  autonomousTurns: external_exports.object({
20730
20756
  observe: external_exports.boolean()
20731
- }).strict().optional()
20757
+ }).strict().optional(),
20758
+ /** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
20759
+ steer: external_exports.boolean().optional()
20732
20760
  }).strict();
20733
20761
  var harnessConfigurationStateSchema = external_exports.object({
20734
20762
  effectiveModel: harnessModelRefSchema.optional(),
@@ -20776,7 +20804,9 @@ var harnessInspectionSchema = external_exports.union([
20776
20804
  var harnessInspectParamsSchema = external_exports.object({
20777
20805
  harnessId: harnessIdSchema,
20778
20806
  cwd: nonBlankTextSchema2.max(16384).optional(),
20779
- refresh: external_exports.boolean().optional()
20807
+ refresh: external_exports.boolean().optional(),
20808
+ /** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
20809
+ purpose: external_exports.literal("availability").optional()
20780
20810
  }).strict();
20781
20811
  var harnessWebUiOpenParamsSchema = external_exports.object({
20782
20812
  harnessId: harnessIdSchema
@@ -20859,6 +20889,16 @@ var threadOwnershipListResultSchema = external_exports.object({
20859
20889
  seen.add(thread.threadId);
20860
20890
  }
20861
20891
  });
20892
+ var threadSteeringInspectParamsSchema = external_exports.object({
20893
+ threadId: hostThreadIdSchema,
20894
+ /** The text about to be steered; a Harness command always stops and restarts. */
20895
+ text: external_exports.string().optional()
20896
+ }).strict();
20897
+ var THREAD_STEER_DELIVERY_PARAM = "codexhostSteerDelivery";
20898
+ var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
20899
+ var threadSteeringInspectResultSchema = external_exports.object({
20900
+ delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
20901
+ }).strict();
20862
20902
 
20863
20903
  // packages/shared-contracts/dist/harness-plugins.js
20864
20904
  var HARNESS_PLUGIN_API_VERSION = 1;
@@ -20979,6 +21019,8 @@ var harnessLaunchSettingsSchema = external_exports.object({
20979
21019
 
20980
21020
  // packages/shared-contracts/dist/harness-installation.js
20981
21021
  var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
21022
+ var HARNESS_INSTALLATION_START_METHOD = "codexhost/harness/installation/start";
21023
+ var HARNESS_INSTALLATION_STATUS_METHOD = "codexhost/harness/installation/status";
20982
21024
  var harnessInstallationParamsSchema = external_exports.object({
20983
21025
  harnessId: harnessIdSchema,
20984
21026
  action: external_exports.enum(["check", "update", "install"])
@@ -20988,6 +21030,10 @@ var harnessInstallationStateSchema = external_exports.object({
20988
21030
  latestVersion: external_exports.string().min(1).max(128),
20989
21031
  updateAvailable: external_exports.boolean(),
20990
21032
  canUpdate: external_exports.boolean(),
21033
+ /** Defaults to CLI; some Harnesses ship only inside a desktop application. */
21034
+ versionKind: external_exports.enum(["cli", "application"]).optional(),
21035
+ /** Official download opened by the user; does not imply an automatic installation. */
21036
+ manualUpdateUrl: external_exports.url().max(2048).refine((value2) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value2), "Manual updates require a credential-free HTTPS URL").optional(),
20991
21037
  // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
20992
21038
  message: external_exports.string().max(2048).optional(),
20993
21039
  messageCode: external_exports.string().min(1).max(128).optional(),
@@ -20995,6 +21041,20 @@ var harnessInstallationStateSchema = external_exports.object({
20995
21041
  notice: harnessLocalizedTextSchema.optional(),
20996
21042
  latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
20997
21043
  }).strict();
21044
+ var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
21045
+ var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
21046
+ external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
21047
+ external_exports.object({
21048
+ taskId: external_exports.string().uuid(),
21049
+ status: external_exports.literal("succeeded"),
21050
+ result: harnessInstallationStateSchema
21051
+ }).strict(),
21052
+ external_exports.object({
21053
+ taskId: external_exports.string().uuid(),
21054
+ status: external_exports.literal("failed"),
21055
+ error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
21056
+ }).strict()
21057
+ ]);
20998
21058
 
20999
21059
  // packages/shared-contracts/dist/codex-accounts.js
21000
21060
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
@@ -22982,9 +23042,13 @@ function requestManagerFromHookState(value2, hostId2) {
22982
23042
  const direct = manager(value2) ?? manager(value2.manager);
22983
23043
  if (direct)
22984
23044
  return direct;
22985
- if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function" || typeof value2.waitForManagerForHostId !== "function")
23045
+ if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function")
22986
23046
  return null;
22987
- return manager(value2.getForHostId(hostId2));
23047
+ try {
23048
+ return manager(value2.getForHostId(hostId2));
23049
+ } catch {
23050
+ return null;
23051
+ }
22988
23052
  }
22989
23053
  function discoverRendererHosts(root, ancestors = committedReactAncestors, managerFrom = requestManagerFromHookState) {
22990
23054
  const editors = [
@@ -23020,7 +23084,7 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
23020
23084
  const manager = managerFrom(value2);
23021
23085
  if (manager)
23022
23086
  managers.add(manager);
23023
- if (value2 && typeof value2 === "object" && "addManager" in value2 && typeof value2.addManager === "function" && "getForHostId" in value2 && typeof value2.getForHostId === "function" && "waitForManagerForHostId" in value2 && typeof value2.waitForManagerForHostId === "function") {
23087
+ if (value2 && typeof value2 === "object" && "addManager" in value2 && typeof value2.addManager === "function" && "getForHostId" in value2 && typeof value2.getForHostId === "function") {
23024
23088
  registries.add(value2);
23025
23089
  }
23026
23090
  hook = hook.next && typeof hook.next === "object" ? hook.next : null;
@@ -23036,7 +23100,13 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
23036
23100
  function resolveRendererHostManager(discovery, hostId2, managerFrom = requestManagerFromHookState) {
23037
23101
  if (!hostId2)
23038
23102
  return null;
23039
- const candidates = discovery.registries.length ? discovery.registries.map((registry2) => managerFrom(registry2.getForHostId(hostId2))) : discovery.managers;
23103
+ const candidates = discovery.registries.length ? discovery.registries.flatMap((registry2) => {
23104
+ try {
23105
+ return [managerFrom(registry2.getForHostId(hostId2))];
23106
+ } catch {
23107
+ return [];
23108
+ }
23109
+ }) : discovery.managers;
23040
23110
  const matching = new Set(candidates.filter((manager) => manager && (manager.getHostId?.() ?? manager.requestClient.hostId) === hostId2 && (manager.requestClient.hostId === void 0 || manager.requestClient.hostId === hostId2)));
23041
23111
  return matching.size === 1 ? matching.values().next().value ?? null : null;
23042
23112
  }
@@ -24048,6 +24118,64 @@ async function handleHarnessInstallation(params, adapters) {
24048
24118
  }
24049
24119
  }
24050
24120
 
24121
+ // packages/host-runtime/src/harness-installation-tasks.ts
24122
+ import { randomUUID as randomUUID3 } from "node:crypto";
24123
+ var HarnessInstallationTasks = class {
24124
+ #tasks = /* @__PURE__ */ new Map();
24125
+ #active = /* @__PURE__ */ new Map();
24126
+ #prune() {
24127
+ const cutoff = Date.now() - 15 * 6e4;
24128
+ for (const [id2, task] of this.#tasks) {
24129
+ if (task.finishedAt !== void 0 && task.finishedAt < cutoff) this.#tasks.delete(id2);
24130
+ }
24131
+ }
24132
+ start(params, adapters) {
24133
+ const parsed2 = harnessInstallationParamsSchema.safeParse(params);
24134
+ if (!parsed2.success)
24135
+ throw new HarnessInstallationError(-32602, "Invalid Harness installation request");
24136
+ this.#prune();
24137
+ const key = JSON.stringify([parsed2.data.harnessId, parsed2.data.action]);
24138
+ const activeId = this.#active.get(key);
24139
+ const active = activeId ? this.#tasks.get(activeId) : void 0;
24140
+ if (active) return active.state;
24141
+ const taskId = randomUUID3();
24142
+ const task = {
24143
+ state: { taskId, status: "running" }
24144
+ };
24145
+ this.#tasks.set(taskId, task);
24146
+ this.#active.set(key, taskId);
24147
+ void handleHarnessInstallation(parsed2.data, adapters).then(
24148
+ (result) => {
24149
+ task.state = { taskId, status: "succeeded", result };
24150
+ },
24151
+ (error51) => {
24152
+ task.state = {
24153
+ taskId,
24154
+ status: "failed",
24155
+ error: error51 instanceof HarnessInstallationError ? { code: error51.code, message: error51.message } : { code: -32077, message: "Harness version management failed" }
24156
+ };
24157
+ }
24158
+ ).finally(() => {
24159
+ task.finishedAt = Date.now();
24160
+ this.#active.delete(key);
24161
+ });
24162
+ return task.state;
24163
+ }
24164
+ status(params) {
24165
+ const parsed2 = harnessInstallationTaskParamsSchema.safeParse(params);
24166
+ if (!parsed2.success)
24167
+ throw new HarnessInstallationError(-32602, "Invalid Harness installation task request");
24168
+ this.#prune();
24169
+ const task = this.#tasks.get(parsed2.data.taskId);
24170
+ if (!task)
24171
+ throw new HarnessInstallationError(
24172
+ -32079,
24173
+ "Harness installation task is unavailable on this Host"
24174
+ );
24175
+ return task.state;
24176
+ }
24177
+ };
24178
+
24051
24179
  // packages/host-runtime/src/account/codex-credential-export.ts
24052
24180
  import { createHash as createHash3 } from "node:crypto";
24053
24181
  import { readFile as readFile8 } from "node:fs/promises";
@@ -24140,7 +24268,7 @@ async function listOthers(adapter) {
24140
24268
  }
24141
24269
 
24142
24270
  // packages/host-runtime/src/harness-display-settings.ts
24143
- import { randomUUID as randomUUID3 } from "node:crypto";
24271
+ import { randomUUID as randomUUID4 } from "node:crypto";
24144
24272
  import { link, mkdir as mkdir6, readFile as readFile9, rename as rename4, rm as rm5, writeFile as writeFile6 } from "node:fs/promises";
24145
24273
  import os4 from "node:os";
24146
24274
  import path13 from "node:path";
@@ -24165,7 +24293,7 @@ var HarnessDisplaySettingsStore = class {
24165
24293
  async set(input) {
24166
24294
  const entries = harnessDisplayEntriesSchema.parse(input.entries);
24167
24295
  await mkdir6(path13.dirname(this.#file), { recursive: true, mode: 448 });
24168
- const temporary = `${this.#file}.${randomUUID3()}.tmp`;
24296
+ const temporary = `${this.#file}.${randomUUID4()}.tmp`;
24169
24297
  try {
24170
24298
  await writeFile6(temporary, `${JSON.stringify(entries)}
24171
24299
  `, { mode: 384, flag: "wx" });
@@ -24186,7 +24314,7 @@ var HarnessDisplaySettingsStore = class {
24186
24314
  };
24187
24315
 
24188
24316
  // packages/host-runtime/src/model-price-overrides-file.ts
24189
- import { randomUUID as randomUUID4 } from "node:crypto";
24317
+ import { randomUUID as randomUUID5 } from "node:crypto";
24190
24318
  import { mkdir as mkdir8, readFile as readFile11, rename as rename6, rm as rm6, writeFile as writeFile8 } from "node:fs/promises";
24191
24319
  import path15 from "node:path";
24192
24320
 
@@ -24761,7 +24889,7 @@ async function updateModelPriceOverridesFile(file2, change) {
24761
24889
  const updated = { ...document, models: next };
24762
24890
  parseModelPriceOverrides(updated);
24763
24891
  await mkdir8(path15.dirname(file2), { recursive: true });
24764
- const temporary = `${file2}.${randomUUID4()}.tmp`;
24892
+ const temporary = `${file2}.${randomUUID5()}.tmp`;
24765
24893
  try {
24766
24894
  await writeFile8(temporary, `${JSON.stringify(updated, null, 2)}
24767
24895
  `, { flag: "wx" });
@@ -24797,11 +24925,11 @@ async function handleModelPriceOverridesRequest(catalog, method, params) {
24797
24925
  }
24798
24926
 
24799
24927
  // packages/host-runtime/src/delegation-skill.ts
24800
- import { createHash as createHash4, randomUUID as randomUUID5 } from "node:crypto";
24928
+ import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
24801
24929
  import { mkdir as mkdir9, open as open4, readFile as readFile12, rename as rename7, rm as rm7, stat as stat5 } from "node:fs/promises";
24802
24930
  import os6 from "node:os";
24803
24931
  import path16 from "node:path";
24804
- var SKILL_VERSION = 9;
24932
+ var SKILL_VERSION = 10;
24805
24933
  var DELEGATION_SKILL_NAME = "codexhost-delegation";
24806
24934
  var SKILL_RELATIVE_PATH = path16.join("skills", DELEGATION_SKILL_NAME, "SKILL.md");
24807
24935
  var PREVIOUS_MANAGED_DIGESTS = [
@@ -24815,7 +24943,9 @@ var PREVIOUS_MANAGED_DIGESTS = [
24815
24943
  "fa7944cd1e72ffbaf932fca2074bdb78aad4670d8990b6711220dd83c39509a0",
24816
24944
  "b9c1cce41d2556e73a6514aa55618d7d3f2f9ef935f5ae50b0da5a04941514b4",
24817
24945
  // v8, which ran a bare `codexhost` from PATH.
24818
- "ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde"
24946
+ "ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde",
24947
+ // v9, before the child-session name guidance.
24948
+ "b72a059e139bd5b93b95f7ac02ab80f428d5a721cc67b004210d5263e75baed7"
24819
24949
  ];
24820
24950
  var CODEXHOST_DELEGATION_SKILL = `---
24821
24951
  name: codexhost-delegation
@@ -24852,7 +24982,8 @@ Use the Harness native defaults. Inspect the target when a Model or Thinking
24852
24982
  selection is needed or the default is unavailable.
24853
24983
 
24854
24984
  For a new delegation, create an independent child session and submit the
24855
- requested task. For an existing external session, resolve the target from the
24985
+ requested task. Give it a short task name that tells it apart from sibling
24986
+ tasks, using the help's task-name option. For an existing external session, resolve the target from the
24856
24987
  user-provided session link, identifier, or context and operate on that Thread
24857
24988
  directly; it need not have been created by the current assistant. If the target
24858
24989
  is ambiguous, ask the user to identify it. Keep requests to view or summarize a
@@ -24894,7 +25025,7 @@ async function readOptional(filePath) {
24894
25025
  }
24895
25026
  async function atomicWrite(filePath, content) {
24896
25027
  await mkdir9(path16.dirname(filePath), { recursive: true, mode: 448 });
24897
- const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID5()}.tmp`);
25028
+ const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID6()}.tmp`);
24898
25029
  const handle = await open4(temporaryPath, "wx", 384);
24899
25030
  try {
24900
25031
  await handle.writeFile(content, "utf8");
@@ -25131,6 +25262,7 @@ var usageFields = /* @__PURE__ */ new Set([
25131
25262
  ...safeIntegerFields,
25132
25263
  ...percentFields,
25133
25264
  "sessionCacheUsage",
25265
+ "composerIndicators",
25134
25266
  "totalCostUsd",
25135
25267
  "totalCredits",
25136
25268
  "contextUsagePercent",
@@ -25153,6 +25285,7 @@ function parseHostUsage(value2) {
25153
25285
  throw new Error(`Harness Usage contains unknown field '${key}'`);
25154
25286
  }
25155
25287
  }
25288
+ const indicators = value2.composerIndicators === void 0 ? {} : { composerIndicators: composerIndicatorsSchema.parse(value2.composerIndicators) };
25156
25289
  for (const field of [
25157
25290
  "totalCredits",
25158
25291
  "contextUsagePercent",
@@ -25223,9 +25356,9 @@ function parseHostUsage(value2) {
25223
25356
  if (value2.costSource !== "publicPrice") {
25224
25357
  throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
25225
25358
  }
25226
- return { ...value2, unpricedModels: [...models] };
25359
+ return { ...value2, ...indicators, unpricedModels: [...models] };
25227
25360
  }
25228
- return { ...value2 };
25361
+ return { ...value2, ...indicators };
25229
25362
  }
25230
25363
  var requestTokenFields = [
25231
25364
  "inputTokens",
@@ -25376,7 +25509,7 @@ var packageMetadata = {
25376
25509
 
25377
25510
  // packages/mapping-store/dist/mapping-store.js
25378
25511
  import { execFileSync } from "node:child_process";
25379
- import { randomUUID as randomUUID8 } from "node:crypto";
25512
+ import { randomUUID as randomUUID9 } from "node:crypto";
25380
25513
  import { constants as constants3 } from "node:fs";
25381
25514
  import { copyFile as copyFile3, mkdir as mkdir11, open as open7, readFile as readFile15, readdir as readdir4, rename as rename10, rm as rm10, stat as stat6 } from "node:fs/promises";
25382
25515
  import path18 from "node:path";
@@ -25436,7 +25569,7 @@ var storedThreadMetadataV1Schema = external_exports.object({
25436
25569
  formatVersion: external_exports.literal(1),
25437
25570
  hostThreadId: storedHostThreadIdSchema,
25438
25571
  ...storedThreadMetadataFieldsShape
25439
- }).strict();
25572
+ }).passthrough();
25440
25573
  function refineThreadRecord(record4, context) {
25441
25574
  if (record4.state === "ready" && !record4.nativeSessionRef) {
25442
25575
  context.addIssue({
@@ -25495,8 +25628,8 @@ function refineThreadRecord(record4, context) {
25495
25628
  }
25496
25629
  }
25497
25630
  }
25498
- var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).strict().superRefine(refineThreadRecord);
25499
- var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).strict().superRefine(refineThreadRecord);
25631
+ var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).passthrough().superRefine(refineThreadRecord);
25632
+ var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).passthrough().superRefine(refineThreadRecord);
25500
25633
  var delegationStatusSchema = external_exports.enum([
25501
25634
  "creating",
25502
25635
  "running",
@@ -25523,7 +25656,7 @@ var storedDelegationRecordV1Schema = external_exports.object({
25523
25656
  });
25524
25657
 
25525
25658
  // packages/mapping-store/dist/section-placements.js
25526
- import { randomUUID as randomUUID6 } from "node:crypto";
25659
+ import { randomUUID as randomUUID7 } from "node:crypto";
25527
25660
  import { constants } from "node:fs";
25528
25661
  import { open as open5, readFile as readFile13, rename as rename8, rm as rm8 } from "node:fs/promises";
25529
25662
  var threadIdSchema = external_exports.string().min(1).max(1024);
@@ -25575,7 +25708,7 @@ async function readSectionPlacementsFile(file2) {
25575
25708
  }
25576
25709
  async function writeSectionPlacementsFile(file2, placements) {
25577
25710
  const parsed2 = parseSectionPlacements({ formatVersion: 1, placements });
25578
- const temp = `${file2}.tmp-${randomUUID6()}`;
25711
+ const temp = `${file2}.tmp-${randomUUID7()}`;
25579
25712
  let handle = null;
25580
25713
  try {
25581
25714
  handle = await open5(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
@@ -25594,7 +25727,7 @@ async function writeSectionPlacementsFile(file2, placements) {
25594
25727
  }
25595
25728
 
25596
25729
  // packages/mapping-store/dist/superseded-sessions.js
25597
- import { randomUUID as randomUUID7 } from "node:crypto";
25730
+ import { randomUUID as randomUUID8 } from "node:crypto";
25598
25731
  import { constants as constants2 } from "node:fs";
25599
25732
  import { mkdir as mkdir10, open as open6, readFile as readFile14, rename as rename9, rm as rm9 } from "node:fs/promises";
25600
25733
  import path17 from "node:path";
@@ -25629,7 +25762,7 @@ async function writeSupersededSessionsFile(file2, sessions) {
25629
25762
  formatVersion: 1,
25630
25763
  sessions: sessions.slice(-SUPERSEDED_SESSIONS_MAX)
25631
25764
  }).sessions;
25632
- const temp = `${file2}.tmp-${randomUUID7()}`;
25765
+ const temp = `${file2}.tmp-${randomUUID8()}`;
25633
25766
  let handle = null;
25634
25767
  try {
25635
25768
  await mkdir10(path17.dirname(file2), { recursive: true });
@@ -25874,7 +26007,7 @@ var MappingStore = class {
25874
26007
  this.#sectionsDirectory = path18.join(this.#directory, "sections");
25875
26008
  this.#metadataDirectory = path18.join(this.#directory, "thread-metadata");
25876
26009
  this.#lockPath = path18.join(this.#directory, "store.lock");
25877
- this.#instanceId = options2.instanceId ?? randomUUID8();
26010
+ this.#instanceId = options2.instanceId ?? randomUUID9();
25878
26011
  this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
25879
26012
  this.#beforeReplace = options2.beforeReplace;
25880
26013
  }
@@ -26398,7 +26531,7 @@ var MappingStore = class {
26398
26531
  this.#rebuildIndexes();
26399
26532
  }
26400
26533
  async #replaceFile(target, record4, preserveBackup) {
26401
- const temp = `${target}.tmp-${randomUUID8()}`;
26534
+ const temp = `${target}.tmp-${randomUUID9()}`;
26402
26535
  let handle = null;
26403
26536
  try {
26404
26537
  await this.#beforeReplace?.(cloneRecord(record4));
@@ -26422,18 +26555,20 @@ var MappingStore = class {
26422
26555
  });
26423
26556
  }
26424
26557
  }
26425
- /** Atomically writes, or with null removes, a Thread's Desktop metadata file. */
26558
+ /** Atomically patches owned metadata fields, retaining unknown fields on disk. */
26426
26559
  async #writeMetadataFile(hostThreadId, metadata) {
26427
26560
  const target = this.#metadataPath(hostThreadId);
26428
- const temp = `${target}.tmp-${randomUUID8()}`;
26561
+ const temp = `${target}.tmp-${randomUUID9()}`;
26429
26562
  let handle = null;
26430
26563
  try {
26431
- if (!metadata) {
26564
+ const retained = Object.fromEntries(Object.entries(await this.#readMetadata(hostThreadId) ?? {}).filter(([name]) => !["formatVersion", "hostThreadId", ...THREAD_METADATA_FIELDS].includes(name)));
26565
+ if (!metadata && Object.keys(retained).length === 0) {
26432
26566
  await rm10(target, { force: true });
26433
26567
  return;
26434
26568
  }
26569
+ const next = { ...retained, formatVersion: 1, hostThreadId, ...metadata };
26435
26570
  handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
26436
- await handle.writeFile(`${JSON.stringify(metadata, null, 2)}
26571
+ await handle.writeFile(`${JSON.stringify(next, null, 2)}
26437
26572
  `, "utf8");
26438
26573
  await handle.sync();
26439
26574
  await handle.close();
@@ -26470,7 +26605,7 @@ var MappingStore = class {
26470
26605
  }
26471
26606
  async #replaceDelegationFile(record4) {
26472
26607
  const target = this.#delegationPath(record4.delegationId);
26473
- const temp = `${target}.tmp-${randomUUID8()}`;
26608
+ const temp = `${target}.tmp-${randomUUID9()}`;
26474
26609
  let handle = null;
26475
26610
  try {
26476
26611
  handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
@@ -28155,8 +28290,18 @@ function collabAgentStatus(status2) {
28155
28290
  return "interrupted";
28156
28291
  }
28157
28292
  }
28293
+ function projectUserMessage(item, clientId) {
28294
+ return {
28295
+ id: item.itemId,
28296
+ type: "userMessage",
28297
+ clientId,
28298
+ content: item.input.map(({ text }) => ({ type: "text", text, text_elements: [] }))
28299
+ };
28300
+ }
28158
28301
  function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, senderThreadId) {
28159
28302
  switch (item.type) {
28303
+ case "userMessage":
28304
+ return projectUserMessage(item, null);
28160
28305
  case "agentMessage":
28161
28306
  return {
28162
28307
  id: item.itemId,
@@ -28368,6 +28513,7 @@ var CodexTurnProjector = class {
28368
28513
  #interactions = /* @__PURE__ */ new Map();
28369
28514
  #items = /* @__PURE__ */ new Map();
28370
28515
  #wireItemOrder = [];
28516
+ #userMessageClientIds = /* @__PURE__ */ new Map();
28371
28517
  #startedAt;
28372
28518
  #startedAtMs;
28373
28519
  #threadId;
@@ -28409,6 +28555,10 @@ var CodexTurnProjector = class {
28409
28555
  }
28410
28556
  return items;
28411
28557
  }
28558
+ /** Associate steered input with the Desktop message that submitted it, before it is published. */
28559
+ bindUserMessageClientId(itemId, clientId) {
28560
+ this.#userMessageClientIds.set(itemId, clientId);
28561
+ }
28412
28562
  pendingTurn(startedAt = null) {
28413
28563
  return {
28414
28564
  id: this.#turnId,
@@ -28419,6 +28569,8 @@ var CodexTurnProjector = class {
28419
28569
  const projected = this.#items.get(itemId);
28420
28570
  if (!projected?.wireStarted)
28421
28571
  return [];
28572
+ if (projected.item.type === "userMessage")
28573
+ return [this.#projectItem(projected.item)];
28422
28574
  if (projected.item.type === "agentMessage") {
28423
28575
  return [projectItem(projected.item, projected.outcome, this.#cwd)];
28424
28576
  }
@@ -28746,7 +28898,7 @@ var CodexTurnProjector = class {
28746
28898
  return { messages: [] };
28747
28899
  }
28748
28900
  const messages = [
28749
- completedItem(projectItem(projected.item, projected.outcome, this.#cwd, !projected.streamedCommandOutput, this.#threadId))
28901
+ completedItem(this.#projectItem(projected.item, projected.outcome, !projected.streamedCommandOutput))
28750
28902
  ];
28751
28903
  if (projected.item.type === "reasoning") {
28752
28904
  const reasoning = projected.item;
@@ -28811,6 +28963,8 @@ var CodexTurnProjector = class {
28811
28963
  projectReasoningTranscriptItem(reasoning, projected.outcome, this.#cwd, projected.durationMs ?? null)
28812
28964
  ];
28813
28965
  }
28966
+ if (projected.item.type === "userMessage")
28967
+ return [this.#projectItem(projected.item)];
28814
28968
  if (projected.item.type === "agentMessage") {
28815
28969
  return [projectItem(projected.item, projected.outcome, this.#cwd)];
28816
28970
  }
@@ -28896,10 +29050,13 @@ var CodexTurnProjector = class {
28896
29050
  threadId: this.#threadId,
28897
29051
  turnId: this.#turnId,
28898
29052
  startedAtMs,
28899
- item: projectItem(item, null, this.#cwd, true, this.#threadId)
29053
+ item: this.#projectItem(item, null)
28900
29054
  }
28901
29055
  };
28902
29056
  }
29057
+ #projectItem(item, outcome = null, includeCommandOutput = true) {
29058
+ return item.type === "userMessage" ? projectUserMessage(item, this.#userMessageClientIds.get(item.itemId) ?? null) : projectItem(item, outcome, this.#cwd, includeCommandOutput, this.#threadId);
29059
+ }
28903
29060
  #startReasoningTranscript(item, startedAtMs) {
28904
29061
  return {
28905
29062
  method: "item/started",
@@ -30291,7 +30448,7 @@ var HarnessAccountInspectionCache = class {
30291
30448
  };
30292
30449
 
30293
30450
  // packages/host-runtime/src/app-server-host.ts
30294
- import { createHash as createHash9, randomUUID as randomUUID14 } from "node:crypto";
30451
+ import { createHash as createHash9, randomUUID as randomUUID16 } from "node:crypto";
30295
30452
  import os8 from "node:os";
30296
30453
  import path25 from "node:path";
30297
30454
 
@@ -30299,12 +30456,12 @@ import path25 from "node:path";
30299
30456
  import nodePath from "node:path";
30300
30457
 
30301
30458
  // packages/host-runtime/src/external-thread-repository.ts
30302
- import { randomUUID as randomUUID10 } from "node:crypto";
30459
+ import { randomUUID as randomUUID11 } from "node:crypto";
30303
30460
  import os7 from "node:os";
30304
30461
  import path22 from "node:path";
30305
30462
 
30306
30463
  // packages/host-runtime/src/external-subagent-threads.ts
30307
- import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
30464
+ import { createHash as createHash6, randomUUID as randomUUID10 } from "node:crypto";
30308
30465
  function childCreateRequest(parent, nativeRef, id2) {
30309
30466
  const key = createHash6("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
30310
30467
  return `subagent:${key}`;
@@ -30379,7 +30536,7 @@ function subagentMaterializer(store, parent, previousParent) {
30379
30536
  return rebind(existing, parent);
30380
30537
  }
30381
30538
  const provisional = existing ?? await store.createProvisional({
30382
- hostThreadId: hostThreadIdSchema.parse(randomUUID9()),
30539
+ hostThreadId: hostThreadIdSchema.parse(randomUUID10()),
30383
30540
  createRequestId,
30384
30541
  harnessId: parent.harnessId,
30385
30542
  cwd: parent.cwd,
@@ -30552,7 +30709,7 @@ var ExternalThreadRepository = class {
30552
30709
  throw new Error("Derived Snapshot identity does not belong to its Native Session");
30553
30710
  }
30554
30711
  return {
30555
- hostTurnId: hostTurnIdSchema.parse(randomUUID10()),
30712
+ hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
30556
30713
  nativeTurnRef: turn.nativeTurnRef,
30557
30714
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
30558
30715
  };
@@ -30675,14 +30832,14 @@ var ExternalThreadRepository = class {
30675
30832
  const aligned = snapshot2.turns.map((turn) => {
30676
30833
  const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
30677
30834
  const mapping = existing ?? {
30678
- hostTurnId: hostTurnIdSchema.parse(randomUUID10()),
30835
+ hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
30679
30836
  nativeTurnRef: turn.nativeTurnRef,
30680
30837
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
30681
30838
  };
30682
30839
  return {
30683
30840
  snapshot: turn,
30684
30841
  mapping: {
30685
- ...mapping,
30842
+ hostTurnId: mapping.hostTurnId,
30686
30843
  nativeTurnRef: turn.nativeTurnRef,
30687
30844
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
30688
30845
  }
@@ -30702,8 +30859,8 @@ var ExternalThreadRepository = class {
30702
30859
  };
30703
30860
  function createExternalThreadRecordInput(input) {
30704
30861
  return {
30705
- hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID10()),
30706
- createRequestId: input.createRequestId ?? randomUUID10(),
30862
+ hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID11()),
30863
+ createRequestId: input.createRequestId ?? randomUUID11(),
30707
30864
  harnessId: input.harnessId,
30708
30865
  cwd: input.cwd,
30709
30866
  ...input.title ? { title: input.title } : {},
@@ -30821,6 +30978,15 @@ async function executeExternalThreadFork(input) {
30821
30978
  boundaryIndex = mappings.length - 1;
30822
30979
  }
30823
30980
  const boundary = mappings[boundaryIndex];
30981
+ if (boundary && source.steeredTurnIds.has(boundary.hostTurnId)) {
30982
+ return {
30983
+ ok: false,
30984
+ error: {
30985
+ code: -32080,
30986
+ message: "This Turn took steered input; reopen the Thread before forking from it"
30987
+ }
30988
+ };
30989
+ }
30824
30990
  if (boundaryIndex < 0 || !boundary?.nativeCheckpointRef) {
30825
30991
  return {
30826
30992
  ok: false,
@@ -30877,6 +31043,7 @@ async function executeExternalThreadFork(input) {
30877
31043
  return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
30878
31044
  }
30879
31045
  const session = opened.value;
31046
+ await inheritSourceModel(source, session);
30880
31047
  const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
30881
31048
  try {
30882
31049
  const derivedNativeRef = session.initialState.nativeRef;
@@ -30894,7 +31061,7 @@ async function executeExternalThreadFork(input) {
30894
31061
  source.harnessId,
30895
31062
  provisional.transportModelId
30896
31063
  );
30897
- if (effectiveModel && selection?.model && selection.model.id !== effectiveModel.id) {
31064
+ if (effectiveModel && selection && selection.model?.id !== effectiveModel.id) {
30898
31065
  const transportModelId = encodeExternalTransportSelection(source.harnessId, {
30899
31066
  ...selection,
30900
31067
  model: effectiveModel
@@ -30939,6 +31106,22 @@ async function executeExternalThreadFork(input) {
30939
31106
  };
30940
31107
  }
30941
31108
  }
31109
+ async function inheritSourceModel(source, session) {
31110
+ let persisted;
31111
+ try {
31112
+ persisted = decodeExternalTransportSelection(source.harnessId, source.transportModelId)?.model;
31113
+ } catch {
31114
+ persisted = void 0;
31115
+ }
31116
+ const sourceModel = source.stateObserver.state.effectiveModel ?? source.requestedModel ?? persisted;
31117
+ if (!sourceModel || !session.capabilities.configuration.selectModel || session.initialState.effectiveModel !== void 0) {
31118
+ return;
31119
+ }
31120
+ try {
31121
+ await session.execute({ type: "model.select", model: sourceModel });
31122
+ } catch {
31123
+ }
31124
+ }
30942
31125
  async function inheritSourcePermissionMode(source, session) {
30943
31126
  const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
30944
31127
  if (!sourceModeId) return void 0;
@@ -31560,6 +31743,16 @@ async function executeExternalThreadRollback(input) {
31560
31743
  if (derived.running) {
31561
31744
  return { ok: false, error: { code: -32072, message: "External Thread has an active Turn" } };
31562
31745
  }
31746
+ const undone = derived.record.turnMappings.slice(-rollback.numTurns);
31747
+ if (undone.some((mapping) => derived.steeredTurnIds.has(mapping.hostTurnId))) {
31748
+ return {
31749
+ ok: false,
31750
+ error: {
31751
+ code: -32080,
31752
+ message: "A Turn here took steered input; reopen the Thread before undoing Turns"
31753
+ }
31754
+ };
31755
+ }
31563
31756
  const refreshError = await runtime.refresh(derived);
31564
31757
  if (refreshError) return { ok: false, error: refreshError };
31565
31758
  if (expectedLastTurnId !== void 0 && derived.record.turnMappings.at(-1)?.hostTurnId !== expectedLastTurnId) {
@@ -32359,6 +32552,7 @@ var ExternalThreadRuntime = class {
32359
32552
  #repository;
32360
32553
  #lifecycle = new ExternalThreadLifecycle();
32361
32554
  #hasRunningDescendants;
32555
+ #steeredTurnIds = /* @__PURE__ */ new Map();
32362
32556
  #subagentRunning;
32363
32557
  #threads = /* @__PURE__ */ new Map();
32364
32558
  constructor(input) {
@@ -32372,7 +32566,8 @@ var ExternalThreadRuntime = class {
32372
32566
  this.idleRelease = new ExternalThreadIdleRelease({
32373
32567
  threads: () => this.values(),
32374
32568
  get: (id2) => this.get(id2),
32375
- remove: (id2) => this.remove(id2),
32569
+ // Idle release detaches only the Native Session. Host Thread state survives restoration.
32570
+ remove: (id2) => this.#detach(id2),
32376
32571
  queue: input.idleRelease?.queue ?? new DesktopRequestQueue(),
32377
32572
  canRelease: (thread) => !thread.sessionUnavailable && !this.#lifecycle.busy(thread.id) && (input.idleRelease?.canRelease(thread) ?? false),
32378
32573
  ...input.idleRelease?.onClosed ? { onClosed: input.idleRelease.onClosed } : {},
@@ -32382,14 +32577,21 @@ var ExternalThreadRuntime = class {
32382
32577
  get(threadId2) {
32383
32578
  return this.#threads.get(threadId2);
32384
32579
  }
32580
+ #detach(threadId2) {
32581
+ const thread = this.#threads.get(threadId2);
32582
+ this.#threads.delete(threadId2);
32583
+ if (!thread || thread.steeredTurnIds.size === 0) this.#steeredTurnIds.delete(threadId2);
32584
+ }
32385
32585
  values() {
32386
32586
  return [...this.#threads.values()];
32387
32587
  }
32388
32588
  remove(threadId2) {
32389
32589
  this.#threads.delete(threadId2);
32590
+ this.#steeredTurnIds.delete(threadId2);
32390
32591
  }
32391
32592
  clear() {
32392
32593
  this.#threads.clear();
32594
+ this.#steeredTurnIds.clear();
32393
32595
  }
32394
32596
  drain() {
32395
32597
  return this.#lifecycle.drain();
@@ -32446,6 +32648,11 @@ var ExternalThreadRuntime = class {
32446
32648
  ...effectivePermissionModeId ? { effectivePermissionModeId } : {}
32447
32649
  };
32448
32650
  const running = this.#subagentRunning(input.record.hostThreadId);
32651
+ let steeredTurnIds = this.#steeredTurnIds.get(input.record.hostThreadId);
32652
+ if (!steeredTurnIds) {
32653
+ steeredTurnIds = /* @__PURE__ */ new Set();
32654
+ this.#steeredTurnIds.set(input.record.hostThreadId, steeredTurnIds);
32655
+ }
32449
32656
  const externalThread = {
32450
32657
  id: input.record.hostThreadId,
32451
32658
  cwd: input.record.cwd,
@@ -32470,11 +32677,13 @@ var ExternalThreadRuntime = class {
32470
32677
  usageTurnId: null,
32471
32678
  projectedTurns: /* @__PURE__ */ new Map(),
32472
32679
  responseGates: /* @__PURE__ */ new Map(),
32680
+ pendingSteerProjections: /* @__PURE__ */ new Set(),
32473
32681
  ephemeralTurnIds: /* @__PURE__ */ new Set(),
32474
32682
  persistenceError: null,
32475
32683
  projectedTerminalTurnId: null,
32476
32684
  ignoredInteractionIds: /* @__PURE__ */ new Set(),
32477
- sessionUnavailable: false
32685
+ sessionUnavailable: false,
32686
+ steeredTurnIds
32478
32687
  };
32479
32688
  this.idleRelease.touch(externalThread);
32480
32689
  externalThread.outputTask = this.#consumeOutputs(externalThread);
@@ -32531,13 +32740,13 @@ var ExternalThreadRuntime = class {
32531
32740
  const retire = async () => {
32532
32741
  if (this.#threads.get(parentId) !== parent || this.#threads.get(child.id) !== child) return;
32533
32742
  if (bestEffort) {
32534
- this.#threads.delete(child.id);
32743
+ this.remove(child.id);
32535
32744
  await child.session.close();
32536
32745
  await child.outputTask;
32537
32746
  } else {
32538
32747
  child.sessionUnavailable = true;
32539
32748
  await this.#lifecycle.release(child.id, child.session, child.outputTask);
32540
- if (this.#threads.get(child.id) === child) this.#threads.delete(child.id);
32749
+ if (this.#threads.get(child.id) === child) this.remove(child.id);
32541
32750
  }
32542
32751
  };
32543
32752
  if (bestEffort) await retire().catch(this.#diagnose);
@@ -32910,6 +33119,71 @@ var ExternalThreadRuntime = class {
32910
33119
  };
32911
33120
 
32912
33121
  // packages/host-runtime/src/external-turn-steering.ts
33122
+ import { randomUUID as randomUUID12 } from "node:crypto";
33123
+
33124
+ // packages/host-runtime/src/external-command-routing.ts
33125
+ var ExternalCommandError = class extends Error {
33126
+ constructor(code, message2) {
33127
+ super(message2);
33128
+ this.code = code;
33129
+ }
33130
+ code;
33131
+ };
33132
+ function isExternalCommandCandidate(text) {
33133
+ return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
33134
+ }
33135
+ async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
33136
+ let timeout;
33137
+ try {
33138
+ const result = await Promise.race([
33139
+ commands.list(),
33140
+ new Promise((resolve) => {
33141
+ timeout = setTimeout(() => resolve(null), timeoutMs);
33142
+ })
33143
+ ]);
33144
+ return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
33145
+ } catch {
33146
+ return null;
33147
+ } finally {
33148
+ if (timeout !== void 0) clearTimeout(timeout);
33149
+ }
33150
+ }
33151
+ async function resolveExternalCommand(commands, text, options2 = {}) {
33152
+ const catalog = await commands.list();
33153
+ if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
33154
+ const commandText = text.trim();
33155
+ const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
33156
+ if (commandText === command.invocation) return true;
33157
+ return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
33158
+ });
33159
+ if (!matched) {
33160
+ const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
33161
+ if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
33162
+ return null;
33163
+ }
33164
+ throw new ExternalCommandError(
33165
+ -32078,
33166
+ "External Harness does not expose the requested command"
33167
+ );
33168
+ }
33169
+ const argumentText = commandText.slice(matched.invocation.length).trimStart();
33170
+ return {
33171
+ descriptor: matched,
33172
+ ...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
33173
+ };
33174
+ }
33175
+
33176
+ // packages/host-runtime/src/external-turn-steering.ts
33177
+ function isHarnessCommand(thread, text) {
33178
+ return thread.session.commands !== void 0 && isExternalCommandCandidate(restoreHarnessCommandMentions(text));
33179
+ }
33180
+ function externalSteeringDelivery(thread, text) {
33181
+ if (text !== void 0 && isHarnessCommand(thread, text)) return "newTurn";
33182
+ if (thread.session.readCapabilities) {
33183
+ return thread.session.readCapabilities().then((capabilities) => capabilities.steer === true ? "activeTurn" : "newTurn");
33184
+ }
33185
+ return thread.session.capabilities.steer === true ? "activeTurn" : "newTurn";
33186
+ }
32913
33187
  var ExternalSteerError = class extends Error {
32914
33188
  constructor(code, message2) {
32915
33189
  super(message2);
@@ -32917,6 +33191,11 @@ var ExternalSteerError = class extends Error {
32917
33191
  }
32918
33192
  code;
32919
33193
  };
33194
+ var ExternalSteerNotTakenError = class extends ExternalSteerError {
33195
+ constructor(message2) {
33196
+ super(-32074, message2);
33197
+ }
33198
+ };
32920
33199
  function parseInput(params) {
32921
33200
  if (typeof params.expectedTurnId !== "string" || !params.expectedTurnId.trim()) {
32922
33201
  throw new ExternalSteerError(-32602, "External steering requires expectedTurnId");
@@ -32933,12 +33212,47 @@ function parseInput(params) {
32933
33212
  if (clientUserMessageId != null && (typeof clientUserMessageId !== "string" || !clientUserMessageId.trim())) {
32934
33213
  throw new ExternalSteerError(-32602, "External steering message identity is invalid");
32935
33214
  }
33215
+ const delivery = params[THREAD_STEER_DELIVERY_PARAM];
33216
+ const parsedDelivery = delivery == null ? void 0 : threadSteerDeliverySchema.safeParse(delivery);
33217
+ if (parsedDelivery && !parsedDelivery.success) {
33218
+ throw new ExternalSteerError(-32602, "External steering delivery is invalid");
33219
+ }
32936
33220
  return {
32937
33221
  expectedTurnId: params.expectedTurnId,
32938
33222
  text,
32939
- ...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {}
33223
+ ...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {},
33224
+ ...parsedDelivery ? { delivery: parsedDelivery.data } : {}
32940
33225
  };
32941
33226
  }
33227
+ async function insertNativeSteer(thread, input, host) {
33228
+ const restored = restoreHarnessCommandMentions(input.text);
33229
+ const steered = [{ type: "text", text: rewriteDelegationMentionText(restored) }];
33230
+ const displayed = [{ type: "text", text: restored }];
33231
+ const projectionDone = Promise.withResolvers();
33232
+ thread.pendingSteerProjections.add(projectionDone.promise);
33233
+ try {
33234
+ const result = await thread.session.execute({
33235
+ type: "turn.steer",
33236
+ turnId: input.turnId,
33237
+ input: steered
33238
+ });
33239
+ if (!result.ok) throw new ExternalSteerNotTakenError(result.error.message);
33240
+ thread.steeredTurnIds.add(input.turnId);
33241
+ const item = {
33242
+ type: "userMessage",
33243
+ itemId: hostItemIdSchema.parse(randomUUID12()),
33244
+ input: displayed
33245
+ };
33246
+ try {
33247
+ await host.project(input.turnId, item, input.clientUserMessageId);
33248
+ } catch (error51) {
33249
+ host.diagnose(error51);
33250
+ }
33251
+ } finally {
33252
+ projectionDone.resolve(void 0);
33253
+ thread.pendingSteerProjections.delete(projectionDone.promise);
33254
+ }
33255
+ }
32942
33256
  var ExternalTurnSteering = class {
32943
33257
  constructor(timeoutMs = 2e4) {
32944
33258
  this.timeoutMs = timeoutMs;
@@ -32950,7 +33264,7 @@ var ExternalTurnSteering = class {
32950
33264
  hasPending(threadId2) {
32951
33265
  return threadId2 === void 0 ? this.#pending.size > 0 : this.#pending.has(threadId2);
32952
33266
  }
32953
- run(thread, params, start) {
33267
+ run(thread, params, start, insert) {
32954
33268
  try {
32955
33269
  const input = parseInput(params);
32956
33270
  if (this.#closed)
@@ -32972,7 +33286,7 @@ var ExternalTurnSteering = class {
32972
33286
  if (!thread.running || thread.activeTurnId !== input.expectedTurnId) {
32973
33287
  throw new ExternalSteerError(-32074, "External steering must reference the active Turn");
32974
33288
  }
32975
- const result = this.#replace(thread, input, start);
33289
+ const result = this.#deliver(thread, input, start, insert);
32976
33290
  if (key) {
32977
33291
  const receipt2 = { fingerprint, result, settled: false };
32978
33292
  this.#receipts.set(key, receipt2);
@@ -32995,6 +33309,56 @@ var ExternalTurnSteering = class {
32995
33309
  return Promise.reject(error51);
32996
33310
  }
32997
33311
  }
33312
+ /**
33313
+ * A Renderer that already presented a delivery gets exactly that one. Otherwise native delivery
33314
+ * is tried only when the Session can take the input now, and input the Harness did not take
33315
+ * falls back to stopping and restarting, so no case is worse than the stop-then-start path.
33316
+ */
33317
+ #deliver(thread, input, start, insert) {
33318
+ const delivery = input.delivery === "newTurn" || isHarnessCommand(thread, input.text) ? "newTurn" : input.delivery ?? externalSteeringDelivery(thread);
33319
+ const deliver = (mode) => {
33320
+ if (this.#closed || !thread.running || thread.activeTurnId !== input.expectedTurnId) {
33321
+ throw new ExternalSteerError(-32074, "External steering target is no longer active");
33322
+ }
33323
+ if (this.hasPending(thread.id))
33324
+ throw new ExternalSteerError(-32072, "External Thread is already changing direction");
33325
+ if (mode === "newTurn") return this.#replace(thread, input, start);
33326
+ const native = insert({
33327
+ turnId: thread.activeTurnId,
33328
+ text: input.text,
33329
+ ...input.clientUserMessageId ? { clientUserMessageId: input.clientUserMessageId } : {}
33330
+ }).then((admitted) => ({ ...admitted, delivery: "activeTurn" }));
33331
+ if (input.delivery === "activeTurn") return native;
33332
+ return native.catch(async (error51) => {
33333
+ if (!(error51 instanceof ExternalSteerNotTakenError)) throw error51;
33334
+ if (thread.running || thread.activeTurnId) return deliver("newTurn");
33335
+ const assertActive = () => {
33336
+ if (this.#closed)
33337
+ throw new ExternalSteerError(-32074, "External steering connection is closed");
33338
+ };
33339
+ return { ...await start(input.text, assertActive), delivery: "newTurn" };
33340
+ });
33341
+ };
33342
+ if (typeof delivery === "string") return deliver(delivery);
33343
+ const failure = Promise.withResolvers();
33344
+ let failureReason = null;
33345
+ const pending = {
33346
+ turnId: input.expectedTurnId,
33347
+ resolve: () => void 0,
33348
+ reject(error51) {
33349
+ failureReason ??= error51;
33350
+ failure.reject(error51);
33351
+ }
33352
+ };
33353
+ this.#pending.set(thread.id, pending);
33354
+ return Promise.race([delivery, failure.promise]).then((mode) => {
33355
+ if (failureReason) throw failureReason;
33356
+ if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
33357
+ return deliver(mode);
33358
+ }).finally(() => {
33359
+ if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
33360
+ });
33361
+ }
32998
33362
  terminal(threadId2, turnId, outcome) {
32999
33363
  const pending = this.#pending.get(threadId2);
33000
33364
  if (pending?.turnId === turnId) pending.resolve(outcome);
@@ -33049,7 +33413,9 @@ var ExternalTurnSteering = class {
33049
33413
  thread.session.execute({ type: "turn.cancel", turnId }),
33050
33414
  failure.promise
33051
33415
  ]);
33052
- if (!cancelled.ok) throw new ExternalSteerError(-32074, cancelled.error.message);
33416
+ if (!cancelled.ok && cancelled.error.code !== "invalidState") {
33417
+ throw new ExternalSteerError(-32074, cancelled.error.message);
33418
+ }
33053
33419
  const outcome = await Promise.race([terminal3.promise, failure.promise]);
33054
33420
  clearTimeout(timeout);
33055
33421
  const assertActive = () => {
@@ -33067,7 +33433,7 @@ var ExternalTurnSteering = class {
33067
33433
  if (thread.running || thread.activeTurnId) {
33068
33434
  throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
33069
33435
  }
33070
- return await start(input.text, assertActive);
33436
+ return { ...await start(input.text, assertActive), delivery: "newTurn" };
33071
33437
  } finally {
33072
33438
  clearTimeout(timeout);
33073
33439
  if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
@@ -33075,58 +33441,6 @@ var ExternalTurnSteering = class {
33075
33441
  }
33076
33442
  };
33077
33443
 
33078
- // packages/host-runtime/src/external-command-routing.ts
33079
- var ExternalCommandError = class extends Error {
33080
- constructor(code, message2) {
33081
- super(message2);
33082
- this.code = code;
33083
- }
33084
- code;
33085
- };
33086
- function isExternalCommandCandidate(text) {
33087
- return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
33088
- }
33089
- async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
33090
- let timeout;
33091
- try {
33092
- const result = await Promise.race([
33093
- commands.list(),
33094
- new Promise((resolve) => {
33095
- timeout = setTimeout(() => resolve(null), timeoutMs);
33096
- })
33097
- ]);
33098
- return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
33099
- } catch {
33100
- return null;
33101
- } finally {
33102
- if (timeout !== void 0) clearTimeout(timeout);
33103
- }
33104
- }
33105
- async function resolveExternalCommand(commands, text, options2 = {}) {
33106
- const catalog = await commands.list();
33107
- if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
33108
- const commandText = text.trim();
33109
- const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
33110
- if (commandText === command.invocation) return true;
33111
- return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
33112
- });
33113
- if (!matched) {
33114
- const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
33115
- if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
33116
- return null;
33117
- }
33118
- throw new ExternalCommandError(
33119
- -32078,
33120
- "External Harness does not expose the requested command"
33121
- );
33122
- }
33123
- const argumentText = commandText.slice(matched.invocation.length).trimStart();
33124
- return {
33125
- descriptor: matched,
33126
- ...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
33127
- };
33128
- }
33129
-
33130
33444
  // packages/host-runtime/src/live-command-catalog-cache.ts
33131
33445
  import path23 from "node:path";
33132
33446
  var MAX_ENTRIES = 64;
@@ -33158,7 +33472,7 @@ function sameWorkspace(left, right) {
33158
33472
  }
33159
33473
 
33160
33474
  // packages/host-runtime/src/harness-delegation-coordinator.ts
33161
- import { createHash as createHash8, randomUUID as randomUUID11 } from "node:crypto";
33475
+ import { createHash as createHash8, randomUUID as randomUUID13 } from "node:crypto";
33162
33476
  import path24 from "node:path";
33163
33477
 
33164
33478
  // packages/host-runtime/src/delegation-snapshot.ts
@@ -33304,6 +33618,15 @@ function projectDelegationThreadSnapshot(input) {
33304
33618
  // packages/host-runtime/src/harness-delegation-coordinator.ts
33305
33619
  var IMPLICIT_DEDUPLICATION_MS = 3e4;
33306
33620
  var NATIVE_REF_TIMEOUT_MS = 1e4;
33621
+ function truncateTitle(value2, length) {
33622
+ return value2.slice(0, length).replace(/[\uD800-\uDBFF]$/u, "");
33623
+ }
33624
+ function delegationTitle(parentTitle, input) {
33625
+ const taskName = (input.taskName ?? input.task.trim().split(/\r?\n/u)[0] ?? input.task).replace(/\s+/gu, " ").trim();
33626
+ const subtask = truncateTitle(taskName, 120);
33627
+ const parent = (parentTitle?.trim() || "Untitled Thread").replace(/\s+/gu, " ");
33628
+ return `${subtask} · ${truncateTitle(parent, 200 - subtask.length - 3)}`;
33629
+ }
33307
33630
  function delay3(milliseconds) {
33308
33631
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
33309
33632
  }
@@ -33330,6 +33653,12 @@ function statusFromThread(thread, busy) {
33330
33653
  function validateStart(input) {
33331
33654
  if (typeof input.task !== "string" || !input.task.trim())
33332
33655
  throw new DelegationControlError("INVALID_ARGUMENT", "Task must not be empty");
33656
+ if (input.taskName !== void 0 && (typeof input.taskName !== "string" || !input.taskName.trim() || input.taskName.length > 120)) {
33657
+ throw new DelegationControlError(
33658
+ "INVALID_ARGUMENT",
33659
+ "Task name must contain 1 to 120 characters"
33660
+ );
33661
+ }
33333
33662
  if (input.cwd !== void 0 && (typeof input.cwd !== "string" || !input.cwd.trim()))
33334
33663
  throw new DelegationControlError("INVALID_ARGUMENT", "cwd must not be empty");
33335
33664
  if (input.requestId !== void 0 && (typeof input.requestId !== "string" || !input.requestId.trim())) {
@@ -33350,7 +33679,7 @@ var HarnessDelegationCoordinator = class {
33350
33679
  #cancelOfficial;
33351
33680
  #startOfficial;
33352
33681
  #listOfficial;
33353
- #officialThreadCwd;
33682
+ #officialThreadMetadata;
33354
33683
  #activeOfficialParents;
33355
33684
  #externalThreadBusy;
33356
33685
  constructor(input) {
@@ -33367,7 +33696,7 @@ var HarnessDelegationCoordinator = class {
33367
33696
  this.#cancelOfficial = input.cancelOfficial;
33368
33697
  this.#startOfficial = input.startOfficial;
33369
33698
  this.#listOfficial = input.listOfficial;
33370
- this.#officialThreadCwd = input.officialThreadCwd;
33699
+ this.#officialThreadMetadata = input.officialThreadMetadata;
33371
33700
  this.#activeOfficialParents = input.activeOfficialParents;
33372
33701
  this.#externalThreadBusy = input.externalThreadBusy;
33373
33702
  }
@@ -33397,8 +33726,14 @@ var HarnessDelegationCoordinator = class {
33397
33726
  const parentThreadId = await this.#resolveParent(input.parentThreadId);
33398
33727
  const parent = await this.#parentMetadata(parentThreadId);
33399
33728
  const selectedCwd = input.cwd ?? parent.cwd ?? process.cwd();
33729
+ const title = delegationTitle(parent.title, input);
33400
33730
  if (input.harnessId === "codex") {
33401
- const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
33731
+ const result = await this.#startOfficial({
33732
+ ...input,
33733
+ parentThreadId,
33734
+ cwd: selectedCwd,
33735
+ title
33736
+ });
33402
33737
  return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
33403
33738
  }
33404
33739
  const startInput = { ...input, parentThreadId, cwd: path24.resolve(selectedCwd) };
@@ -33441,17 +33776,17 @@ var HarnessDelegationCoordinator = class {
33441
33776
  });
33442
33777
  this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
33443
33778
  }
33444
- const delegationId = hostThreadIdSchema.parse(randomUUID11());
33445
- const childThreadId = hostThreadIdSchema.parse(randomUUID11());
33446
- const turnId = hostTurnIdSchema.parse(randomUUID11());
33447
- const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID11();
33779
+ const delegationId = hostThreadIdSchema.parse(randomUUID13());
33780
+ const childThreadId = hostThreadIdSchema.parse(randomUUID13());
33781
+ const turnId = hostTurnIdSchema.parse(randomUUID13());
33782
+ const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID13();
33448
33783
  let record4 = await this.#repository.createProvisional(
33449
33784
  createExternalThreadRecordInput({
33450
33785
  hostThreadId: childThreadId,
33451
33786
  createRequestId,
33452
33787
  harnessId: harnessIdSchema.parse(targetHarnessId),
33453
33788
  cwd: startInput.cwd,
33454
- title: input.task.trim().slice(0, 120),
33789
+ title,
33455
33790
  transportModelId: input.model || input.thinkingOptionId ? encodeExternalTransportSelection(targetHarnessId, {
33456
33791
  ...input.model ? { model: input.model } : {},
33457
33792
  ...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
@@ -33598,7 +33933,7 @@ var HarnessDelegationCoordinator = class {
33598
33933
  if (this.#externalThreadBusy(thread) || thread.activeTurnId) {
33599
33934
  throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
33600
33935
  }
33601
- const turnId = hostTurnIdSchema.parse(randomUUID11());
33936
+ const turnId = hostTurnIdSchema.parse(randomUUID13());
33602
33937
  try {
33603
33938
  await this.#startExternalTurn(thread, input.message, turnId);
33604
33939
  } catch (error51) {
@@ -33812,9 +34147,14 @@ var HarnessDelegationCoordinator = class {
33812
34147
  }
33813
34148
  async #parentMetadata(parentThreadId) {
33814
34149
  const record4 = await this.#repository.find(parentThreadId);
33815
- if (record4) return { harnessId: record4.harnessId, cwd: record4.cwd };
33816
- const cwd = await this.#officialThreadCwd(parentThreadId).catch(() => void 0);
33817
- return { harnessId: "codex", ...cwd ? { cwd } : {} };
34150
+ if (record4)
34151
+ return {
34152
+ harnessId: record4.harnessId,
34153
+ cwd: record4.cwd,
34154
+ title: record4.title
34155
+ };
34156
+ const metadata = await this.#officialThreadMetadata(parentThreadId).catch(() => ({}));
34157
+ return { harnessId: "codex", ...metadata };
33818
34158
  }
33819
34159
  async #existingResult(delegation) {
33820
34160
  const record4 = await this.#repository.find(delegation.childHostThreadId);
@@ -36243,10 +36583,10 @@ var SingleNativeCodexAccount = class {
36243
36583
  };
36244
36584
 
36245
36585
  // packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
36246
- import { randomUUID as randomUUID13 } from "node:crypto";
36586
+ import { randomUUID as randomUUID15 } from "node:crypto";
36247
36587
 
36248
36588
  // packages/host-runtime/src/official-request-broker.ts
36249
- import { randomUUID as randomUUID12 } from "node:crypto";
36589
+ import { randomUUID as randomUUID14 } from "node:crypto";
36250
36590
  var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
36251
36591
  var MAX_RETIRED_IDS = 1024;
36252
36592
  function isRecord15(value2) {
@@ -36262,7 +36602,7 @@ var OfficialRequestBroker = class {
36262
36602
  constructor(input) {
36263
36603
  this.#send = input.send;
36264
36604
  this.#timeoutMs = input.timeoutMs ?? 3e4;
36265
- this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID12()}`);
36605
+ this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID14()}`);
36266
36606
  }
36267
36607
  get pendingCount() {
36268
36608
  return this.#pending.size;
@@ -36616,7 +36956,7 @@ var OfficialRuntimeOwner = class {
36616
36956
  }
36617
36957
  #attach(role, output, onBackendStopped) {
36618
36958
  const client = {
36619
- id: randomUUID13(),
36959
+ id: randomUUID15(),
36620
36960
  role,
36621
36961
  output,
36622
36962
  ...onBackendStopped ? { onBackendStopped } : {},
@@ -36774,7 +37114,7 @@ var OfficialRuntimeOwner = class {
36774
37114
  if (!object4(value2)) return client.output(event);
36775
37115
  if (typeof value2.id === "string" || typeof value2.id === "number") {
36776
37116
  if (typeof value2.method === "string") {
36777
- const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID13()}`;
37117
+ const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID15()}`;
36778
37118
  client.serverRequests.set(id2, value2.id);
36779
37119
  const projected = { ...value2, id: id2 };
36780
37120
  return client.output({
@@ -36950,16 +37290,16 @@ var OfficialRuntimeScope = class {
36950
37290
  #scheduleRecovery() {
36951
37291
  if (!this.#recovery || this.#closed || this.#recoveryTimer || this.#starting) return;
36952
37292
  const { delaysMs } = this.#recovery;
36953
- const delay6 = delaysMs[Math.min(this.#recoveryAttempt, delaysMs.length - 1)] ?? 0;
37293
+ const delay7 = delaysMs[Math.min(this.#recoveryAttempt, delaysMs.length - 1)] ?? 0;
36954
37294
  this.#recoveryAttempt++;
36955
37295
  this.#diagnosticOutput.write(
36956
- `codexhost: official Codex is unavailable; restarting in ${String(delay6)}ms
37296
+ `codexhost: official Codex is unavailable; restarting in ${String(delay7)}ms
36957
37297
  `
36958
37298
  );
36959
37299
  const timer = setTimeout(() => {
36960
37300
  this.#recoveryTimer = void 0;
36961
37301
  this.start().catch(() => void 0);
36962
- }, delay6);
37302
+ }, delay7);
36963
37303
  timer.unref();
36964
37304
  this.#recoveryTimer = timer;
36965
37305
  }
@@ -38054,6 +38394,7 @@ var AppServerHost = class {
38054
38394
  #plugins;
38055
38395
  #launchSettings;
38056
38396
  #accountInspections = new HarnessAccountInspectionCache();
38397
+ #installationTasks = new HarnessInstallationTasks();
38057
38398
  #externalRuntime;
38058
38399
  #executionHosts = /* @__PURE__ */ new WeakMap();
38059
38400
  #externalPrewarms = new ExternalThreadPrewarms();
@@ -38084,7 +38425,7 @@ var AppServerHost = class {
38084
38425
  #sectionMoves = Promise.resolve();
38085
38426
  #writer;
38086
38427
  /** Console requests share Desktop handling; their replies return to the console. */
38087
- #consoleRequestPrefix = `codexhost-console:${randomUUID14()}:`;
38428
+ #consoleRequestPrefix = `codexhost-console:${randomUUID16()}:`;
38088
38429
  #consoleReplies = /* @__PURE__ */ new Map();
38089
38430
  #nextConsoleRequest = 0;
38090
38431
  #subagentThreadStatuses = /* @__PURE__ */ new Map();
@@ -38222,7 +38563,7 @@ var AppServerHost = class {
38222
38563
  cancelOfficial: (input) => this.#cancelOfficialDelegationThread(input),
38223
38564
  startOfficial: (input) => this.#startOfficialDelegation(input),
38224
38565
  listOfficial: (input) => this.#listDelegationThreads(input),
38225
- officialThreadCwd: (threadId2) => this.#readOfficialThreadCwd(threadId2),
38566
+ officialThreadMetadata: (threadId2) => this.#readOfficialThreadMetadata(threadId2),
38226
38567
  activeOfficialParents: () => [...this.#activeOfficialTurns.keys()],
38227
38568
  externalThreadBusy: (thread) => this.#externalThreadBusy(thread)
38228
38569
  });
@@ -38868,11 +39209,11 @@ var AppServerHost = class {
38868
39209
  this.#dispatchDesktopReply(request, () => this.#inspectHarness(request));
38869
39210
  return;
38870
39211
  }
38871
- if (request.method === HARNESS_INSTALLATION_METHOD) {
39212
+ if (request.method === HARNESS_INSTALLATION_METHOD || request.method === HARNESS_INSTALLATION_START_METHOD || request.method === HARNESS_INSTALLATION_STATUS_METHOD) {
38872
39213
  this.#dispatchDesktopReply(request, async () => {
38873
- await this.#waitForPlugins();
38874
39214
  try {
38875
- const result = await handleHarnessInstallation(request.params, this.#externalAdapters);
39215
+ if (request.method !== HARNESS_INSTALLATION_STATUS_METHOD) await this.#waitForPlugins();
39216
+ const result = request.method === HARNESS_INSTALLATION_START_METHOD ? this.#installationTasks.start(request.params, this.#externalAdapters) : request.method === HARNESS_INSTALLATION_STATUS_METHOD ? this.#installationTasks.status(request.params) : await handleHarnessInstallation(request.params, this.#externalAdapters);
38876
39217
  await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
38877
39218
  } catch (error51) {
38878
39219
  await this.#writer.json(
@@ -38957,6 +39298,10 @@ var AppServerHost = class {
38957
39298
  await this.#listThreadOwnership(request);
38958
39299
  return;
38959
39300
  }
39301
+ if (request.method === "codexhost/thread/steering/inspect") {
39302
+ await this.#inspectThreadSteering(request);
39303
+ return;
39304
+ }
38960
39305
  if (request.method === "codexhost/thread/model/select") {
38961
39306
  await this.#selectThreadModel(request);
38962
39307
  return;
@@ -39534,12 +39879,17 @@ var AppServerHost = class {
39534
39879
  ]);
39535
39880
  return thread !== null || childDelegation !== null || delegation !== null;
39536
39881
  }
39537
- async #readOfficialThreadCwd(threadId2) {
39538
- const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
39539
- if (isRecord18(response.error)) return void 0;
39882
+ async #readOfficialThreadMetadata(threadId2) {
39883
+ const response = await this.#requestOfficial("thread/read", { threadId: threadId2, includeTurns: false });
39884
+ if (isRecord18(response.error)) return {};
39540
39885
  const result = isRecord18(response.result) ? response.result : null;
39541
39886
  const thread = result && isRecord18(result.thread) ? result.thread : null;
39542
- return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
39887
+ if (!thread) return {};
39888
+ const title = typeof thread.name === "string" && thread.name.trim() ? thread.name : thread.preview;
39889
+ return {
39890
+ ...typeof thread.cwd === "string" && thread.cwd.trim() ? { cwd: thread.cwd } : {},
39891
+ ...typeof title === "string" && title.trim() ? { title } : {}
39892
+ };
39543
39893
  }
39544
39894
  async #inspectOfficialDelegationTarget(input) {
39545
39895
  const response = await this.#requestOfficial("model/list", {});
@@ -39692,6 +40042,9 @@ var AppServerHost = class {
39692
40042
  this.#pendingOfficialDelegationThreads.add(threadId2);
39693
40043
  let turnId;
39694
40044
  try {
40045
+ await this.#requestOfficial("thread/name/set", { threadId: threadId2, name: input.title }).catch(
40046
+ () => void 0
40047
+ );
39695
40048
  const turn = await this.#requestOfficial("turn/start", {
39696
40049
  threadId: threadId2,
39697
40050
  input: [{ type: "text", text: input.task }],
@@ -39710,7 +40063,7 @@ var AppServerHost = class {
39710
40063
  throw error51;
39711
40064
  }
39712
40065
  this.#activeOfficialTurns.set(threadId2, turnId);
39713
- const delegationId = hostThreadIdSchema.parse(randomUUID14());
40066
+ const delegationId = hostThreadIdSchema.parse(randomUUID16());
39714
40067
  try {
39715
40068
  const source = await this.#repository.find(input.parentThreadId);
39716
40069
  const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
@@ -39898,7 +40251,7 @@ var AppServerHost = class {
39898
40251
  async #listDelegationThreads(input) {
39899
40252
  const [sortKey, sortDirection2] = input.sort.split("-");
39900
40253
  const request = {
39901
- id: `codexhost:delegation-list:${randomUUID14()}`,
40254
+ id: `codexhost:delegation-list:${randomUUID16()}`,
39902
40255
  method: "thread/list",
39903
40256
  params: {
39904
40257
  cwd: input.cwd ? [input.cwd] : null,
@@ -40247,7 +40600,8 @@ var AppServerHost = class {
40247
40600
  try {
40248
40601
  inspection = await adapter.inspect({
40249
40602
  ...params.data.cwd ? { cwd: params.data.cwd } : {},
40250
- ...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {}
40603
+ ...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {},
40604
+ ...params.data.purpose ? { purpose: params.data.purpose } : {}
40251
40605
  });
40252
40606
  } catch (error51) {
40253
40607
  await this.#writer.json(
@@ -40440,6 +40794,28 @@ var AppServerHost = class {
40440
40794
  );
40441
40795
  }
40442
40796
  }
40797
+ /** Read the same delivery decision that Desktop `turn/steer` will follow. */
40798
+ async #inspectThreadSteering(request) {
40799
+ const params = threadSteeringInspectParamsSchema.safeParse(request.params);
40800
+ if (!params.success) {
40801
+ await this.#writer.json(rpcError(request, -32602, "Invalid Thread steering params"));
40802
+ return;
40803
+ }
40804
+ let delivery;
40805
+ try {
40806
+ const location = await this.#locateExternalThread(params.data.threadId);
40807
+ if (await this.#writeResolutionError(request, location)) return;
40808
+ const thread = location.kind === "external" ? this.#externalRuntime.get(params.data.threadId) : void 0;
40809
+ delivery = location.kind !== "external" ? "official" : thread ? await externalSteeringDelivery(thread, params.data.text) : "newTurn";
40810
+ } catch {
40811
+ await this.#writer.json(
40812
+ rpcError(request, -32081, "Thread steering metadata could not be read")
40813
+ );
40814
+ return;
40815
+ }
40816
+ const result = threadSteeringInspectResultSchema.parse({ delivery });
40817
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
40818
+ }
40443
40819
  async #inspectThreadCommands(request) {
40444
40820
  const params = threadCommandsInspectParamsSchema.safeParse(request.params);
40445
40821
  if (!params.success) {
@@ -40603,7 +40979,7 @@ var AppServerHost = class {
40603
40979
  if (thread.running || thread.activeTurnId) {
40604
40980
  throw new ExternalCommandError(-32072, "External Thread already has an active operation");
40605
40981
  }
40606
- const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID14());
40982
+ const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID16());
40607
40983
  const projection = {
40608
40984
  projector: new CodexTurnProjector({
40609
40985
  threadId: thread.id,
@@ -40691,6 +41067,26 @@ var AppServerHost = class {
40691
41067
  if (!projected.effectiveModel) {
40692
41068
  throw new Error("Harness Session did not report an effective Model");
40693
41069
  }
41070
+ const transportModelId = encodeExternalTransportSelection(thread.harnessId, {
41071
+ ...decodeExternalTransportSelection(thread.harnessId, thread.transportModelId) ?? {},
41072
+ model: projected.effectiveModel
41073
+ });
41074
+ thread.transportModelId = transportModelId;
41075
+ thread.requestedModel = projected.effectiveModel;
41076
+ try {
41077
+ thread.record = await this.#repository.setTransportModelId(
41078
+ thread.record.hostThreadId,
41079
+ transportModelId
41080
+ );
41081
+ } catch (error51) {
41082
+ this.#diagnose(error51);
41083
+ }
41084
+ thread.thread = externalThreadValue({
41085
+ record: { ...thread.record, transportModelId },
41086
+ turns: thread.turns,
41087
+ sessionId: thread.sessionId,
41088
+ running: thread.running
41089
+ });
40694
41090
  await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(projected) }));
40695
41091
  } catch (error51) {
40696
41092
  await this.#writer.json(
@@ -41020,9 +41416,20 @@ var AppServerHost = class {
41020
41416
  await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
41021
41417
  return true;
41022
41418
  }
41419
+ /** Refresh history before Desktop acts on native Turn boundaries. */
41023
41420
  #refreshExternalThread(thread) {
41024
41421
  return this.#externalRuntime.refresh(thread);
41025
41422
  }
41423
+ #markExternalHistoryRead(thread, turns) {
41424
+ if (!thread.historyHydrated) return;
41425
+ for (const turnId of thread.steeredTurnIds) {
41426
+ if (turnId !== thread.activeTurnId && turns.some(
41427
+ (turn) => turn.id === turnId && (turn.status === "completed" || turn.status === "failed" || turn.status === "interrupted")
41428
+ )) {
41429
+ thread.steeredTurnIds.delete(turnId);
41430
+ }
41431
+ }
41432
+ }
41026
41433
  #persistTerminalIdentity(thread, event) {
41027
41434
  return this.#externalRuntime.persistTerminalIdentity(thread, event);
41028
41435
  }
@@ -41224,17 +41631,19 @@ var AppServerHost = class {
41224
41631
  return;
41225
41632
  }
41226
41633
  }
41634
+ const readTurns = includeTurns ? [...this.#externalHistoryTurns(thread)] : [];
41227
41635
  await this.#writer.json(
41228
41636
  rpcEnvelope(request, {
41229
41637
  result: {
41230
41638
  thread: {
41231
41639
  ...thread.thread,
41232
41640
  ...await this.#externalSectionFields(thread.record.hostThreadId),
41233
- turns: includeTurns ? this.#externalHistoryTurns(thread) : []
41641
+ turns: readTurns
41234
41642
  }
41235
41643
  }
41236
41644
  })
41237
41645
  );
41646
+ if (includeTurns) this.#markExternalHistoryRead(thread, readTurns);
41238
41647
  await this.#replayExternalUsage(thread);
41239
41648
  }
41240
41649
  async #listExternalHistory(request, thread, params, historyFresh) {
@@ -41251,6 +41660,9 @@ var AppServerHost = class {
41251
41660
  const turns = this.#externalHistoryTurns(thread);
41252
41661
  const result = request.method === "thread/turns/list" ? listExternalTurns(turns, params) : listExternalItems(turns, params);
41253
41662
  await this.#writer.json(rpcEnvelope(request, { result }));
41663
+ if (request.method === "thread/turns/list") {
41664
+ this.#markExternalHistoryRead(thread, result.data);
41665
+ }
41254
41666
  } catch (error51) {
41255
41667
  await this.#writer.json(
41256
41668
  rpcError(
@@ -41269,7 +41681,7 @@ var AppServerHost = class {
41269
41681
  return;
41270
41682
  }
41271
41683
  }
41272
- const turns = this.#externalHistoryTurns(thread);
41684
+ const turns = [...this.#externalHistoryTurns(thread)];
41273
41685
  const responseThread = {
41274
41686
  ...await this.#withExternalSection(thread.thread),
41275
41687
  turns: params.excludeTurns === true ? [] : turns
@@ -41301,6 +41713,8 @@ var AppServerHost = class {
41301
41713
  }
41302
41714
  })
41303
41715
  );
41716
+ if (params.excludeTurns !== true) this.#markExternalHistoryRead(thread, turns);
41717
+ else if (initialTurnsPage) this.#markExternalHistoryRead(thread, initialTurnsPage.data);
41304
41718
  } catch (error51) {
41305
41719
  await this.#writer.json(
41306
41720
  rpcError(
@@ -41443,10 +41857,15 @@ var AppServerHost = class {
41443
41857
  assertActive,
41444
41858
  typeof requestObject(request).clientUserMessageId === "string" ? requestObject(request).clientUserMessageId : void 0,
41445
41859
  requestObject(request)[THREAD_REFERENCE_SOURCE_HOST_PARAM]
41446
- )
41860
+ ),
41861
+ (input) => this.#insertExternalInput(thread, input)
41447
41862
  );
41448
41863
  try {
41449
- await this.#writer.json(rpcEnvelope(request, { result: { turnId: started.turnId } }));
41864
+ await this.#writer.json(
41865
+ rpcEnvelope(request, {
41866
+ result: { turnId: started.turnId, delivery: started.delivery }
41867
+ })
41868
+ );
41450
41869
  } finally {
41451
41870
  started.gate.resolve();
41452
41871
  }
@@ -41462,6 +41881,34 @@ var AppServerHost = class {
41462
41881
  this.#signalActiveWorkChanged();
41463
41882
  }
41464
41883
  }
41884
+ /** Native same-Turn input; `insertNativeSteer` owns the delivery and its fallback signal. */
41885
+ async #insertExternalInput(thread, input) {
41886
+ await insertNativeSteer(thread, input, {
41887
+ project: async (turnId, item, clientUserMessageId) => {
41888
+ const projection = this.#projectedTurn(thread, turnId);
41889
+ if (clientUserMessageId) {
41890
+ projection.projector.bindUserMessageClientId(item.itemId, clientUserMessageId);
41891
+ }
41892
+ await this.#projectHarnessOutput(thread, {
41893
+ kind: "event",
41894
+ event: { type: "item.started", turnId, item }
41895
+ });
41896
+ await this.#projectHarnessOutput(thread, {
41897
+ kind: "event",
41898
+ event: {
41899
+ type: "item.completed",
41900
+ turnId,
41901
+ snapshot: { item, outcome: { status: "succeeded" } }
41902
+ }
41903
+ });
41904
+ },
41905
+ diagnose: (error51) => this.#diagnose(error51)
41906
+ });
41907
+ return {
41908
+ turnId: input.turnId,
41909
+ gate: { promise: Promise.resolve(), resolve: () => void 0 }
41910
+ };
41911
+ }
41465
41912
  /** Keep command restoration and dispatch identical for start and steer submissions. */
41466
41913
  async #beginExternalInputTurn(thread, inputText, assertActive, clientUserMessageId, sourceHostId) {
41467
41914
  const text = restoreHarnessCommandMentions(inputText);
@@ -41519,7 +41966,7 @@ var AppServerHost = class {
41519
41966
  if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
41520
41967
  throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
41521
41968
  }
41522
- const turnId = hostTurnIdSchema.parse(randomUUID14());
41969
+ const turnId = hostTurnIdSchema.parse(randomUUID16());
41523
41970
  const startedAtMs = Date.now();
41524
41971
  const projection = {
41525
41972
  projector: new CodexTurnProjector({
@@ -41814,6 +42261,9 @@ var AppServerHost = class {
41814
42261
  }
41815
42262
  return;
41816
42263
  }
42264
+ if (event.type === "turn.completed" && thread.pendingSteerProjections.size > 0) {
42265
+ await Promise.allSettled([...thread.pendingSteerProjections]);
42266
+ }
41817
42267
  const projection = this.#projectedTurn(thread, event.turnId);
41818
42268
  await this.#waitForTurnResponse(thread, event.turnId);
41819
42269
  if (event.type === "interaction.closed" && thread.ignoredInteractionIds.delete(event.interactionId)) {
@@ -41863,6 +42313,7 @@ var AppServerHost = class {
41863
42313
  thread.activeTurnId = null;
41864
42314
  if (!projection.projector.hasOpenDetachedItems) thread.projectedTurns.delete(event.turnId);
41865
42315
  thread.responseGates.delete(event.turnId);
42316
+ thread.pendingSteerProjections.clear();
41866
42317
  this.#signalActiveWorkChanged();
41867
42318
  const delegation = await this.#repository.getDelegationByChild(thread.record.hostThreadId);
41868
42319
  if (delegation) {
@@ -42153,7 +42604,7 @@ var AppServerHost = class {
42153
42604
  try {
42154
42605
  result = projection.projector.projectQuestion(
42155
42606
  interaction,
42156
- hostItemIdSchema.parse(randomUUID14())
42607
+ hostItemIdSchema.parse(randomUUID16())
42157
42608
  );
42158
42609
  } catch (error51) {
42159
42610
  this.#diagnose(error51);
@@ -42392,7 +42843,7 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
42392
42843
  var wrapper_default = import_websocket.default;
42393
42844
 
42394
42845
  // packages/host-runtime/src/remote-socket-lock.ts
42395
- import { randomUUID as randomUUID15 } from "node:crypto";
42846
+ import { randomUUID as randomUUID17 } from "node:crypto";
42396
42847
  import { chmod as chmod3, lstat as lstat5, mkdir as mkdir12, open as open9, readFile as readFile16, readdir as readdir5, rename as rename11, rm as rm11 } from "node:fs/promises";
42397
42848
  import { uptime } from "node:os";
42398
42849
  import path26 from "node:path";
@@ -42518,7 +42969,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
42518
42969
  await chmod3(lockDirectory, 448);
42519
42970
  }
42520
42971
  async function writeLockRecordAtomic(lockDirectory, entryPath, record4) {
42521
- const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${randomUUID15()}`);
42972
+ const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${randomUUID17()}`);
42522
42973
  const handle = await open9(temporary, "wx", 384);
42523
42974
  try {
42524
42975
  await handle.writeFile(`${JSON.stringify(record4)}
@@ -42593,7 +43044,7 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
42593
43044
  const legacyPath = `${socketPath}.initializing`;
42594
43045
  const lockDirectory = `${socketPath}.initializers`;
42595
43046
  await preparePrivateLockDirectory(lockDirectory);
42596
- const ownerToken = randomUUID15();
43047
+ const ownerToken = randomUUID17();
42597
43048
  const entryPath = path26.join(lockDirectory, lockEntryName(ownerToken));
42598
43049
  const baseRecord = {
42599
43050
  version: 2,
@@ -43104,12 +43555,12 @@ function createRemoteAppServerWebSocketListener(input) {
43104
43555
 
43105
43556
  // packages/host-runtime/src/remote-official-app-server.ts
43106
43557
  import { spawn as spawn5 } from "node:child_process";
43107
- import { randomUUID as randomUUID16 } from "node:crypto";
43558
+ import { randomUUID as randomUUID18 } from "node:crypto";
43108
43559
  import { lstat as lstat7, rm as rm13, stat as stat7 } from "node:fs/promises";
43109
43560
  import path28 from "node:path";
43110
43561
  var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
43111
43562
  var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
43112
- function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID16()) {
43563
+ function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID18()) {
43113
43564
  if (!path28.posix.isAbsolute(desktopControlSocketPath)) {
43114
43565
  throw new Error("Desktop control socket path must be absolute");
43115
43566
  }
@@ -44328,11 +44779,11 @@ async function readRemoteDelegationThread(environment, input) {
44328
44779
  }
44329
44780
 
44330
44781
  // packages/host-runtime/src/shared-thread-owner.ts
44331
- import { randomUUID as randomUUID18 } from "node:crypto";
44782
+ import { randomUUID as randomUUID20 } from "node:crypto";
44332
44783
  import { PassThrough as PassThrough3 } from "node:stream";
44333
44784
 
44334
44785
  // packages/host-runtime/src/shared-thread-peer.ts
44335
- import { randomUUID as randomUUID17 } from "node:crypto";
44786
+ import { randomUUID as randomUUID19 } from "node:crypto";
44336
44787
  function object5(value2) {
44337
44788
  return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
44338
44789
  }
@@ -44346,7 +44797,7 @@ var StreamThreadPeer = class {
44346
44797
  input;
44347
44798
  output;
44348
44799
  stop;
44349
- #prefix = `shared:${randomUUID17()}:`;
44800
+ #prefix = `shared:${randomUUID19()}:`;
44350
44801
  #pending = /* @__PURE__ */ new Map();
44351
44802
  #listeners = /* @__PURE__ */ new Set();
44352
44803
  #ended = Promise.withResolvers();
@@ -44424,7 +44875,7 @@ var SharedThreadOwner = class {
44424
44875
  input = new PassThrough3();
44425
44876
  output = new PassThrough3();
44426
44877
  #peer = new StreamThreadPeer(this.output, this.input, () => this.input.end());
44427
- #prefix = `shared-interaction:${randomUUID18()}:`;
44878
+ #prefix = `shared-interaction:${randomUUID20()}:`;
44428
44879
  #interactions = /* @__PURE__ */ new Map();
44429
44880
  #listeners = /* @__PURE__ */ new Set();
44430
44881
  #receipts = /* @__PURE__ */ new Map();
@@ -44734,7 +45185,7 @@ var SharedThreadBridge = class {
44734
45185
  };
44735
45186
 
44736
45187
  // packages/host-runtime/src/remote-control-app-server.ts
44737
- import { randomUUID as randomUUID19 } from "node:crypto";
45188
+ import { randomUUID as randomUUID21 } from "node:crypto";
44738
45189
  import { mkdir as mkdir15, open as open10, rename as rename12, rm as rm14 } from "node:fs/promises";
44739
45190
  import path33 from "node:path";
44740
45191
  var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
@@ -44755,7 +45206,7 @@ function nodeCompatibleWindowsPath(value2) {
44755
45206
  if (value2.startsWith("\\\\?\\")) return value2.slice(4);
44756
45207
  return value2;
44757
45208
  }
44758
- function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID19()) {
45209
+ function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID21()) {
44759
45210
  const safeInstance = instanceId.replaceAll(/[^a-zA-Z0-9-]/gu, "");
44760
45211
  if (!safeInstance) throw new Error("Remote Control bridge instance ID is invalid");
44761
45212
  return `\\\\.\\pipe\\codexhost-remote-control-${processId}-${safeInstance}`;
@@ -44770,7 +45221,7 @@ async function publishRemoteControlAppServerDescriptor(plan) {
44770
45221
  await mkdir15(directory, { recursive: true, mode: 448 });
44771
45222
  const temporaryPath = path33.join(
44772
45223
  directory,
44773
- `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID19()}.tmp`
45224
+ `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID21()}.tmp`
44774
45225
  );
44775
45226
  const handle = await open10(temporaryPath, "wx", 384);
44776
45227
  try {
@@ -45292,12 +45743,19 @@ function createHostUpdateCoordinator(options2) {
45292
45743
  }
45293
45744
 
45294
45745
  // packages/host-runtime/src/usage-statistics.ts
45295
- import { randomUUID as randomUUID20 } from "node:crypto";
45746
+ import { randomUUID as randomUUID22 } from "node:crypto";
45296
45747
  import { mkdir as mkdir17, readFile as readFile17, readdir as readdir6, rename as rename14, rm as rm16, writeFile as writeFile10 } from "node:fs/promises";
45297
45748
  import path36 from "node:path";
45298
45749
  import { setImmediate as yieldToEventLoop } from "node:timers/promises";
45299
45750
 
45300
45751
  // packages/harness-adapter/dist/usage-statistics.js
45752
+ var HarnessUsageSourceChangedError = class extends Error {
45753
+ code = "HARNESS_USAGE_SOURCE_CHANGED";
45754
+ /** Plugins may bundle their own copy of this contract, so instanceof is insufficient. */
45755
+ static is(error51) {
45756
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "HARNESS_USAGE_SOURCE_CHANGED";
45757
+ }
45758
+ };
45301
45759
  var MAX_SESSION_ID_LENGTH = 512;
45302
45760
  var MAX_CWD_LENGTH = 4096;
45303
45761
  var MAX_SESSION_TITLE_LENGTH = 200;
@@ -45309,10 +45767,13 @@ function usageSessionTitle(value2) {
45309
45767
  return void 0;
45310
45768
  if (normalized.length <= MAX_SESSION_TITLE_LENGTH)
45311
45769
  return normalized;
45312
- const characters = [...normalized];
45313
- if (characters.length <= MAX_SESSION_TITLE_LENGTH)
45314
- return normalized;
45315
- return `${characters.slice(0, MAX_SESSION_TITLE_LENGTH - 1).join("").trimEnd()}…`;
45770
+ let title = "";
45771
+ for (const character of normalized) {
45772
+ if (title.length + character.length >= MAX_SESSION_TITLE_LENGTH)
45773
+ break;
45774
+ title += character;
45775
+ }
45776
+ return `${title.trimEnd()}…`;
45316
45777
  }
45317
45778
  function sessionIdOk(value2) {
45318
45779
  return typeof value2 === "string" && value2.length > 0 && value2.length <= MAX_SESSION_ID_LENGTH;
@@ -45397,6 +45858,95 @@ function withHostSessionTitles(result, records) {
45397
45858
  };
45398
45859
  }
45399
45860
 
45861
+ // packages/host-runtime/src/usage-statistics-sources.ts
45862
+ import { setTimeout as delay6 } from "node:timers/promises";
45863
+ async function* readUsageStatisticsSources(capability, sources, signal) {
45864
+ let pending = sources;
45865
+ for (let attempt = 0; ; attempt++) {
45866
+ const changed = [];
45867
+ for (const source of pending) {
45868
+ signal.throwIfAborted();
45869
+ try {
45870
+ const entries = (await capability.readSource(source.id, signal)).map(parseHarnessUsageEntry).filter((entry) => entry !== null);
45871
+ yield { source, entries };
45872
+ } catch (error51) {
45873
+ signal.throwIfAborted();
45874
+ if (HarnessUsageSourceChangedError.is(error51) && attempt < 2) changed.push(source);
45875
+ else yield { source, error: error51 };
45876
+ }
45877
+ }
45878
+ if (!changed.length) return;
45879
+ await delay6(50 * (attempt + 1), void 0, { signal });
45880
+ let current;
45881
+ try {
45882
+ current = new Map(
45883
+ (await capability.listSources(signal)).map((source) => [source.id, source])
45884
+ );
45885
+ } catch (error51) {
45886
+ signal.throwIfAborted();
45887
+ for (const source of changed) yield { source, error: error51 };
45888
+ return;
45889
+ }
45890
+ const next = [];
45891
+ for (const source of changed) {
45892
+ const fresh = current.get(source.id);
45893
+ if (fresh) next.push(fresh);
45894
+ else yield { source, removed: true };
45895
+ }
45896
+ pending = next;
45897
+ }
45898
+ }
45899
+
45900
+ // packages/host-runtime/src/usage-statistics-calendar.ts
45901
+ function dateKey(year, month, day) {
45902
+ return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
45903
+ }
45904
+ function createUsageStatisticsCalendar(timeZone) {
45905
+ const localZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
45906
+ const zone = timeZone ?? localZone;
45907
+ if (zone === localZone) {
45908
+ return {
45909
+ timeZone: zone,
45910
+ at(ms) {
45911
+ const date5 = new Date(ms);
45912
+ return {
45913
+ date: dateKey(date5.getFullYear(), date5.getMonth() + 1, date5.getDate()),
45914
+ weekday: date5.getDay(),
45915
+ hour: date5.getHours()
45916
+ };
45917
+ }
45918
+ };
45919
+ }
45920
+ const format = new Intl.DateTimeFormat("en-US", {
45921
+ timeZone: zone,
45922
+ calendar: "gregory",
45923
+ numberingSystem: "latn",
45924
+ year: "numeric",
45925
+ month: "2-digit",
45926
+ day: "2-digit",
45927
+ hour: "2-digit",
45928
+ hourCycle: "h23"
45929
+ });
45930
+ return {
45931
+ timeZone: zone,
45932
+ at(ms) {
45933
+ const parts = format.formatToParts(ms);
45934
+ const part = (type) => Number(parts.find((value2) => value2.type === type)?.value);
45935
+ const year = part("year"), month = part("month"), day = part("day");
45936
+ return {
45937
+ date: dateKey(year, month, day),
45938
+ weekday: new Date(Date.UTC(year, month - 1, day)).getUTCDay(),
45939
+ hour: part("hour")
45940
+ };
45941
+ }
45942
+ };
45943
+ }
45944
+ function shiftUsageDate(date5, days) {
45945
+ const value2 = /* @__PURE__ */ new Date(`${date5}T12:00:00Z`);
45946
+ value2.setUTCDate(value2.getUTCDate() + days);
45947
+ return dateKey(value2.getUTCFullYear(), value2.getUTCMonth() + 1, value2.getUTCDate());
45948
+ }
45949
+
45400
45950
  // packages/host-runtime/src/usage-statistics.ts
45401
45951
  var CACHE_VERSION = 7;
45402
45952
  var STALE_AFTER_MS = 1e4;
@@ -45457,17 +46007,6 @@ function expand(value2, intern) {
45457
46007
  function message(error51) {
45458
46008
  return error51 instanceof Error ? error51.message : String(error51);
45459
46009
  }
45460
- function localDate2(ms) {
45461
- const date5 = new Date(ms);
45462
- const month = String(date5.getMonth() + 1).padStart(2, "0");
45463
- const day = String(date5.getDate()).padStart(2, "0");
45464
- return `${date5.getFullYear()}-${month}-${day}`;
45465
- }
45466
- function shiftDate(date5, days) {
45467
- const value2 = /* @__PURE__ */ new Date(`${date5}T12:00:00`);
45468
- value2.setDate(value2.getDate() + days);
45469
- return localDate2(value2.getTime());
45470
- }
45471
46010
  var SESSIONS_PER_MEASURE = 50;
45472
46011
  var MODELS_PER_SESSION = 16;
45473
46012
  function emptyTotals() {
@@ -45654,23 +46193,27 @@ var UsageStatistics = class {
45654
46193
  }
45655
46194
  for (const { harness: harness2, capability, ids } of listed) {
45656
46195
  const cache = this.#cache(harness2);
45657
- const present = /* @__PURE__ */ new Set();
46196
+ const present = new Set(ids.map(({ id: id2 }) => id2));
45658
46197
  let failed = null;
45659
- for (const { id: id2, fingerprint } of ids) {
45660
- present.add(id2);
45661
- if (cache.sources.get(id2)?.fingerprint !== fingerprint) {
45662
- try {
45663
- const entries = (await capability.readSource(id2, signal)).map(parseHarnessUsageEntry).filter((entry) => entry !== null);
45664
- cache.sources.set(id2, { fingerprint, entries });
46198
+ const pending = ids.filter(
46199
+ ({ id: id2, fingerprint }) => cache.sources.get(id2)?.fingerprint !== fingerprint
46200
+ );
46201
+ this.#progress.read += ids.length - pending.length;
46202
+ try {
46203
+ for await (const result of readUsageStatisticsSources(capability, pending, signal)) {
46204
+ const { id: id2, fingerprint } = result.source;
46205
+ if ("entries" in result) {
46206
+ cache.sources.set(id2, { fingerprint, entries: result.entries });
45665
46207
  cache.dirty = true;
45666
46208
  this.#generation += 1;
45667
- } catch (error51) {
45668
- if (signal.aborted) return;
45669
- failed ??= message(error51);
45670
- }
46209
+ } else if ("error" in result) failed ??= message(result.error);
46210
+ else present.delete(id2);
46211
+ this.#progress.read += 1;
45671
46212
  await yieldToEventLoop();
45672
46213
  }
45673
- this.#progress.read += 1;
46214
+ } catch (error51) {
46215
+ if (signal.aborted) return;
46216
+ throw error51;
45674
46217
  }
45675
46218
  for (const id2 of cache.sources.keys()) {
45676
46219
  if (!present.has(id2)) {
@@ -45735,7 +46278,7 @@ var UsageStatistics = class {
45735
46278
  async #persist(harness2, cache) {
45736
46279
  if (!cache.dirty || this.#now() - cache.persistedAtMs < PERSIST_INTERVAL_MS) return;
45737
46280
  const file2 = this.#file(harness2);
45738
- const temporary = `${file2}.${randomUUID20()}.tmp`;
46281
+ const temporary = `${file2}.${randomUUID22()}.tmp`;
45739
46282
  try {
45740
46283
  await mkdir17(this.#directory, { recursive: true });
45741
46284
  const sources = [...cache.sources].map(([id2, source]) => [
@@ -45753,9 +46296,10 @@ var UsageStatistics = class {
45753
46296
  await rm16(temporary, { force: true });
45754
46297
  }
45755
46298
  }
45756
- /** Every request once, per Harness in source order, with its local date and hour. */
45757
- #indexed() {
45758
- if (this.#index?.generation === this.#generation) return this.#index.entries;
46299
+ /** Every request once, per Harness in source order, in the requested calendar. */
46300
+ #indexed(calendar) {
46301
+ if (this.#index?.generation === this.#generation && this.#index.timeZone === calendar.timeZone)
46302
+ return this.#index.entries;
45759
46303
  const entries = [];
45760
46304
  for (const [harness2, cache] of this.#caches) {
45761
46305
  const seen = /* @__PURE__ */ new Set();
@@ -45763,26 +46307,20 @@ var UsageStatistics = class {
45763
46307
  for (const entry of parsed2) {
45764
46308
  if (seen.has(entry.id)) continue;
45765
46309
  seen.add(entry.id);
45766
- const at = new Date(entry.occurredAtMs);
45767
- entries.push({
45768
- harness: harness2,
45769
- entry,
45770
- date: localDate2(entry.occurredAtMs),
45771
- weekday: at.getDay(),
45772
- hour: at.getHours()
45773
- });
46310
+ entries.push({ harness: harness2, entry, ...calendar.at(entry.occurredAtMs) });
45774
46311
  }
45775
46312
  }
45776
46313
  }
45777
- this.#index = { generation: this.#generation, entries };
46314
+ this.#index = { generation: this.#generation, timeZone: calendar.timeZone, entries };
45778
46315
  return entries;
45779
46316
  }
45780
46317
  #aggregate(params, now, lookup) {
45781
46318
  const { range } = params;
45782
46319
  const days = RANGE_DAYS[range];
45783
- const to = localDate2(now);
46320
+ const calendar = createUsageStatisticsCalendar(params.timeZone);
46321
+ const to = calendar.at(now).date;
45784
46322
  let from = null;
45785
- if (days !== null) from = shiftDate(to, -days + 1);
46323
+ if (days !== null) from = shiftUsageDate(to, -days + 1);
45786
46324
  const inRange = (date5) => (from === null || date5 >= from) && date5 <= to;
45787
46325
  const day = params.date !== void 0 && inRange(params.date) ? params.date : null;
45788
46326
  const harnessFilter = params.harness ?? null;
@@ -45823,7 +46361,7 @@ var UsageStatistics = class {
45823
46361
  const harnessPriced = /* @__PURE__ */ new Map();
45824
46362
  const byProject = /* @__PURE__ */ new Map();
45825
46363
  const sessions = /* @__PURE__ */ new Map();
45826
- for (const indexed of this.#indexed()) {
46364
+ for (const indexed of this.#indexed(calendar)) {
45827
46365
  const { harness: harness2, entry, date: date5 } = indexed;
45828
46366
  if (!inRange(date5)) continue;
45829
46367
  const model2 = entry.model ?? null;
@@ -46351,7 +46889,7 @@ async function runHostRuntime(input) {
46351
46889
  }
46352
46890
 
46353
46891
  // packages/host-runtime/src/remote-host-install.ts
46354
- import { createHash as createHash11, randomUUID as randomUUID21 } from "node:crypto";
46892
+ import { createHash as createHash11, randomUUID as randomUUID23 } from "node:crypto";
46355
46893
  import { constants as fsConstants } from "node:fs";
46356
46894
  import {
46357
46895
  access as access3,
@@ -46450,7 +46988,7 @@ async function writeAtomic(filePath, contents, mode) {
46450
46988
  await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
46451
46989
  const temporary = path38.join(
46452
46990
  path38.dirname(filePath),
46453
- `.${path38.basename(filePath)}.${process.pid}.${randomUUID21()}.tmp`
46991
+ `.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
46454
46992
  );
46455
46993
  try {
46456
46994
  if (typeof contents === "string") {
@@ -46474,7 +47012,7 @@ async function writeAtomicExecutable(filePath, sourcePath) {
46474
47012
  await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
46475
47013
  const temporary = path38.join(
46476
47014
  path38.dirname(filePath),
46477
- `.${path38.basename(filePath)}.${process.pid}.${randomUUID21()}.tmp`
47015
+ `.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
46478
47016
  );
46479
47017
  try {
46480
47018
  await copyFile4(sourcePath, temporary);
@@ -47215,6 +47753,7 @@ var harnessBrokerMethodSchema = external_exports.enum([
47215
47753
  "adapter.open",
47216
47754
  "adapter.subagent.readSnapshot",
47217
47755
  "session.readSnapshot",
47756
+ "session.readCapabilities",
47218
47757
  "session.refreshUsage",
47219
47758
  "session.execute",
47220
47759
  "session.commands.list",
@@ -47397,6 +47936,11 @@ var turnStartSchema = external_exports.object({
47397
47936
  turnId: hostTurnIdSchema,
47398
47937
  input: external_exports.array(textInputSchema)
47399
47938
  }).strict();
47939
+ var turnSteerSchema = external_exports.object({
47940
+ type: external_exports.literal("turn.steer"),
47941
+ turnId: hostTurnIdSchema,
47942
+ input: external_exports.array(textInputSchema)
47943
+ }).strict();
47400
47944
  var turnCancelSchema = external_exports.object({ type: external_exports.literal("turn.cancel"), turnId: hostTurnIdSchema }).strict();
47401
47945
  var interactionResponseSchema = external_exports.union([
47402
47946
  external_exports.object({
@@ -47422,6 +47966,7 @@ var permissionSelectSchema = external_exports.object({
47422
47966
  }).strict();
47423
47967
  var brokerHostCommandSchema = external_exports.discriminatedUnion("type", [
47424
47968
  turnStartSchema,
47969
+ turnSteerSchema,
47425
47970
  turnCancelSchema,
47426
47971
  interactionRespondSchema,
47427
47972
  modelSelectSchema,
@@ -47556,7 +48101,7 @@ var harnessOutputSchema = external_exports.custom((value2) => {
47556
48101
  });
47557
48102
 
47558
48103
  // packages/harness-broker/dist/server.js
47559
- import { randomBytes as randomBytes5, randomUUID as randomUUID22 } from "node:crypto";
48104
+ import { randomBytes as randomBytes5, randomUUID as randomUUID24 } from "node:crypto";
47560
48105
  import { chmod as chmod6, lstat as lstat10, mkdir as mkdir19, open as open11, readFile as readFile19, rename as rename16, rm as rm18 } from "node:fs/promises";
47561
48106
  import net4, {} from "node:net";
47562
48107
  import path41 from "node:path";
@@ -47615,7 +48160,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
47615
48160
  }
47616
48161
  }
47617
48162
  async function publishDescriptor(descriptorPath, descriptor) {
47618
- const temporary = `${descriptorPath}.${process.pid}.${randomUUID22()}.tmp`;
48163
+ const temporary = `${descriptorPath}.${process.pid}.${randomUUID24()}.tmp`;
47619
48164
  const handle = await open11(temporary, "wx", 384);
47620
48165
  try {
47621
48166
  await handle.writeFile(`${JSON.stringify(descriptor)}
@@ -47640,6 +48185,7 @@ function sessionMetadata(record4) {
47640
48185
  sessionId: record4.id,
47641
48186
  sessionGeneration: record4.generation,
47642
48187
  capabilities: record4.session.capabilities,
48188
+ readCapabilities: true,
47643
48189
  initialState: {
47644
48190
  ...initialState,
47645
48191
  ...record4.nativeRef ? { nativeRef: record4.nativeRef } : {},
@@ -47692,7 +48238,7 @@ async function startHarnessBrokerServer(input) {
47692
48238
  await assertNoLiveDescriptor(input.descriptorPath);
47693
48239
  if (process.platform !== "win32")
47694
48240
  await prepareUnixSocketPath(input.socketPath);
47695
- const generation = input.generation ?? randomUUID22();
48241
+ const generation = input.generation ?? randomUUID24();
47696
48242
  const token = input.token ?? randomBytes5(32).toString("hex");
47697
48243
  const descriptor = {
47698
48244
  schemaVersion: 1,
@@ -47733,7 +48279,7 @@ async function startHarnessBrokerServer(input) {
47733
48279
  };
47734
48280
  const server = net4.createServer((socket) => {
47735
48281
  const state = {
47736
- id: randomUUID22(),
48282
+ id: randomUUID24(),
47737
48283
  socket,
47738
48284
  authenticated: false,
47739
48285
  inputSequence: 0,
@@ -47971,7 +48517,7 @@ async function startHarnessBrokerServer(input) {
47971
48517
  }
47972
48518
  };
47973
48519
  }
47974
- const openReservation = randomUUID22();
48520
+ const openReservation = randomUUID24();
47975
48521
  if (sourceKey)
47976
48522
  nativeWriters.set(sourceKey, openReservation);
47977
48523
  const provisionalReservation = openInput.kind === "create" ? openReservation : void 0;
@@ -48115,6 +48661,8 @@ async function startHarnessBrokerServer(input) {
48115
48661
  let result;
48116
48662
  if (command.type === "turn.start")
48117
48663
  result = await record5.session.execute(command);
48664
+ else if (command.type === "turn.steer")
48665
+ result = await record5.session.execute(command);
48118
48666
  else if (command.type === "turn.cancel")
48119
48667
  result = await record5.session.execute(command);
48120
48668
  else if (command.type === "interaction.respond") {
@@ -48146,6 +48694,10 @@ async function startHarnessBrokerServer(input) {
48146
48694
  }
48147
48695
  return result;
48148
48696
  }
48697
+ if (request.method === "session.readCapabilities") {
48698
+ const session = requireSession(request.params).session;
48699
+ return session.readCapabilities ? session.readCapabilities() : session.capabilities;
48700
+ }
48149
48701
  if (request.method === "session.readSnapshot") {
48150
48702
  return requireSession(request.params).session.readSnapshot();
48151
48703
  }
@@ -48272,7 +48824,7 @@ async function startHarnessBrokerServer(input) {
48272
48824
  }
48273
48825
  state.authenticated = true;
48274
48826
  state.inputSequence = 1;
48275
- await send({ kind: "response", id: randomUUID22(), ok: true, value: { ready: true } });
48827
+ await send({ kind: "response", id: randomUUID24(), ok: true, value: { ready: true } });
48276
48828
  return;
48277
48829
  }
48278
48830
  const parsed2 = harnessBrokerRequestSchema.safeParse(raw);