@codexhost/cli-darwin-x64 0.13.3 → 0.15.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") } : {},
@@ -8457,10 +8461,10 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
8457
8461
  const shape = def.shape;
8458
8462
  const propValues = {};
8459
8463
  for (const key in shape) {
8460
- const field = shape[key]._zod;
8461
- if (field.values) {
8464
+ const field2 = shape[key]._zod;
8465
+ if (field2.values) {
8462
8466
  propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
8463
- for (const v of field.values)
8467
+ for (const v of field2.values)
8464
8468
  propValues[key].add(v);
8465
8469
  }
8466
8470
  }
@@ -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),
@@ -20210,6 +20223,53 @@ var THREAD_PREWARM_DISCARD_METHOD = "codexhost/thread/prewarm/discard";
20210
20223
  var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
20211
20224
  var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
20212
20225
 
20226
+ // packages/shared-contracts/dist/thread-questions.js
20227
+ var THREAD_QUESTIONS_LIST_METHOD = "codexhost/thread/questions/list";
20228
+ var THREAD_QUESTION_RESPOND_METHOD = "codexhost/thread/question/respond";
20229
+ var field = external_exports.discriminatedUnion("type", [
20230
+ external_exports.object({
20231
+ id: external_exports.string().min(1),
20232
+ type: external_exports.literal("choice"),
20233
+ prompt: external_exports.string(),
20234
+ options: external_exports.array(external_exports.object({
20235
+ value: external_exports.string().min(1),
20236
+ label: external_exports.string(),
20237
+ description: external_exports.string().optional()
20238
+ })).min(1),
20239
+ multiple: external_exports.boolean(),
20240
+ allowOther: external_exports.boolean(),
20241
+ optional: external_exports.boolean()
20242
+ }),
20243
+ external_exports.object({
20244
+ id: external_exports.string().min(1),
20245
+ type: external_exports.literal("text"),
20246
+ prompt: external_exports.string(),
20247
+ multiline: external_exports.boolean(),
20248
+ secret: external_exports.literal(false),
20249
+ optional: external_exports.boolean(),
20250
+ placeholder: external_exports.string().optional(),
20251
+ prefill: external_exports.string().optional()
20252
+ })
20253
+ ]);
20254
+ var threadQuestionSchema = external_exports.object({
20255
+ interactionId: external_exports.string().min(1),
20256
+ turnId: external_exports.string().min(1),
20257
+ title: external_exports.string().optional(),
20258
+ questions: external_exports.array(field).min(1)
20259
+ }).refine(({ questions }) => questions.some((q) => q.type === "choice" && q.multiple), {
20260
+ message: "Shared cards require at least one multi-select question"
20261
+ });
20262
+ var threadQuestionsListParamsSchema = external_exports.strictObject({ threadId: external_exports.string().min(1) });
20263
+ var threadQuestionsResultSchema = external_exports.object({ questions: external_exports.array(threadQuestionSchema) });
20264
+ var threadQuestionRespondParamsSchema = external_exports.strictObject({
20265
+ threadId: external_exports.string().min(1),
20266
+ turnId: external_exports.string().min(1),
20267
+ interactionId: external_exports.string().min(1),
20268
+ answers: external_exports.record(external_exports.string(), external_exports.array(external_exports.string())),
20269
+ cancelled: external_exports.boolean().default(false)
20270
+ });
20271
+ var threadQuestionRespondResultSchema = external_exports.object({ accepted: external_exports.literal(true) });
20272
+
20213
20273
  // packages/shared-contracts/dist/console.js
20214
20274
  var consoleAnnouncementSchema = external_exports.strictObject({
20215
20275
  title: external_exports.string().trim().min(1).max(200),
@@ -20231,6 +20291,8 @@ var CONSOLE_HOST_METHODS = Object.freeze([
20231
20291
  "codexhost/harness/display-settings/set",
20232
20292
  "codexhost/harness/inspect",
20233
20293
  "codexhost/harness/installation",
20294
+ "codexhost/harness/installation/start",
20295
+ "codexhost/harness/installation/status",
20234
20296
  "codexhost/harness/launch-settings/get",
20235
20297
  "codexhost/harness/launch-settings/set",
20236
20298
  "codexhost/harness/web-ui/open",
@@ -20312,7 +20374,18 @@ var threadManualCompactionStartedSchema = external_exports.strictObject({
20312
20374
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
20313
20375
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
20314
20376
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
20377
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
20378
+ var composerIndicatorsSchema = external_exports.array(external_exports.object({
20379
+ kind: external_exports.literal("countdown"),
20380
+ id: external_exports.string().min(1).max(64),
20381
+ expiresAtUnix: nonNegativeSafeIntegerSchema,
20382
+ label: indicatorTextSchema(256).optional(),
20383
+ tooltip: indicatorTextSchema(1024).optional()
20384
+ }).strict()).max(2).refine((entries) => new Set(entries.map(({ id: id2 }) => id2)).size === entries.length, {
20385
+ message: "Composer indicator IDs must be unique"
20386
+ });
20315
20387
  var threadUsageSnapshotSchema = external_exports.object({
20388
+ composerIndicators: composerIndicatorsSchema.optional(),
20316
20389
  inputTokens: nonNegativeSafeIntegerSchema.optional(),
20317
20390
  cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
20318
20391
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -20728,7 +20801,9 @@ var harnessSessionCapabilitiesSchema = external_exports.object({
20728
20801
  }).strict().optional(),
20729
20802
  autonomousTurns: external_exports.object({
20730
20803
  observe: external_exports.boolean()
20731
- }).strict().optional()
20804
+ }).strict().optional(),
20805
+ /** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
20806
+ steer: external_exports.boolean().optional()
20732
20807
  }).strict();
20733
20808
  var harnessConfigurationStateSchema = external_exports.object({
20734
20809
  effectiveModel: harnessModelRefSchema.optional(),
@@ -20776,7 +20851,9 @@ var harnessInspectionSchema = external_exports.union([
20776
20851
  var harnessInspectParamsSchema = external_exports.object({
20777
20852
  harnessId: harnessIdSchema,
20778
20853
  cwd: nonBlankTextSchema2.max(16384).optional(),
20779
- refresh: external_exports.boolean().optional()
20854
+ refresh: external_exports.boolean().optional(),
20855
+ /** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
20856
+ purpose: external_exports.literal("availability").optional()
20780
20857
  }).strict();
20781
20858
  var harnessWebUiOpenParamsSchema = external_exports.object({
20782
20859
  harnessId: harnessIdSchema
@@ -20859,6 +20936,16 @@ var threadOwnershipListResultSchema = external_exports.object({
20859
20936
  seen.add(thread.threadId);
20860
20937
  }
20861
20938
  });
20939
+ var threadSteeringInspectParamsSchema = external_exports.object({
20940
+ threadId: hostThreadIdSchema,
20941
+ /** The text about to be steered; a Harness command always stops and restarts. */
20942
+ text: external_exports.string().optional()
20943
+ }).strict();
20944
+ var THREAD_STEER_DELIVERY_PARAM = "codexhostSteerDelivery";
20945
+ var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
20946
+ var threadSteeringInspectResultSchema = external_exports.object({
20947
+ delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
20948
+ }).strict();
20862
20949
 
20863
20950
  // packages/shared-contracts/dist/harness-plugins.js
20864
20951
  var HARNESS_PLUGIN_API_VERSION = 1;
@@ -20979,6 +21066,8 @@ var harnessLaunchSettingsSchema = external_exports.object({
20979
21066
 
20980
21067
  // packages/shared-contracts/dist/harness-installation.js
20981
21068
  var HARNESS_INSTALLATION_METHOD = "codexhost/harness/installation";
21069
+ var HARNESS_INSTALLATION_START_METHOD = "codexhost/harness/installation/start";
21070
+ var HARNESS_INSTALLATION_STATUS_METHOD = "codexhost/harness/installation/status";
20982
21071
  var harnessInstallationParamsSchema = external_exports.object({
20983
21072
  harnessId: harnessIdSchema,
20984
21073
  action: external_exports.enum(["check", "update", "install"])
@@ -20988,6 +21077,10 @@ var harnessInstallationStateSchema = external_exports.object({
20988
21077
  latestVersion: external_exports.string().min(1).max(128),
20989
21078
  updateAvailable: external_exports.boolean(),
20990
21079
  canUpdate: external_exports.boolean(),
21080
+ /** Defaults to CLI; some Harnesses ship only inside a desktop application. */
21081
+ versionKind: external_exports.enum(["cli", "application"]).optional(),
21082
+ /** Official download opened by the user; does not imply an automatic installation. */
21083
+ manualUpdateUrl: external_exports.url().max(2048).refine((value2) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value2), "Manual updates require a credential-free HTTPS URL").optional(),
20991
21084
  // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
20992
21085
  message: external_exports.string().max(2048).optional(),
20993
21086
  messageCode: external_exports.string().min(1).max(128).optional(),
@@ -20995,6 +21088,20 @@ var harnessInstallationStateSchema = external_exports.object({
20995
21088
  notice: harnessLocalizedTextSchema.optional(),
20996
21089
  latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
20997
21090
  }).strict();
21091
+ var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
21092
+ var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
21093
+ external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
21094
+ external_exports.object({
21095
+ taskId: external_exports.string().uuid(),
21096
+ status: external_exports.literal("succeeded"),
21097
+ result: harnessInstallationStateSchema
21098
+ }).strict(),
21099
+ external_exports.object({
21100
+ taskId: external_exports.string().uuid(),
21101
+ status: external_exports.literal("failed"),
21102
+ error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
21103
+ }).strict()
21104
+ ]);
20998
21105
 
20999
21106
  // packages/shared-contracts/dist/codex-accounts.js
21000
21107
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
@@ -22982,9 +23089,13 @@ function requestManagerFromHookState(value2, hostId2) {
22982
23089
  const direct = manager(value2) ?? manager(value2.manager);
22983
23090
  if (direct)
22984
23091
  return direct;
22985
- if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function" || typeof value2.waitForManagerForHostId !== "function")
23092
+ if (!hostId2 || typeof value2.addManager !== "function" || typeof value2.getForHostId !== "function")
22986
23093
  return null;
22987
- return manager(value2.getForHostId(hostId2));
23094
+ try {
23095
+ return manager(value2.getForHostId(hostId2));
23096
+ } catch {
23097
+ return null;
23098
+ }
22988
23099
  }
22989
23100
  function discoverRendererHosts(root, ancestors = committedReactAncestors, managerFrom = requestManagerFromHookState) {
22990
23101
  const editors = [
@@ -23020,7 +23131,7 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
23020
23131
  const manager = managerFrom(value2);
23021
23132
  if (manager)
23022
23133
  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") {
23134
+ if (value2 && typeof value2 === "object" && "addManager" in value2 && typeof value2.addManager === "function" && "getForHostId" in value2 && typeof value2.getForHostId === "function") {
23024
23135
  registries.add(value2);
23025
23136
  }
23026
23137
  hook = hook.next && typeof hook.next === "object" ? hook.next : null;
@@ -23036,7 +23147,13 @@ function discoverRendererHosts(root, ancestors = committedReactAncestors, manage
23036
23147
  function resolveRendererHostManager(discovery, hostId2, managerFrom = requestManagerFromHookState) {
23037
23148
  if (!hostId2)
23038
23149
  return null;
23039
- const candidates = discovery.registries.length ? discovery.registries.map((registry2) => managerFrom(registry2.getForHostId(hostId2))) : discovery.managers;
23150
+ const candidates = discovery.registries.length ? discovery.registries.flatMap((registry2) => {
23151
+ try {
23152
+ return [managerFrom(registry2.getForHostId(hostId2))];
23153
+ } catch {
23154
+ return [];
23155
+ }
23156
+ }) : discovery.managers;
23040
23157
  const matching = new Set(candidates.filter((manager) => manager && (manager.getHostId?.() ?? manager.requestClient.hostId) === hostId2 && (manager.requestClient.hostId === void 0 || manager.requestClient.hostId === hostId2)));
23041
23158
  return matching.size === 1 ? matching.values().next().value ?? null : null;
23042
23159
  }
@@ -24048,6 +24165,64 @@ async function handleHarnessInstallation(params, adapters) {
24048
24165
  }
24049
24166
  }
24050
24167
 
24168
+ // packages/host-runtime/src/harness-installation-tasks.ts
24169
+ import { randomUUID as randomUUID3 } from "node:crypto";
24170
+ var HarnessInstallationTasks = class {
24171
+ #tasks = /* @__PURE__ */ new Map();
24172
+ #active = /* @__PURE__ */ new Map();
24173
+ #prune() {
24174
+ const cutoff = Date.now() - 15 * 6e4;
24175
+ for (const [id2, task] of this.#tasks) {
24176
+ if (task.finishedAt !== void 0 && task.finishedAt < cutoff) this.#tasks.delete(id2);
24177
+ }
24178
+ }
24179
+ start(params, adapters) {
24180
+ const parsed2 = harnessInstallationParamsSchema.safeParse(params);
24181
+ if (!parsed2.success)
24182
+ throw new HarnessInstallationError(-32602, "Invalid Harness installation request");
24183
+ this.#prune();
24184
+ const key = JSON.stringify([parsed2.data.harnessId, parsed2.data.action]);
24185
+ const activeId = this.#active.get(key);
24186
+ const active = activeId ? this.#tasks.get(activeId) : void 0;
24187
+ if (active) return active.state;
24188
+ const taskId = randomUUID3();
24189
+ const task = {
24190
+ state: { taskId, status: "running" }
24191
+ };
24192
+ this.#tasks.set(taskId, task);
24193
+ this.#active.set(key, taskId);
24194
+ void handleHarnessInstallation(parsed2.data, adapters).then(
24195
+ (result) => {
24196
+ task.state = { taskId, status: "succeeded", result };
24197
+ },
24198
+ (error51) => {
24199
+ task.state = {
24200
+ taskId,
24201
+ status: "failed",
24202
+ error: error51 instanceof HarnessInstallationError ? { code: error51.code, message: error51.message } : { code: -32077, message: "Harness version management failed" }
24203
+ };
24204
+ }
24205
+ ).finally(() => {
24206
+ task.finishedAt = Date.now();
24207
+ this.#active.delete(key);
24208
+ });
24209
+ return task.state;
24210
+ }
24211
+ status(params) {
24212
+ const parsed2 = harnessInstallationTaskParamsSchema.safeParse(params);
24213
+ if (!parsed2.success)
24214
+ throw new HarnessInstallationError(-32602, "Invalid Harness installation task request");
24215
+ this.#prune();
24216
+ const task = this.#tasks.get(parsed2.data.taskId);
24217
+ if (!task)
24218
+ throw new HarnessInstallationError(
24219
+ -32079,
24220
+ "Harness installation task is unavailable on this Host"
24221
+ );
24222
+ return task.state;
24223
+ }
24224
+ };
24225
+
24051
24226
  // packages/host-runtime/src/account/codex-credential-export.ts
24052
24227
  import { createHash as createHash3 } from "node:crypto";
24053
24228
  import { readFile as readFile8 } from "node:fs/promises";
@@ -24140,7 +24315,7 @@ async function listOthers(adapter) {
24140
24315
  }
24141
24316
 
24142
24317
  // packages/host-runtime/src/harness-display-settings.ts
24143
- import { randomUUID as randomUUID3 } from "node:crypto";
24318
+ import { randomUUID as randomUUID4 } from "node:crypto";
24144
24319
  import { link, mkdir as mkdir6, readFile as readFile9, rename as rename4, rm as rm5, writeFile as writeFile6 } from "node:fs/promises";
24145
24320
  import os4 from "node:os";
24146
24321
  import path13 from "node:path";
@@ -24165,7 +24340,7 @@ var HarnessDisplaySettingsStore = class {
24165
24340
  async set(input) {
24166
24341
  const entries = harnessDisplayEntriesSchema.parse(input.entries);
24167
24342
  await mkdir6(path13.dirname(this.#file), { recursive: true, mode: 448 });
24168
- const temporary = `${this.#file}.${randomUUID3()}.tmp`;
24343
+ const temporary = `${this.#file}.${randomUUID4()}.tmp`;
24169
24344
  try {
24170
24345
  await writeFile6(temporary, `${JSON.stringify(entries)}
24171
24346
  `, { mode: 384, flag: "wx" });
@@ -24186,7 +24361,7 @@ var HarnessDisplaySettingsStore = class {
24186
24361
  };
24187
24362
 
24188
24363
  // packages/host-runtime/src/model-price-overrides-file.ts
24189
- import { randomUUID as randomUUID4 } from "node:crypto";
24364
+ import { randomUUID as randomUUID5 } from "node:crypto";
24190
24365
  import { mkdir as mkdir8, readFile as readFile11, rename as rename6, rm as rm6, writeFile as writeFile8 } from "node:fs/promises";
24191
24366
  import path15 from "node:path";
24192
24367
 
@@ -24346,9 +24521,9 @@ function parseModelPriceOverrides(value2) {
24346
24521
  if (key.length === 0 || !isRecord3(entry)) {
24347
24522
  throw new Error(`Price override '${key}' is invalid`);
24348
24523
  }
24349
- for (const field of Object.keys(entry)) {
24350
- if (!["input", "output", "cacheRead", "cacheWrite", "cacheWrite1h"].includes(field)) {
24351
- throw new Error(`Price override '${key}' contains unknown field '${field}'`);
24524
+ for (const field2 of Object.keys(entry)) {
24525
+ if (!["input", "output", "cacheRead", "cacheWrite", "cacheWrite1h"].includes(field2)) {
24526
+ throw new Error(`Price override '${key}' contains unknown field '${field2}'`);
24352
24527
  }
24353
24528
  }
24354
24529
  const input = price(entry.input);
@@ -24357,11 +24532,11 @@ function parseModelPriceOverrides(value2) {
24357
24532
  throw new Error(`Price override '${key}' needs non-negative 'input' and 'output'`);
24358
24533
  }
24359
24534
  const resolved = { input, output };
24360
- for (const field of ["cacheRead", "cacheWrite", "cacheWrite1h"]) {
24361
- if (entry[field] === void 0) continue;
24362
- const candidate = price(entry[field]);
24363
- if (candidate === null) throw new Error(`Price override '${key}' has invalid '${field}'`);
24364
- resolved[field] = candidate;
24535
+ for (const field2 of ["cacheRead", "cacheWrite", "cacheWrite1h"]) {
24536
+ if (entry[field2] === void 0) continue;
24537
+ const candidate = price(entry[field2]);
24538
+ if (candidate === null) throw new Error(`Price override '${key}' has invalid '${field2}'`);
24539
+ resolved[field2] = candidate;
24365
24540
  }
24366
24541
  overrides.set(key, resolved);
24367
24542
  }
@@ -24761,7 +24936,7 @@ async function updateModelPriceOverridesFile(file2, change) {
24761
24936
  const updated = { ...document, models: next };
24762
24937
  parseModelPriceOverrides(updated);
24763
24938
  await mkdir8(path15.dirname(file2), { recursive: true });
24764
- const temporary = `${file2}.${randomUUID4()}.tmp`;
24939
+ const temporary = `${file2}.${randomUUID5()}.tmp`;
24765
24940
  try {
24766
24941
  await writeFile8(temporary, `${JSON.stringify(updated, null, 2)}
24767
24942
  `, { flag: "wx" });
@@ -24797,11 +24972,11 @@ async function handleModelPriceOverridesRequest(catalog, method, params) {
24797
24972
  }
24798
24973
 
24799
24974
  // packages/host-runtime/src/delegation-skill.ts
24800
- import { createHash as createHash4, randomUUID as randomUUID5 } from "node:crypto";
24975
+ import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
24801
24976
  import { mkdir as mkdir9, open as open4, readFile as readFile12, rename as rename7, rm as rm7, stat as stat5 } from "node:fs/promises";
24802
24977
  import os6 from "node:os";
24803
24978
  import path16 from "node:path";
24804
- var SKILL_VERSION = 9;
24979
+ var SKILL_VERSION = 10;
24805
24980
  var DELEGATION_SKILL_NAME = "codexhost-delegation";
24806
24981
  var SKILL_RELATIVE_PATH = path16.join("skills", DELEGATION_SKILL_NAME, "SKILL.md");
24807
24982
  var PREVIOUS_MANAGED_DIGESTS = [
@@ -24815,7 +24990,9 @@ var PREVIOUS_MANAGED_DIGESTS = [
24815
24990
  "fa7944cd1e72ffbaf932fca2074bdb78aad4670d8990b6711220dd83c39509a0",
24816
24991
  "b9c1cce41d2556e73a6514aa55618d7d3f2f9ef935f5ae50b0da5a04941514b4",
24817
24992
  // v8, which ran a bare `codexhost` from PATH.
24818
- "ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde"
24993
+ "ca06be59f0d47c9a54d05ed2d9588c9c737306cc155cb4dff3fe2a2a61891dde",
24994
+ // v9, before the child-session name guidance.
24995
+ "b72a059e139bd5b93b95f7ac02ab80f428d5a721cc67b004210d5263e75baed7"
24819
24996
  ];
24820
24997
  var CODEXHOST_DELEGATION_SKILL = `---
24821
24998
  name: codexhost-delegation
@@ -24852,7 +25029,8 @@ Use the Harness native defaults. Inspect the target when a Model or Thinking
24852
25029
  selection is needed or the default is unavailable.
24853
25030
 
24854
25031
  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
25032
+ requested task. Give it a short task name that tells it apart from sibling
25033
+ tasks, using the help's task-name option. For an existing external session, resolve the target from the
24856
25034
  user-provided session link, identifier, or context and operate on that Thread
24857
25035
  directly; it need not have been created by the current assistant. If the target
24858
25036
  is ambiguous, ask the user to identify it. Keep requests to view or summarize a
@@ -24894,7 +25072,7 @@ async function readOptional(filePath) {
24894
25072
  }
24895
25073
  async function atomicWrite(filePath, content) {
24896
25074
  await mkdir9(path16.dirname(filePath), { recursive: true, mode: 448 });
24897
- const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID5()}.tmp`);
25075
+ const temporaryPath = path16.join(path16.dirname(filePath), `.SKILL.md.${randomUUID6()}.tmp`);
24898
25076
  const handle = await open4(temporaryPath, "wx", 384);
24899
25077
  try {
24900
25078
  await handle.writeFile(content, "utf8");
@@ -25049,6 +25227,42 @@ function parseHarnessAccountCredits(value2) {
25049
25227
  return parsed2.success ? parsed2.data : null;
25050
25228
  }
25051
25229
 
25230
+ // packages/harness-adapter/dist/question.js
25231
+ function invalidRequest(message2) {
25232
+ return { code: "invalidRequest", message: message2, retryable: false };
25233
+ }
25234
+ function validateHostQuestionResponse(interaction, response) {
25235
+ const questionIds = new Set(interaction.questions.map(({ id: id2 }) => id2));
25236
+ if (response.cancelled) {
25237
+ return Object.keys(response.answers).length === 0 ? null : invalidRequest("Cancelled Question Response must not contain answers");
25238
+ }
25239
+ for (const answerId of Object.keys(response.answers)) {
25240
+ if (!questionIds.has(answerId)) {
25241
+ return invalidRequest("Question Response contains an unknown Question ID");
25242
+ }
25243
+ }
25244
+ for (const question of interaction.questions) {
25245
+ const answers = response.answers[question.id] ?? [];
25246
+ if (!question.optional && answers.length === 0) {
25247
+ return invalidRequest("Question Response omits a required answer");
25248
+ }
25249
+ if (question.type === "text") {
25250
+ if (answers.length > 1) {
25251
+ return invalidRequest("Text Question accepts at most one answer");
25252
+ }
25253
+ continue;
25254
+ }
25255
+ if (!question.multiple && answers.length > 1) {
25256
+ return invalidRequest("Single-choice Question accepts at most one answer");
25257
+ }
25258
+ const declared = new Set(question.options.map(({ value: value2 }) => value2));
25259
+ if (!question.allowOther && answers.some((answer) => !declared.has(answer))) {
25260
+ return invalidRequest("Question Response contains an undeclared choice");
25261
+ }
25262
+ }
25263
+ return null;
25264
+ }
25265
+
25052
25266
  // packages/harness-adapter/dist/output-channel.js
25053
25267
  var HarnessOutputChannel = class {
25054
25268
  outputs;
@@ -25131,6 +25345,7 @@ var usageFields = /* @__PURE__ */ new Set([
25131
25345
  ...safeIntegerFields,
25132
25346
  ...percentFields,
25133
25347
  "sessionCacheUsage",
25348
+ "composerIndicators",
25134
25349
  "totalCostUsd",
25135
25350
  "totalCredits",
25136
25351
  "contextUsagePercent",
@@ -25153,26 +25368,27 @@ function parseHostUsage(value2) {
25153
25368
  throw new Error(`Harness Usage contains unknown field '${key}'`);
25154
25369
  }
25155
25370
  }
25156
- for (const field of [
25371
+ const indicators = value2.composerIndicators === void 0 ? {} : { composerIndicators: composerIndicatorsSchema.parse(value2.composerIndicators) };
25372
+ for (const field2 of [
25157
25373
  "totalCredits",
25158
25374
  "contextUsagePercent",
25159
25375
  "apiOutputTokensPerSecond"
25160
25376
  ]) {
25161
- const candidate = value2[field];
25377
+ const candidate = value2[field2];
25162
25378
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
25163
- throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
25379
+ throw new Error(`Harness Usage '${field2}' must be a finite non-negative number`);
25164
25380
  }
25165
25381
  }
25166
- for (const field of tokenFields) {
25167
- const candidate = value2[field];
25382
+ for (const field2 of tokenFields) {
25383
+ const candidate = value2[field2];
25168
25384
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
25169
- throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
25385
+ throw new Error(`Harness Usage '${field2}' must be a non-negative safe integer`);
25170
25386
  }
25171
25387
  }
25172
- for (const field of safeIntegerFields) {
25173
- const candidate = value2[field];
25388
+ for (const field2 of safeIntegerFields) {
25389
+ const candidate = value2[field2];
25174
25390
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
25175
- throw new Error(`Harness Usage '${field}' must be a non-negative safe integer`);
25391
+ throw new Error(`Harness Usage '${field2}' must be a non-negative safe integer`);
25176
25392
  }
25177
25393
  }
25178
25394
  if (value2.outputTokensPerSecond !== void 0 && (typeof value2.outputTokensPerSecond !== "number" || !Number.isFinite(value2.outputTokensPerSecond) || value2.outputTokensPerSecond < 0)) {
@@ -25181,10 +25397,10 @@ function parseHostUsage(value2) {
25181
25397
  if (value2.totalCostUsd !== void 0 && (typeof value2.totalCostUsd !== "number" || !Number.isFinite(value2.totalCostUsd) || value2.totalCostUsd < 0)) {
25182
25398
  throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
25183
25399
  }
25184
- for (const field of percentFields) {
25185
- const candidate = value2[field];
25400
+ for (const field2 of percentFields) {
25401
+ const candidate = value2[field2];
25186
25402
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
25187
- throw new Error(`Harness Usage '${field}' must be between 0 and 100`);
25403
+ throw new Error(`Harness Usage '${field2}' must be between 0 and 100`);
25188
25404
  }
25189
25405
  }
25190
25406
  if (value2.sessionCacheUsage !== void 0) {
@@ -25223,9 +25439,9 @@ function parseHostUsage(value2) {
25223
25439
  if (value2.costSource !== "publicPrice") {
25224
25440
  throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
25225
25441
  }
25226
- return { ...value2, unpricedModels: [...models] };
25442
+ return { ...value2, ...indicators, unpricedModels: [...models] };
25227
25443
  }
25228
- return { ...value2 };
25444
+ return { ...value2, ...indicators };
25229
25445
  }
25230
25446
  var requestTokenFields = [
25231
25447
  "inputTokens",
@@ -25255,19 +25471,19 @@ function parseHostUsageRequest(value2) {
25255
25471
  if (typeof value2.requestId !== "string" || value2.requestId.length === 0) {
25256
25472
  throw new Error("Harness Usage request 'requestId' must be a non-empty string");
25257
25473
  }
25258
- for (const field of ["model", "provider"]) {
25259
- const candidate = value2[field];
25474
+ for (const field2 of ["model", "provider"]) {
25475
+ const candidate = value2[field2];
25260
25476
  if (candidate !== void 0 && (typeof candidate !== "string" || candidate.length === 0)) {
25261
- throw new Error(`Harness Usage request '${field}' must be a non-empty string`);
25477
+ throw new Error(`Harness Usage request '${field2}' must be a non-empty string`);
25262
25478
  }
25263
25479
  }
25264
25480
  if (value2.historical !== void 0 && typeof value2.historical !== "boolean") {
25265
25481
  throw new Error("Harness Usage request 'historical' must be a boolean");
25266
25482
  }
25267
- for (const field of requestTokenFields) {
25268
- const candidate = value2[field];
25483
+ for (const field2 of requestTokenFields) {
25484
+ const candidate = value2[field2];
25269
25485
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
25270
- throw new Error(`Harness Usage request '${field}' must be a non-negative safe integer`);
25486
+ throw new Error(`Harness Usage request '${field2}' must be a non-negative safe integer`);
25271
25487
  }
25272
25488
  }
25273
25489
  if (value2.inputTokens === void 0 || value2.outputTokens === void 0) {
@@ -25376,7 +25592,7 @@ var packageMetadata = {
25376
25592
 
25377
25593
  // packages/mapping-store/dist/mapping-store.js
25378
25594
  import { execFileSync } from "node:child_process";
25379
- import { randomUUID as randomUUID8 } from "node:crypto";
25595
+ import { randomUUID as randomUUID9 } from "node:crypto";
25380
25596
  import { constants as constants3 } from "node:fs";
25381
25597
  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
25598
  import path18 from "node:path";
@@ -25436,7 +25652,7 @@ var storedThreadMetadataV1Schema = external_exports.object({
25436
25652
  formatVersion: external_exports.literal(1),
25437
25653
  hostThreadId: storedHostThreadIdSchema,
25438
25654
  ...storedThreadMetadataFieldsShape
25439
- }).strict();
25655
+ }).passthrough();
25440
25656
  function refineThreadRecord(record4, context) {
25441
25657
  if (record4.state === "ready" && !record4.nativeSessionRef) {
25442
25658
  context.addIssue({
@@ -25495,8 +25711,8 @@ function refineThreadRecord(record4, context) {
25495
25711
  }
25496
25712
  }
25497
25713
  }
25498
- var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).strict().superRefine(refineThreadRecord);
25499
- var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).strict().superRefine(refineThreadRecord);
25714
+ var storedThreadCoreV1Schema = external_exports.object(storedThreadCoreV1Shape).passthrough().superRefine(refineThreadRecord);
25715
+ var storedThreadRecordV1Schema = external_exports.object({ ...storedThreadCoreV1Shape, ...storedThreadMetadataFieldsShape }).passthrough().superRefine(refineThreadRecord);
25500
25716
  var delegationStatusSchema = external_exports.enum([
25501
25717
  "creating",
25502
25718
  "running",
@@ -25523,7 +25739,7 @@ var storedDelegationRecordV1Schema = external_exports.object({
25523
25739
  });
25524
25740
 
25525
25741
  // packages/mapping-store/dist/section-placements.js
25526
- import { randomUUID as randomUUID6 } from "node:crypto";
25742
+ import { randomUUID as randomUUID7 } from "node:crypto";
25527
25743
  import { constants } from "node:fs";
25528
25744
  import { open as open5, readFile as readFile13, rename as rename8, rm as rm8 } from "node:fs/promises";
25529
25745
  var threadIdSchema = external_exports.string().min(1).max(1024);
@@ -25575,7 +25791,7 @@ async function readSectionPlacementsFile(file2) {
25575
25791
  }
25576
25792
  async function writeSectionPlacementsFile(file2, placements) {
25577
25793
  const parsed2 = parseSectionPlacements({ formatVersion: 1, placements });
25578
- const temp = `${file2}.tmp-${randomUUID6()}`;
25794
+ const temp = `${file2}.tmp-${randomUUID7()}`;
25579
25795
  let handle = null;
25580
25796
  try {
25581
25797
  handle = await open5(temp, "wx", constants.S_IRUSR | constants.S_IWUSR);
@@ -25594,7 +25810,7 @@ async function writeSectionPlacementsFile(file2, placements) {
25594
25810
  }
25595
25811
 
25596
25812
  // packages/mapping-store/dist/superseded-sessions.js
25597
- import { randomUUID as randomUUID7 } from "node:crypto";
25813
+ import { randomUUID as randomUUID8 } from "node:crypto";
25598
25814
  import { constants as constants2 } from "node:fs";
25599
25815
  import { mkdir as mkdir10, open as open6, readFile as readFile14, rename as rename9, rm as rm9 } from "node:fs/promises";
25600
25816
  import path17 from "node:path";
@@ -25629,7 +25845,7 @@ async function writeSupersededSessionsFile(file2, sessions) {
25629
25845
  formatVersion: 1,
25630
25846
  sessions: sessions.slice(-SUPERSEDED_SESSIONS_MAX)
25631
25847
  }).sessions;
25632
- const temp = `${file2}.tmp-${randomUUID7()}`;
25848
+ const temp = `${file2}.tmp-${randomUUID8()}`;
25633
25849
  let handle = null;
25634
25850
  try {
25635
25851
  await mkdir10(path17.dirname(file2), { recursive: true });
@@ -25783,10 +25999,15 @@ function processIdentity(pid) {
25783
25999
  }
25784
26000
  const query = [
25785
26001
  "$ErrorActionPreference = 'Stop'",
25786
- `$process = Get-Process -Id ${pid}`,
25787
- "$process | Select-Object Path, StartTime | ConvertTo-Json -Compress"
26002
+ `$process = Get-CimInstance -ClassName Win32_Process -Filter 'ProcessId = ${pid}'`,
26003
+ "if ($null -ne $process) { [pscustomobject]@{ Path = $process.ExecutablePath; StartTime = $(if ($null -ne $process.CreationDate) { $process.CreationDate.ToUniversalTime().ToString('o', [Globalization.CultureInfo]::InvariantCulture) } else { $null }) } | ConvertTo-Json -Compress }"
25788
26004
  ].join("; ");
25789
- const result = execFileSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", query], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], windowsHide: true }).trim();
26005
+ const result = execFileSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", query], {
26006
+ encoding: "utf8",
26007
+ stdio: ["ignore", "pipe", "ignore"],
26008
+ windowsHide: true,
26009
+ timeout: 5e3
26010
+ }).trim();
25790
26011
  if (!result)
25791
26012
  return { executablePath: null, startedAt: null };
25792
26013
  const parsed2 = JSON.parse(result);
@@ -25874,7 +26095,7 @@ var MappingStore = class {
25874
26095
  this.#sectionsDirectory = path18.join(this.#directory, "sections");
25875
26096
  this.#metadataDirectory = path18.join(this.#directory, "thread-metadata");
25876
26097
  this.#lockPath = path18.join(this.#directory, "store.lock");
25877
- this.#instanceId = options2.instanceId ?? randomUUID8();
26098
+ this.#instanceId = options2.instanceId ?? randomUUID9();
25878
26099
  this.#now = options2.now ?? (() => /* @__PURE__ */ new Date());
25879
26100
  this.#beforeReplace = options2.beforeReplace;
25880
26101
  }
@@ -26398,7 +26619,7 @@ var MappingStore = class {
26398
26619
  this.#rebuildIndexes();
26399
26620
  }
26400
26621
  async #replaceFile(target, record4, preserveBackup) {
26401
- const temp = `${target}.tmp-${randomUUID8()}`;
26622
+ const temp = `${target}.tmp-${randomUUID9()}`;
26402
26623
  let handle = null;
26403
26624
  try {
26404
26625
  await this.#beforeReplace?.(cloneRecord(record4));
@@ -26422,18 +26643,20 @@ var MappingStore = class {
26422
26643
  });
26423
26644
  }
26424
26645
  }
26425
- /** Atomically writes, or with null removes, a Thread's Desktop metadata file. */
26646
+ /** Atomically patches owned metadata fields, retaining unknown fields on disk. */
26426
26647
  async #writeMetadataFile(hostThreadId, metadata) {
26427
26648
  const target = this.#metadataPath(hostThreadId);
26428
- const temp = `${target}.tmp-${randomUUID8()}`;
26649
+ const temp = `${target}.tmp-${randomUUID9()}`;
26429
26650
  let handle = null;
26430
26651
  try {
26431
- if (!metadata) {
26652
+ const retained = Object.fromEntries(Object.entries(await this.#readMetadata(hostThreadId) ?? {}).filter(([name]) => !["formatVersion", "hostThreadId", ...THREAD_METADATA_FIELDS].includes(name)));
26653
+ if (!metadata && Object.keys(retained).length === 0) {
26432
26654
  await rm10(target, { force: true });
26433
26655
  return;
26434
26656
  }
26657
+ const next = { ...retained, formatVersion: 1, hostThreadId, ...metadata };
26435
26658
  handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
26436
- await handle.writeFile(`${JSON.stringify(metadata, null, 2)}
26659
+ await handle.writeFile(`${JSON.stringify(next, null, 2)}
26437
26660
  `, "utf8");
26438
26661
  await handle.sync();
26439
26662
  await handle.close();
@@ -26470,7 +26693,7 @@ var MappingStore = class {
26470
26693
  }
26471
26694
  async #replaceDelegationFile(record4) {
26472
26695
  const target = this.#delegationPath(record4.delegationId);
26473
- const temp = `${target}.tmp-${randomUUID8()}`;
26696
+ const temp = `${target}.tmp-${randomUUID9()}`;
26474
26697
  let handle = null;
26475
26698
  try {
26476
26699
  handle = await open7(temp, "wx", constants3.S_IRUSR | constants3.S_IWUSR);
@@ -26655,17 +26878,17 @@ var ELLIPSIS = "…";
26655
26878
  function isRecord7(value2) {
26656
26879
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
26657
26880
  }
26658
- function boundedText(value2, field, maxLength) {
26881
+ function boundedText(value2, field2, maxLength) {
26659
26882
  const text = value2.trim();
26660
26883
  if (text.length === 0 || text.length > maxLength) {
26661
- throw new Error(`Host Approval ${field} must contain 1 to ${maxLength} characters`);
26884
+ throw new Error(`Host Approval ${field2} must contain 1 to ${maxLength} characters`);
26662
26885
  }
26663
26886
  return text;
26664
26887
  }
26665
- function clampedText(value2, field, maxLength) {
26888
+ function clampedText(value2, field2, maxLength) {
26666
26889
  const text = value2.trim();
26667
26890
  if (text.length === 0) {
26668
- throw new Error(`Host Approval ${field} must contain at least 1 character`);
26891
+ throw new Error(`Host Approval ${field2} must contain at least 1 character`);
26669
26892
  }
26670
26893
  const characters = [...text];
26671
26894
  if (characters.length <= maxLength)
@@ -27880,9 +28103,9 @@ function nestedString(value2, keys, preserveText = false) {
27880
28103
  if (!isRecord10(value2))
27881
28104
  return void 0;
27882
28105
  for (const key of keys) {
27883
- const field = value2[key];
27884
- if (typeof field === "string" && (preserveText || field.trim().length > 0))
27885
- return preserveText ? field : field.trim();
28106
+ const field2 = value2[key];
28107
+ if (typeof field2 === "string" && (preserveText || field2.trim().length > 0))
28108
+ return preserveText ? field2 : field2.trim();
27886
28109
  }
27887
28110
  for (const wrapper of ["input", "arguments", "params"]) {
27888
28111
  const nested = nestedString(value2[wrapper], keys, preserveText);
@@ -28155,8 +28378,18 @@ function collabAgentStatus(status2) {
28155
28378
  return "interrupted";
28156
28379
  }
28157
28380
  }
28381
+ function projectUserMessage(item, clientId) {
28382
+ return {
28383
+ id: item.itemId,
28384
+ type: "userMessage",
28385
+ clientId,
28386
+ content: item.input.map(({ text }) => ({ type: "text", text, text_elements: [] }))
28387
+ };
28388
+ }
28158
28389
  function projectItem(item, outcome, defaultCwd, includeCommandOutput = true, senderThreadId) {
28159
28390
  switch (item.type) {
28391
+ case "userMessage":
28392
+ return projectUserMessage(item, null);
28160
28393
  case "agentMessage":
28161
28394
  return {
28162
28395
  id: item.itemId,
@@ -28368,6 +28601,7 @@ var CodexTurnProjector = class {
28368
28601
  #interactions = /* @__PURE__ */ new Map();
28369
28602
  #items = /* @__PURE__ */ new Map();
28370
28603
  #wireItemOrder = [];
28604
+ #userMessageClientIds = /* @__PURE__ */ new Map();
28371
28605
  #startedAt;
28372
28606
  #startedAtMs;
28373
28607
  #threadId;
@@ -28409,6 +28643,10 @@ var CodexTurnProjector = class {
28409
28643
  }
28410
28644
  return items;
28411
28645
  }
28646
+ /** Associate steered input with the Desktop message that submitted it, before it is published. */
28647
+ bindUserMessageClientId(itemId, clientId) {
28648
+ this.#userMessageClientIds.set(itemId, clientId);
28649
+ }
28412
28650
  pendingTurn(startedAt = null) {
28413
28651
  return {
28414
28652
  id: this.#turnId,
@@ -28419,6 +28657,8 @@ var CodexTurnProjector = class {
28419
28657
  const projected = this.#items.get(itemId);
28420
28658
  if (!projected?.wireStarted)
28421
28659
  return [];
28660
+ if (projected.item.type === "userMessage")
28661
+ return [this.#projectItem(projected.item)];
28422
28662
  if (projected.item.type === "agentMessage") {
28423
28663
  return [projectItem(projected.item, projected.outcome, this.#cwd)];
28424
28664
  }
@@ -28746,7 +28986,7 @@ var CodexTurnProjector = class {
28746
28986
  return { messages: [] };
28747
28987
  }
28748
28988
  const messages = [
28749
- completedItem(projectItem(projected.item, projected.outcome, this.#cwd, !projected.streamedCommandOutput, this.#threadId))
28989
+ completedItem(this.#projectItem(projected.item, projected.outcome, !projected.streamedCommandOutput))
28750
28990
  ];
28751
28991
  if (projected.item.type === "reasoning") {
28752
28992
  const reasoning = projected.item;
@@ -28811,6 +29051,8 @@ var CodexTurnProjector = class {
28811
29051
  projectReasoningTranscriptItem(reasoning, projected.outcome, this.#cwd, projected.durationMs ?? null)
28812
29052
  ];
28813
29053
  }
29054
+ if (projected.item.type === "userMessage")
29055
+ return [this.#projectItem(projected.item)];
28814
29056
  if (projected.item.type === "agentMessage") {
28815
29057
  return [projectItem(projected.item, projected.outcome, this.#cwd)];
28816
29058
  }
@@ -28896,10 +29138,13 @@ var CodexTurnProjector = class {
28896
29138
  threadId: this.#threadId,
28897
29139
  turnId: this.#turnId,
28898
29140
  startedAtMs,
28899
- item: projectItem(item, null, this.#cwd, true, this.#threadId)
29141
+ item: this.#projectItem(item, null)
28900
29142
  }
28901
29143
  };
28902
29144
  }
29145
+ #projectItem(item, outcome = null, includeCommandOutput = true) {
29146
+ return item.type === "userMessage" ? projectUserMessage(item, this.#userMessageClientIds.get(item.itemId) ?? null) : projectItem(item, outcome, this.#cwd, includeCommandOutput, this.#threadId);
29147
+ }
28903
29148
  #startReasoningTranscript(item, startedAtMs) {
28904
29149
  return {
28905
29150
  method: "item/started",
@@ -30291,7 +30536,7 @@ var HarnessAccountInspectionCache = class {
30291
30536
  };
30292
30537
 
30293
30538
  // packages/host-runtime/src/app-server-host.ts
30294
- import { createHash as createHash9, randomUUID as randomUUID14 } from "node:crypto";
30539
+ import { createHash as createHash9, randomUUID as randomUUID16 } from "node:crypto";
30295
30540
  import os8 from "node:os";
30296
30541
  import path25 from "node:path";
30297
30542
 
@@ -30299,12 +30544,12 @@ import path25 from "node:path";
30299
30544
  import nodePath from "node:path";
30300
30545
 
30301
30546
  // packages/host-runtime/src/external-thread-repository.ts
30302
- import { randomUUID as randomUUID10 } from "node:crypto";
30547
+ import { randomUUID as randomUUID11 } from "node:crypto";
30303
30548
  import os7 from "node:os";
30304
30549
  import path22 from "node:path";
30305
30550
 
30306
30551
  // packages/host-runtime/src/external-subagent-threads.ts
30307
- import { createHash as createHash6, randomUUID as randomUUID9 } from "node:crypto";
30552
+ import { createHash as createHash6, randomUUID as randomUUID10 } from "node:crypto";
30308
30553
  function childCreateRequest(parent, nativeRef, id2) {
30309
30554
  const key = createHash6("sha256").update(JSON.stringify([parent.hostThreadId, parent.harnessId, nativeRef.nativeSessionId, id2])).digest("hex");
30310
30555
  return `subagent:${key}`;
@@ -30379,7 +30624,7 @@ function subagentMaterializer(store, parent, previousParent) {
30379
30624
  return rebind(existing, parent);
30380
30625
  }
30381
30626
  const provisional = existing ?? await store.createProvisional({
30382
- hostThreadId: hostThreadIdSchema.parse(randomUUID9()),
30627
+ hostThreadId: hostThreadIdSchema.parse(randomUUID10()),
30383
30628
  createRequestId,
30384
30629
  harnessId: parent.harnessId,
30385
30630
  cwd: parent.cwd,
@@ -30552,7 +30797,7 @@ var ExternalThreadRepository = class {
30552
30797
  throw new Error("Derived Snapshot identity does not belong to its Native Session");
30553
30798
  }
30554
30799
  return {
30555
- hostTurnId: hostTurnIdSchema.parse(randomUUID10()),
30800
+ hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
30556
30801
  nativeTurnRef: turn.nativeTurnRef,
30557
30802
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
30558
30803
  };
@@ -30675,14 +30920,14 @@ var ExternalThreadRepository = class {
30675
30920
  const aligned = snapshot2.turns.map((turn) => {
30676
30921
  const existing = mappingsByNative.get(nativeTurnKey2(turn.nativeTurnRef));
30677
30922
  const mapping = existing ?? {
30678
- hostTurnId: hostTurnIdSchema.parse(randomUUID10()),
30923
+ hostTurnId: hostTurnIdSchema.parse(randomUUID11()),
30679
30924
  nativeTurnRef: turn.nativeTurnRef,
30680
30925
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
30681
30926
  };
30682
30927
  return {
30683
30928
  snapshot: turn,
30684
30929
  mapping: {
30685
- ...mapping,
30930
+ hostTurnId: mapping.hostTurnId,
30686
30931
  nativeTurnRef: turn.nativeTurnRef,
30687
30932
  ...turn.checkpoint ? { nativeCheckpointRef: turn.checkpoint } : {}
30688
30933
  }
@@ -30702,8 +30947,8 @@ var ExternalThreadRepository = class {
30702
30947
  };
30703
30948
  function createExternalThreadRecordInput(input) {
30704
30949
  return {
30705
- hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID10()),
30706
- createRequestId: input.createRequestId ?? randomUUID10(),
30950
+ hostThreadId: input.hostThreadId ?? hostThreadIdSchema.parse(randomUUID11()),
30951
+ createRequestId: input.createRequestId ?? randomUUID11(),
30707
30952
  harnessId: input.harnessId,
30708
30953
  cwd: input.cwd,
30709
30954
  ...input.title ? { title: input.title } : {},
@@ -30821,6 +31066,15 @@ async function executeExternalThreadFork(input) {
30821
31066
  boundaryIndex = mappings.length - 1;
30822
31067
  }
30823
31068
  const boundary = mappings[boundaryIndex];
31069
+ if (boundary && source.steeredTurnIds.has(boundary.hostTurnId)) {
31070
+ return {
31071
+ ok: false,
31072
+ error: {
31073
+ code: -32080,
31074
+ message: "This Turn took steered input; reopen the Thread before forking from it"
31075
+ }
31076
+ };
31077
+ }
30824
31078
  if (boundaryIndex < 0 || !boundary?.nativeCheckpointRef) {
30825
31079
  return {
30826
31080
  ok: false,
@@ -30877,6 +31131,7 @@ async function executeExternalThreadFork(input) {
30877
31131
  return { ok: false, error: mapExternalThreadHarnessError(opened.error, "fork") };
30878
31132
  }
30879
31133
  const session = opened.value;
31134
+ await inheritSourceModel(source, session);
30880
31135
  const inheritedPermissionModeId = await inheritSourcePermissionMode(source, session);
30881
31136
  try {
30882
31137
  const derivedNativeRef = session.initialState.nativeRef;
@@ -30894,7 +31149,7 @@ async function executeExternalThreadFork(input) {
30894
31149
  source.harnessId,
30895
31150
  provisional.transportModelId
30896
31151
  );
30897
- if (effectiveModel && selection?.model && selection.model.id !== effectiveModel.id) {
31152
+ if (effectiveModel && selection && selection.model?.id !== effectiveModel.id) {
30898
31153
  const transportModelId = encodeExternalTransportSelection(source.harnessId, {
30899
31154
  ...selection,
30900
31155
  model: effectiveModel
@@ -30939,6 +31194,22 @@ async function executeExternalThreadFork(input) {
30939
31194
  };
30940
31195
  }
30941
31196
  }
31197
+ async function inheritSourceModel(source, session) {
31198
+ let persisted;
31199
+ try {
31200
+ persisted = decodeExternalTransportSelection(source.harnessId, source.transportModelId)?.model;
31201
+ } catch {
31202
+ persisted = void 0;
31203
+ }
31204
+ const sourceModel = source.stateObserver.state.effectiveModel ?? source.requestedModel ?? persisted;
31205
+ if (!sourceModel || !session.capabilities.configuration.selectModel || session.initialState.effectiveModel !== void 0) {
31206
+ return;
31207
+ }
31208
+ try {
31209
+ await session.execute({ type: "model.select", model: sourceModel });
31210
+ } catch {
31211
+ }
31212
+ }
30942
31213
  async function inheritSourcePermissionMode(source, session) {
30943
31214
  const sourceModeId = source.stateObserver.state.effectivePermissionModeId ?? source.requestedPermissionModeId;
30944
31215
  if (!sourceModeId) return void 0;
@@ -31227,6 +31498,22 @@ var SessionImportRequests = class {
31227
31498
  }
31228
31499
  };
31229
31500
 
31501
+ // packages/host-runtime/src/shared-question.ts
31502
+ function usesSharedQuestionCard(interaction) {
31503
+ return interaction.questions.some((question) => question.type === "choice" && question.multiple);
31504
+ }
31505
+ function sharedQuestion(interaction) {
31506
+ return threadQuestionSchema.parse(interaction);
31507
+ }
31508
+ function validateSharedQuestionResponse(interaction, response) {
31509
+ const error51 = validateHostQuestionResponse(interaction, response);
31510
+ if (error51) throw new Error(error51.message);
31511
+ for (const values of Object.values(response.answers)) {
31512
+ if (new Set(values).size !== values.length) throw new Error("Duplicate Question answers");
31513
+ if (values.some((value2) => !value2.trim())) throw new Error("Empty Question answer");
31514
+ }
31515
+ }
31516
+
31230
31517
  // packages/host-runtime/src/external-thread-history.ts
31231
31518
  var DEFAULT_PAGE_SIZE2 = 25;
31232
31519
  var MAX_PAGE_SIZE2 = 100;
@@ -31560,6 +31847,16 @@ async function executeExternalThreadRollback(input) {
31560
31847
  if (derived.running) {
31561
31848
  return { ok: false, error: { code: -32072, message: "External Thread has an active Turn" } };
31562
31849
  }
31850
+ const undone = derived.record.turnMappings.slice(-rollback.numTurns);
31851
+ if (undone.some((mapping) => derived.steeredTurnIds.has(mapping.hostTurnId))) {
31852
+ return {
31853
+ ok: false,
31854
+ error: {
31855
+ code: -32080,
31856
+ message: "A Turn here took steered input; reopen the Thread before undoing Turns"
31857
+ }
31858
+ };
31859
+ }
31563
31860
  const refreshError = await runtime.refresh(derived);
31564
31861
  if (refreshError) return { ok: false, error: refreshError };
31565
31862
  if (expectedLastTurnId !== void 0 && derived.record.turnMappings.at(-1)?.hostTurnId !== expectedLastTurnId) {
@@ -32174,7 +32471,7 @@ var UsageMeter = class {
32174
32471
  derive(native, prices) {
32175
32472
  const usage = Object.fromEntries(
32176
32473
  Object.entries(native ?? {}).filter(
32177
- ([field]) => !hostDerivedUsageFields.includes(field)
32474
+ ([field2]) => !hostDerivedUsageFields.includes(field2)
32178
32475
  )
32179
32476
  );
32180
32477
  const sessionCacheUsage = usage.sessionCacheUsage;
@@ -32359,6 +32656,7 @@ var ExternalThreadRuntime = class {
32359
32656
  #repository;
32360
32657
  #lifecycle = new ExternalThreadLifecycle();
32361
32658
  #hasRunningDescendants;
32659
+ #steeredTurnIds = /* @__PURE__ */ new Map();
32362
32660
  #subagentRunning;
32363
32661
  #threads = /* @__PURE__ */ new Map();
32364
32662
  constructor(input) {
@@ -32372,7 +32670,8 @@ var ExternalThreadRuntime = class {
32372
32670
  this.idleRelease = new ExternalThreadIdleRelease({
32373
32671
  threads: () => this.values(),
32374
32672
  get: (id2) => this.get(id2),
32375
- remove: (id2) => this.remove(id2),
32673
+ // Idle release detaches only the Native Session. Host Thread state survives restoration.
32674
+ remove: (id2) => this.#detach(id2),
32376
32675
  queue: input.idleRelease?.queue ?? new DesktopRequestQueue(),
32377
32676
  canRelease: (thread) => !thread.sessionUnavailable && !this.#lifecycle.busy(thread.id) && (input.idleRelease?.canRelease(thread) ?? false),
32378
32677
  ...input.idleRelease?.onClosed ? { onClosed: input.idleRelease.onClosed } : {},
@@ -32382,14 +32681,21 @@ var ExternalThreadRuntime = class {
32382
32681
  get(threadId2) {
32383
32682
  return this.#threads.get(threadId2);
32384
32683
  }
32684
+ #detach(threadId2) {
32685
+ const thread = this.#threads.get(threadId2);
32686
+ this.#threads.delete(threadId2);
32687
+ if (!thread || thread.steeredTurnIds.size === 0) this.#steeredTurnIds.delete(threadId2);
32688
+ }
32385
32689
  values() {
32386
32690
  return [...this.#threads.values()];
32387
32691
  }
32388
32692
  remove(threadId2) {
32389
32693
  this.#threads.delete(threadId2);
32694
+ this.#steeredTurnIds.delete(threadId2);
32390
32695
  }
32391
32696
  clear() {
32392
32697
  this.#threads.clear();
32698
+ this.#steeredTurnIds.clear();
32393
32699
  }
32394
32700
  drain() {
32395
32701
  return this.#lifecycle.drain();
@@ -32446,6 +32752,11 @@ var ExternalThreadRuntime = class {
32446
32752
  ...effectivePermissionModeId ? { effectivePermissionModeId } : {}
32447
32753
  };
32448
32754
  const running = this.#subagentRunning(input.record.hostThreadId);
32755
+ let steeredTurnIds = this.#steeredTurnIds.get(input.record.hostThreadId);
32756
+ if (!steeredTurnIds) {
32757
+ steeredTurnIds = /* @__PURE__ */ new Set();
32758
+ this.#steeredTurnIds.set(input.record.hostThreadId, steeredTurnIds);
32759
+ }
32449
32760
  const externalThread = {
32450
32761
  id: input.record.hostThreadId,
32451
32762
  cwd: input.record.cwd,
@@ -32470,11 +32781,13 @@ var ExternalThreadRuntime = class {
32470
32781
  usageTurnId: null,
32471
32782
  projectedTurns: /* @__PURE__ */ new Map(),
32472
32783
  responseGates: /* @__PURE__ */ new Map(),
32784
+ pendingSteerProjections: /* @__PURE__ */ new Set(),
32473
32785
  ephemeralTurnIds: /* @__PURE__ */ new Set(),
32474
32786
  persistenceError: null,
32475
32787
  projectedTerminalTurnId: null,
32476
32788
  ignoredInteractionIds: /* @__PURE__ */ new Set(),
32477
- sessionUnavailable: false
32789
+ sessionUnavailable: false,
32790
+ steeredTurnIds
32478
32791
  };
32479
32792
  this.idleRelease.touch(externalThread);
32480
32793
  externalThread.outputTask = this.#consumeOutputs(externalThread);
@@ -32531,13 +32844,13 @@ var ExternalThreadRuntime = class {
32531
32844
  const retire = async () => {
32532
32845
  if (this.#threads.get(parentId) !== parent || this.#threads.get(child.id) !== child) return;
32533
32846
  if (bestEffort) {
32534
- this.#threads.delete(child.id);
32847
+ this.remove(child.id);
32535
32848
  await child.session.close();
32536
32849
  await child.outputTask;
32537
32850
  } else {
32538
32851
  child.sessionUnavailable = true;
32539
32852
  await this.#lifecycle.release(child.id, child.session, child.outputTask);
32540
- if (this.#threads.get(child.id) === child) this.#threads.delete(child.id);
32853
+ if (this.#threads.get(child.id) === child) this.remove(child.id);
32541
32854
  }
32542
32855
  };
32543
32856
  if (bestEffort) await retire().catch(this.#diagnose);
@@ -32910,6 +33223,71 @@ var ExternalThreadRuntime = class {
32910
33223
  };
32911
33224
 
32912
33225
  // packages/host-runtime/src/external-turn-steering.ts
33226
+ import { randomUUID as randomUUID12 } from "node:crypto";
33227
+
33228
+ // packages/host-runtime/src/external-command-routing.ts
33229
+ var ExternalCommandError = class extends Error {
33230
+ constructor(code, message2) {
33231
+ super(message2);
33232
+ this.code = code;
33233
+ }
33234
+ code;
33235
+ };
33236
+ function isExternalCommandCandidate(text) {
33237
+ return /^\/[^\s/]+(?:\s|$)/u.test(text.trimStart());
33238
+ }
33239
+ async function inspectLiveCommandCatalog(commands, timeoutMs = 1e3) {
33240
+ let timeout;
33241
+ try {
33242
+ const result = await Promise.race([
33243
+ commands.list(),
33244
+ new Promise((resolve) => {
33245
+ timeout = setTimeout(() => resolve(null), timeoutMs);
33246
+ })
33247
+ ]);
33248
+ return result?.ok ? harnessCommandCatalogSchema.parse(result.value) : null;
33249
+ } catch {
33250
+ return null;
33251
+ } finally {
33252
+ if (timeout !== void 0) clearTimeout(timeout);
33253
+ }
33254
+ }
33255
+ async function resolveExternalCommand(commands, text, options2 = {}) {
33256
+ const catalog = await commands.list();
33257
+ if (!catalog.ok) throw new ExternalCommandError(-32073, catalog.error.message);
33258
+ const commandText = text.trim();
33259
+ const matched = catalog.value.commands.toSorted((left, right) => right.invocation.length - left.invocation.length).find((command) => {
33260
+ if (commandText === command.invocation) return true;
33261
+ return command.argumentMode === "text" && commandText.startsWith(`${command.invocation} `);
33262
+ });
33263
+ if (!matched) {
33264
+ const name = /^\/(\S+)/u.exec(commandText)?.[1] ?? "";
33265
+ if (name && !isExcludedLiveCommand(name, "command") && options2.liveCatalogPending?.(catalog.value)) {
33266
+ return null;
33267
+ }
33268
+ throw new ExternalCommandError(
33269
+ -32078,
33270
+ "External Harness does not expose the requested command"
33271
+ );
33272
+ }
33273
+ const argumentText = commandText.slice(matched.invocation.length).trimStart();
33274
+ return {
33275
+ descriptor: matched,
33276
+ ...argumentText.length > 0 ? { arguments: { text: argumentText } } : {}
33277
+ };
33278
+ }
33279
+
33280
+ // packages/host-runtime/src/external-turn-steering.ts
33281
+ function isHarnessCommand(thread, text) {
33282
+ return thread.session.commands !== void 0 && isExternalCommandCandidate(restoreHarnessCommandMentions(text));
33283
+ }
33284
+ function externalSteeringDelivery(thread, text) {
33285
+ if (text !== void 0 && isHarnessCommand(thread, text)) return "newTurn";
33286
+ if (thread.session.readCapabilities) {
33287
+ return thread.session.readCapabilities().then((capabilities) => capabilities.steer === true ? "activeTurn" : "newTurn");
33288
+ }
33289
+ return thread.session.capabilities.steer === true ? "activeTurn" : "newTurn";
33290
+ }
32913
33291
  var ExternalSteerError = class extends Error {
32914
33292
  constructor(code, message2) {
32915
33293
  super(message2);
@@ -32917,6 +33295,11 @@ var ExternalSteerError = class extends Error {
32917
33295
  }
32918
33296
  code;
32919
33297
  };
33298
+ var ExternalSteerNotTakenError = class extends ExternalSteerError {
33299
+ constructor(message2) {
33300
+ super(-32074, message2);
33301
+ }
33302
+ };
32920
33303
  function parseInput(params) {
32921
33304
  if (typeof params.expectedTurnId !== "string" || !params.expectedTurnId.trim()) {
32922
33305
  throw new ExternalSteerError(-32602, "External steering requires expectedTurnId");
@@ -32933,12 +33316,47 @@ function parseInput(params) {
32933
33316
  if (clientUserMessageId != null && (typeof clientUserMessageId !== "string" || !clientUserMessageId.trim())) {
32934
33317
  throw new ExternalSteerError(-32602, "External steering message identity is invalid");
32935
33318
  }
33319
+ const delivery = params[THREAD_STEER_DELIVERY_PARAM];
33320
+ const parsedDelivery = delivery == null ? void 0 : threadSteerDeliverySchema.safeParse(delivery);
33321
+ if (parsedDelivery && !parsedDelivery.success) {
33322
+ throw new ExternalSteerError(-32602, "External steering delivery is invalid");
33323
+ }
32936
33324
  return {
32937
33325
  expectedTurnId: params.expectedTurnId,
32938
33326
  text,
32939
- ...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {}
33327
+ ...typeof clientUserMessageId === "string" ? { clientUserMessageId } : {},
33328
+ ...parsedDelivery ? { delivery: parsedDelivery.data } : {}
32940
33329
  };
32941
33330
  }
33331
+ async function insertNativeSteer(thread, input, host) {
33332
+ const restored = restoreHarnessCommandMentions(input.text);
33333
+ const steered = [{ type: "text", text: rewriteDelegationMentionText(restored) }];
33334
+ const displayed = [{ type: "text", text: restored }];
33335
+ const projectionDone = Promise.withResolvers();
33336
+ thread.pendingSteerProjections.add(projectionDone.promise);
33337
+ try {
33338
+ const result = await thread.session.execute({
33339
+ type: "turn.steer",
33340
+ turnId: input.turnId,
33341
+ input: steered
33342
+ });
33343
+ if (!result.ok) throw new ExternalSteerNotTakenError(result.error.message);
33344
+ thread.steeredTurnIds.add(input.turnId);
33345
+ const item = {
33346
+ type: "userMessage",
33347
+ itemId: hostItemIdSchema.parse(randomUUID12()),
33348
+ input: displayed
33349
+ };
33350
+ try {
33351
+ await host.project(input.turnId, item, input.clientUserMessageId);
33352
+ } catch (error51) {
33353
+ host.diagnose(error51);
33354
+ }
33355
+ } finally {
33356
+ projectionDone.resolve(void 0);
33357
+ thread.pendingSteerProjections.delete(projectionDone.promise);
33358
+ }
33359
+ }
32942
33360
  var ExternalTurnSteering = class {
32943
33361
  constructor(timeoutMs = 2e4) {
32944
33362
  this.timeoutMs = timeoutMs;
@@ -32950,7 +33368,7 @@ var ExternalTurnSteering = class {
32950
33368
  hasPending(threadId2) {
32951
33369
  return threadId2 === void 0 ? this.#pending.size > 0 : this.#pending.has(threadId2);
32952
33370
  }
32953
- run(thread, params, start) {
33371
+ run(thread, params, start, insert) {
32954
33372
  try {
32955
33373
  const input = parseInput(params);
32956
33374
  if (this.#closed)
@@ -32972,7 +33390,7 @@ var ExternalTurnSteering = class {
32972
33390
  if (!thread.running || thread.activeTurnId !== input.expectedTurnId) {
32973
33391
  throw new ExternalSteerError(-32074, "External steering must reference the active Turn");
32974
33392
  }
32975
- const result = this.#replace(thread, input, start);
33393
+ const result = this.#deliver(thread, input, start, insert);
32976
33394
  if (key) {
32977
33395
  const receipt2 = { fingerprint, result, settled: false };
32978
33396
  this.#receipts.set(key, receipt2);
@@ -32995,6 +33413,56 @@ var ExternalTurnSteering = class {
32995
33413
  return Promise.reject(error51);
32996
33414
  }
32997
33415
  }
33416
+ /**
33417
+ * A Renderer that already presented a delivery gets exactly that one. Otherwise native delivery
33418
+ * is tried only when the Session can take the input now, and input the Harness did not take
33419
+ * falls back to stopping and restarting, so no case is worse than the stop-then-start path.
33420
+ */
33421
+ #deliver(thread, input, start, insert) {
33422
+ const delivery = input.delivery === "newTurn" || isHarnessCommand(thread, input.text) ? "newTurn" : input.delivery ?? externalSteeringDelivery(thread);
33423
+ const deliver = (mode) => {
33424
+ if (this.#closed || !thread.running || thread.activeTurnId !== input.expectedTurnId) {
33425
+ throw new ExternalSteerError(-32074, "External steering target is no longer active");
33426
+ }
33427
+ if (this.hasPending(thread.id))
33428
+ throw new ExternalSteerError(-32072, "External Thread is already changing direction");
33429
+ if (mode === "newTurn") return this.#replace(thread, input, start);
33430
+ const native = insert({
33431
+ turnId: thread.activeTurnId,
33432
+ text: input.text,
33433
+ ...input.clientUserMessageId ? { clientUserMessageId: input.clientUserMessageId } : {}
33434
+ }).then((admitted) => ({ ...admitted, delivery: "activeTurn" }));
33435
+ if (input.delivery === "activeTurn") return native;
33436
+ return native.catch(async (error51) => {
33437
+ if (!(error51 instanceof ExternalSteerNotTakenError)) throw error51;
33438
+ if (thread.running || thread.activeTurnId) return deliver("newTurn");
33439
+ const assertActive = () => {
33440
+ if (this.#closed)
33441
+ throw new ExternalSteerError(-32074, "External steering connection is closed");
33442
+ };
33443
+ return { ...await start(input.text, assertActive), delivery: "newTurn" };
33444
+ });
33445
+ };
33446
+ if (typeof delivery === "string") return deliver(delivery);
33447
+ const failure = Promise.withResolvers();
33448
+ let failureReason = null;
33449
+ const pending = {
33450
+ turnId: input.expectedTurnId,
33451
+ resolve: () => void 0,
33452
+ reject(error51) {
33453
+ failureReason ??= error51;
33454
+ failure.reject(error51);
33455
+ }
33456
+ };
33457
+ this.#pending.set(thread.id, pending);
33458
+ return Promise.race([delivery, failure.promise]).then((mode) => {
33459
+ if (failureReason) throw failureReason;
33460
+ if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
33461
+ return deliver(mode);
33462
+ }).finally(() => {
33463
+ if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
33464
+ });
33465
+ }
32998
33466
  terminal(threadId2, turnId, outcome) {
32999
33467
  const pending = this.#pending.get(threadId2);
33000
33468
  if (pending?.turnId === turnId) pending.resolve(outcome);
@@ -33049,7 +33517,9 @@ var ExternalTurnSteering = class {
33049
33517
  thread.session.execute({ type: "turn.cancel", turnId }),
33050
33518
  failure.promise
33051
33519
  ]);
33052
- if (!cancelled.ok) throw new ExternalSteerError(-32074, cancelled.error.message);
33520
+ if (!cancelled.ok && cancelled.error.code !== "invalidState") {
33521
+ throw new ExternalSteerError(-32074, cancelled.error.message);
33522
+ }
33053
33523
  const outcome = await Promise.race([terminal3.promise, failure.promise]);
33054
33524
  clearTimeout(timeout);
33055
33525
  const assertActive = () => {
@@ -33067,7 +33537,7 @@ var ExternalTurnSteering = class {
33067
33537
  if (thread.running || thread.activeTurnId) {
33068
33538
  throw new ExternalSteerError(-32072, "Another External Turn started before replacement");
33069
33539
  }
33070
- return await start(input.text, assertActive);
33540
+ return { ...await start(input.text, assertActive), delivery: "newTurn" };
33071
33541
  } finally {
33072
33542
  clearTimeout(timeout);
33073
33543
  if (this.#pending.get(thread.id) === pending) this.#pending.delete(thread.id);
@@ -33075,58 +33545,6 @@ var ExternalTurnSteering = class {
33075
33545
  }
33076
33546
  };
33077
33547
 
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
33548
  // packages/host-runtime/src/live-command-catalog-cache.ts
33131
33549
  import path23 from "node:path";
33132
33550
  var MAX_ENTRIES = 64;
@@ -33158,7 +33576,7 @@ function sameWorkspace(left, right) {
33158
33576
  }
33159
33577
 
33160
33578
  // packages/host-runtime/src/harness-delegation-coordinator.ts
33161
- import { createHash as createHash8, randomUUID as randomUUID11 } from "node:crypto";
33579
+ import { createHash as createHash8, randomUUID as randomUUID13 } from "node:crypto";
33162
33580
  import path24 from "node:path";
33163
33581
 
33164
33582
  // packages/host-runtime/src/delegation-snapshot.ts
@@ -33304,6 +33722,15 @@ function projectDelegationThreadSnapshot(input) {
33304
33722
  // packages/host-runtime/src/harness-delegation-coordinator.ts
33305
33723
  var IMPLICIT_DEDUPLICATION_MS = 3e4;
33306
33724
  var NATIVE_REF_TIMEOUT_MS = 1e4;
33725
+ function truncateTitle(value2, length) {
33726
+ return value2.slice(0, length).replace(/[\uD800-\uDBFF]$/u, "");
33727
+ }
33728
+ function delegationTitle(parentTitle, input) {
33729
+ const taskName = (input.taskName ?? input.task.trim().split(/\r?\n/u)[0] ?? input.task).replace(/\s+/gu, " ").trim();
33730
+ const subtask = truncateTitle(taskName, 120);
33731
+ const parent = (parentTitle?.trim() || "Untitled Thread").replace(/\s+/gu, " ");
33732
+ return `${subtask} · ${truncateTitle(parent, 200 - subtask.length - 3)}`;
33733
+ }
33307
33734
  function delay3(milliseconds) {
33308
33735
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
33309
33736
  }
@@ -33330,6 +33757,12 @@ function statusFromThread(thread, busy) {
33330
33757
  function validateStart(input) {
33331
33758
  if (typeof input.task !== "string" || !input.task.trim())
33332
33759
  throw new DelegationControlError("INVALID_ARGUMENT", "Task must not be empty");
33760
+ if (input.taskName !== void 0 && (typeof input.taskName !== "string" || !input.taskName.trim() || input.taskName.length > 120)) {
33761
+ throw new DelegationControlError(
33762
+ "INVALID_ARGUMENT",
33763
+ "Task name must contain 1 to 120 characters"
33764
+ );
33765
+ }
33333
33766
  if (input.cwd !== void 0 && (typeof input.cwd !== "string" || !input.cwd.trim()))
33334
33767
  throw new DelegationControlError("INVALID_ARGUMENT", "cwd must not be empty");
33335
33768
  if (input.requestId !== void 0 && (typeof input.requestId !== "string" || !input.requestId.trim())) {
@@ -33350,7 +33783,7 @@ var HarnessDelegationCoordinator = class {
33350
33783
  #cancelOfficial;
33351
33784
  #startOfficial;
33352
33785
  #listOfficial;
33353
- #officialThreadCwd;
33786
+ #officialThreadMetadata;
33354
33787
  #activeOfficialParents;
33355
33788
  #externalThreadBusy;
33356
33789
  constructor(input) {
@@ -33367,7 +33800,7 @@ var HarnessDelegationCoordinator = class {
33367
33800
  this.#cancelOfficial = input.cancelOfficial;
33368
33801
  this.#startOfficial = input.startOfficial;
33369
33802
  this.#listOfficial = input.listOfficial;
33370
- this.#officialThreadCwd = input.officialThreadCwd;
33803
+ this.#officialThreadMetadata = input.officialThreadMetadata;
33371
33804
  this.#activeOfficialParents = input.activeOfficialParents;
33372
33805
  this.#externalThreadBusy = input.externalThreadBusy;
33373
33806
  }
@@ -33397,8 +33830,14 @@ var HarnessDelegationCoordinator = class {
33397
33830
  const parentThreadId = await this.#resolveParent(input.parentThreadId);
33398
33831
  const parent = await this.#parentMetadata(parentThreadId);
33399
33832
  const selectedCwd = input.cwd ?? parent.cwd ?? process.cwd();
33833
+ const title = delegationTitle(parent.title, input);
33400
33834
  if (input.harnessId === "codex") {
33401
- const result = await this.#startOfficial({ ...input, parentThreadId, cwd: selectedCwd });
33835
+ const result = await this.#startOfficial({
33836
+ ...input,
33837
+ parentThreadId,
33838
+ cwd: selectedCwd,
33839
+ title
33840
+ });
33402
33841
  return { ...result, parentThreadId, cwd: result.cwd ?? selectedCwd };
33403
33842
  }
33404
33843
  const startInput = { ...input, parentThreadId, cwd: path24.resolve(selectedCwd) };
@@ -33441,17 +33880,17 @@ var HarnessDelegationCoordinator = class {
33441
33880
  });
33442
33881
  this.#validateConfiguration(inspected.inspection, input.model, input.thinkingOptionId);
33443
33882
  }
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();
33883
+ const delegationId = hostThreadIdSchema.parse(randomUUID13());
33884
+ const childThreadId = hostThreadIdSchema.parse(randomUUID13());
33885
+ const turnId = hostTurnIdSchema.parse(randomUUID13());
33886
+ const createRequestId = input.requestId ? `delegation:${input.requestId}` : randomUUID13();
33448
33887
  let record4 = await this.#repository.createProvisional(
33449
33888
  createExternalThreadRecordInput({
33450
33889
  hostThreadId: childThreadId,
33451
33890
  createRequestId,
33452
33891
  harnessId: harnessIdSchema.parse(targetHarnessId),
33453
33892
  cwd: startInput.cwd,
33454
- title: input.task.trim().slice(0, 120),
33893
+ title,
33455
33894
  transportModelId: input.model || input.thinkingOptionId ? encodeExternalTransportSelection(targetHarnessId, {
33456
33895
  ...input.model ? { model: input.model } : {},
33457
33896
  ...input.thinkingOptionId ? { thinkingOptionId: input.thinkingOptionId } : {}
@@ -33598,7 +34037,7 @@ var HarnessDelegationCoordinator = class {
33598
34037
  if (this.#externalThreadBusy(thread) || thread.activeTurnId) {
33599
34038
  throw new DelegationControlError("THREAD_BUSY", "Thread already has an active Turn");
33600
34039
  }
33601
- const turnId = hostTurnIdSchema.parse(randomUUID11());
34040
+ const turnId = hostTurnIdSchema.parse(randomUUID13());
33602
34041
  try {
33603
34042
  await this.#startExternalTurn(thread, input.message, turnId);
33604
34043
  } catch (error51) {
@@ -33724,10 +34163,10 @@ var HarnessDelegationCoordinator = class {
33724
34163
  }
33725
34164
  };
33726
34165
  });
33727
- const [field, direction] = input.sort.split("-");
34166
+ const [field2, direction] = input.sort.split("-");
33728
34167
  rows.sort((left, right) => {
33729
- const leftTimestamp = field === "created" ? left.createdAt : left.updatedAt;
33730
- const rightTimestamp = field === "created" ? right.createdAt : right.updatedAt;
34168
+ const leftTimestamp = field2 === "created" ? left.createdAt : left.updatedAt;
34169
+ const rightTimestamp = field2 === "created" ? right.createdAt : right.updatedAt;
33731
34170
  const leftTime = Date.parse(leftTimestamp ?? "");
33732
34171
  const rightTime = Date.parse(rightTimestamp ?? "");
33733
34172
  return direction === "asc" ? leftTime - rightTime : rightTime - leftTime;
@@ -33812,9 +34251,14 @@ var HarnessDelegationCoordinator = class {
33812
34251
  }
33813
34252
  async #parentMetadata(parentThreadId) {
33814
34253
  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 } : {} };
34254
+ if (record4)
34255
+ return {
34256
+ harnessId: record4.harnessId,
34257
+ cwd: record4.cwd,
34258
+ title: record4.title
34259
+ };
34260
+ const metadata = await this.#officialThreadMetadata(parentThreadId).catch(() => ({}));
34261
+ return { harnessId: "codex", ...metadata };
33818
34262
  }
33819
34263
  async #existingResult(delegation) {
33820
34264
  const record4 = await this.#repository.find(delegation.childHostThreadId);
@@ -36243,10 +36687,10 @@ var SingleNativeCodexAccount = class {
36243
36687
  };
36244
36688
 
36245
36689
  // packages/host-runtime/src/codex-runtime/official-runtime-owner.ts
36246
- import { randomUUID as randomUUID13 } from "node:crypto";
36690
+ import { randomUUID as randomUUID15 } from "node:crypto";
36247
36691
 
36248
36692
  // packages/host-runtime/src/official-request-broker.ts
36249
- import { randomUUID as randomUUID12 } from "node:crypto";
36693
+ import { randomUUID as randomUUID14 } from "node:crypto";
36250
36694
  var INTERNAL_REQUEST_PREFIX = "codexhost:official:";
36251
36695
  var MAX_RETIRED_IDS = 1024;
36252
36696
  function isRecord15(value2) {
@@ -36262,7 +36706,7 @@ var OfficialRequestBroker = class {
36262
36706
  constructor(input) {
36263
36707
  this.#send = input.send;
36264
36708
  this.#timeoutMs = input.timeoutMs ?? 3e4;
36265
- this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID12()}`);
36709
+ this.#nextId = input.nextId ?? (() => `${INTERNAL_REQUEST_PREFIX}${randomUUID14()}`);
36266
36710
  }
36267
36711
  get pendingCount() {
36268
36712
  return this.#pending.size;
@@ -36616,7 +37060,7 @@ var OfficialRuntimeOwner = class {
36616
37060
  }
36617
37061
  #attach(role, output, onBackendStopped) {
36618
37062
  const client = {
36619
- id: randomUUID13(),
37063
+ id: randomUUID15(),
36620
37064
  role,
36621
37065
  output,
36622
37066
  ...onBackendStopped ? { onBackendStopped } : {},
@@ -36774,7 +37218,7 @@ var OfficialRuntimeOwner = class {
36774
37218
  if (!object4(value2)) return client.output(event);
36775
37219
  if (typeof value2.id === "string" || typeof value2.id === "number") {
36776
37220
  if (typeof value2.method === "string") {
36777
- const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID13()}`;
37221
+ const id2 = `codexhost:server:${client.id}:${event.generation}:${randomUUID15()}`;
36778
37222
  client.serverRequests.set(id2, value2.id);
36779
37223
  const projected = { ...value2, id: id2 };
36780
37224
  return client.output({
@@ -36950,16 +37394,16 @@ var OfficialRuntimeScope = class {
36950
37394
  #scheduleRecovery() {
36951
37395
  if (!this.#recovery || this.#closed || this.#recoveryTimer || this.#starting) return;
36952
37396
  const { delaysMs } = this.#recovery;
36953
- const delay6 = delaysMs[Math.min(this.#recoveryAttempt, delaysMs.length - 1)] ?? 0;
37397
+ const delay7 = delaysMs[Math.min(this.#recoveryAttempt, delaysMs.length - 1)] ?? 0;
36954
37398
  this.#recoveryAttempt++;
36955
37399
  this.#diagnosticOutput.write(
36956
- `codexhost: official Codex is unavailable; restarting in ${String(delay6)}ms
37400
+ `codexhost: official Codex is unavailable; restarting in ${String(delay7)}ms
36957
37401
  `
36958
37402
  );
36959
37403
  const timer = setTimeout(() => {
36960
37404
  this.#recoveryTimer = void 0;
36961
37405
  this.start().catch(() => void 0);
36962
- }, delay6);
37406
+ }, delay7);
36963
37407
  timer.unref();
36964
37408
  this.#recoveryTimer = timer;
36965
37409
  }
@@ -37121,9 +37565,9 @@ var RequestRouteObservationTracker = class {
37121
37565
  };
37122
37566
 
37123
37567
  // packages/host-runtime/src/external-thread-list.ts
37124
- function unixTimestamp(value2, field) {
37568
+ function unixTimestamp(value2, field2) {
37125
37569
  const parsed2 = Date.parse(value2);
37126
- if (!Number.isFinite(parsed2)) throw new Error(`External Thread ${field} is invalid`);
37570
+ if (!Number.isFinite(parsed2)) throw new Error(`External Thread ${field2} is invalid`);
37127
37571
  return Math.floor(parsed2 / 1e3);
37128
37572
  }
37129
37573
  function threadId(thread) {
@@ -37133,11 +37577,11 @@ function threadId(thread) {
37133
37577
  return thread.id;
37134
37578
  }
37135
37579
  function threadListTimestamp(thread, sortKey) {
37136
- const field = sortKey === "created_at" ? thread.createdAt : sortKey === "updated_at" ? thread.updatedAt : thread.recencyAt ?? thread.updatedAt;
37137
- if (!Number.isSafeInteger(field)) {
37580
+ const field2 = sortKey === "created_at" ? thread.createdAt : sortKey === "updated_at" ? thread.updatedAt : thread.recencyAt ?? thread.updatedAt;
37581
+ if (!Number.isSafeInteger(field2)) {
37138
37582
  throw new Error(`Thread list row has no valid ${sortKey} timestamp`);
37139
37583
  }
37140
- return field;
37584
+ return field2;
37141
37585
  }
37142
37586
  function compareTimestamp(left, right, direction) {
37143
37587
  if (left === right) return 0;
@@ -38054,6 +38498,7 @@ var AppServerHost = class {
38054
38498
  #plugins;
38055
38499
  #launchSettings;
38056
38500
  #accountInspections = new HarnessAccountInspectionCache();
38501
+ #installationTasks = new HarnessInstallationTasks();
38057
38502
  #externalRuntime;
38058
38503
  #executionHosts = /* @__PURE__ */ new WeakMap();
38059
38504
  #externalPrewarms = new ExternalThreadPrewarms();
@@ -38084,7 +38529,7 @@ var AppServerHost = class {
38084
38529
  #sectionMoves = Promise.resolve();
38085
38530
  #writer;
38086
38531
  /** Console requests share Desktop handling; their replies return to the console. */
38087
- #consoleRequestPrefix = `codexhost-console:${randomUUID14()}:`;
38532
+ #consoleRequestPrefix = `codexhost-console:${randomUUID16()}:`;
38088
38533
  #consoleReplies = /* @__PURE__ */ new Map();
38089
38534
  #nextConsoleRequest = 0;
38090
38535
  #subagentThreadStatuses = /* @__PURE__ */ new Map();
@@ -38222,7 +38667,7 @@ var AppServerHost = class {
38222
38667
  cancelOfficial: (input) => this.#cancelOfficialDelegationThread(input),
38223
38668
  startOfficial: (input) => this.#startOfficialDelegation(input),
38224
38669
  listOfficial: (input) => this.#listDelegationThreads(input),
38225
- officialThreadCwd: (threadId2) => this.#readOfficialThreadCwd(threadId2),
38670
+ officialThreadMetadata: (threadId2) => this.#readOfficialThreadMetadata(threadId2),
38226
38671
  activeOfficialParents: () => [...this.#activeOfficialTurns.keys()],
38227
38672
  externalThreadBusy: (thread) => this.#externalThreadBusy(thread)
38228
38673
  });
@@ -38868,11 +39313,11 @@ var AppServerHost = class {
38868
39313
  this.#dispatchDesktopReply(request, () => this.#inspectHarness(request));
38869
39314
  return;
38870
39315
  }
38871
- if (request.method === HARNESS_INSTALLATION_METHOD) {
39316
+ if (request.method === HARNESS_INSTALLATION_METHOD || request.method === HARNESS_INSTALLATION_START_METHOD || request.method === HARNESS_INSTALLATION_STATUS_METHOD) {
38872
39317
  this.#dispatchDesktopReply(request, async () => {
38873
- await this.#waitForPlugins();
38874
39318
  try {
38875
- const result = await handleHarnessInstallation(request.params, this.#externalAdapters);
39319
+ if (request.method !== HARNESS_INSTALLATION_STATUS_METHOD) await this.#waitForPlugins();
39320
+ 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
39321
  await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
38877
39322
  } catch (error51) {
38878
39323
  await this.#writer.json(
@@ -38957,6 +39402,19 @@ var AppServerHost = class {
38957
39402
  await this.#listThreadOwnership(request);
38958
39403
  return;
38959
39404
  }
39405
+ if (request.method === THREAD_QUESTIONS_LIST_METHOD || request.method === THREAD_QUESTION_RESPOND_METHOD) {
39406
+ const threadId2 = requestObject(request).threadId;
39407
+ this.#dispatchDesktopReply(
39408
+ request,
39409
+ () => this.#handleSharedQuestionRequest(request),
39410
+ request.method === THREAD_QUESTION_RESPOND_METHOD && typeof threadId2 === "string" ? threadId2 : void 0
39411
+ );
39412
+ return;
39413
+ }
39414
+ if (request.method === "codexhost/thread/steering/inspect") {
39415
+ await this.#inspectThreadSteering(request);
39416
+ return;
39417
+ }
38960
39418
  if (request.method === "codexhost/thread/model/select") {
38961
39419
  await this.#selectThreadModel(request);
38962
39420
  return;
@@ -39534,12 +39992,17 @@ var AppServerHost = class {
39534
39992
  ]);
39535
39993
  return thread !== null || childDelegation !== null || delegation !== null;
39536
39994
  }
39537
- async #readOfficialThreadCwd(threadId2) {
39538
- const response = await this.#requestOfficial("thread/read", { threadId: threadId2 });
39539
- if (isRecord18(response.error)) return void 0;
39995
+ async #readOfficialThreadMetadata(threadId2) {
39996
+ const response = await this.#requestOfficial("thread/read", { threadId: threadId2, includeTurns: false });
39997
+ if (isRecord18(response.error)) return {};
39540
39998
  const result = isRecord18(response.result) ? response.result : null;
39541
39999
  const thread = result && isRecord18(result.thread) ? result.thread : null;
39542
- return thread && typeof thread.cwd === "string" && thread.cwd.trim() ? thread.cwd : void 0;
40000
+ if (!thread) return {};
40001
+ const title = typeof thread.name === "string" && thread.name.trim() ? thread.name : thread.preview;
40002
+ return {
40003
+ ...typeof thread.cwd === "string" && thread.cwd.trim() ? { cwd: thread.cwd } : {},
40004
+ ...typeof title === "string" && title.trim() ? { title } : {}
40005
+ };
39543
40006
  }
39544
40007
  async #inspectOfficialDelegationTarget(input) {
39545
40008
  const response = await this.#requestOfficial("model/list", {});
@@ -39692,6 +40155,9 @@ var AppServerHost = class {
39692
40155
  this.#pendingOfficialDelegationThreads.add(threadId2);
39693
40156
  let turnId;
39694
40157
  try {
40158
+ await this.#requestOfficial("thread/name/set", { threadId: threadId2, name: input.title }).catch(
40159
+ () => void 0
40160
+ );
39695
40161
  const turn = await this.#requestOfficial("turn/start", {
39696
40162
  threadId: threadId2,
39697
40163
  input: [{ type: "text", text: input.task }],
@@ -39710,7 +40176,7 @@ var AppServerHost = class {
39710
40176
  throw error51;
39711
40177
  }
39712
40178
  this.#activeOfficialTurns.set(threadId2, turnId);
39713
- const delegationId = hostThreadIdSchema.parse(randomUUID14());
40179
+ const delegationId = hostThreadIdSchema.parse(randomUUID16());
39714
40180
  try {
39715
40181
  const source = await this.#repository.find(input.parentThreadId);
39716
40182
  const pendingTerminal = this.#pendingOfficialTerminalStatuses.get(threadId2);
@@ -39898,7 +40364,7 @@ var AppServerHost = class {
39898
40364
  async #listDelegationThreads(input) {
39899
40365
  const [sortKey, sortDirection2] = input.sort.split("-");
39900
40366
  const request = {
39901
- id: `codexhost:delegation-list:${randomUUID14()}`,
40367
+ id: `codexhost:delegation-list:${randomUUID16()}`,
39902
40368
  method: "thread/list",
39903
40369
  params: {
39904
40370
  cwd: input.cwd ? [input.cwd] : null,
@@ -40247,7 +40713,8 @@ var AppServerHost = class {
40247
40713
  try {
40248
40714
  inspection = await adapter.inspect({
40249
40715
  ...params.data.cwd ? { cwd: params.data.cwd } : {},
40250
- ...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {}
40716
+ ...params.data.refresh !== void 0 ? { refresh: params.data.refresh } : {},
40717
+ ...params.data.purpose ? { purpose: params.data.purpose } : {}
40251
40718
  });
40252
40719
  } catch (error51) {
40253
40720
  await this.#writer.json(
@@ -40440,6 +40907,28 @@ var AppServerHost = class {
40440
40907
  );
40441
40908
  }
40442
40909
  }
40910
+ /** Read the same delivery decision that Desktop `turn/steer` will follow. */
40911
+ async #inspectThreadSteering(request) {
40912
+ const params = threadSteeringInspectParamsSchema.safeParse(request.params);
40913
+ if (!params.success) {
40914
+ await this.#writer.json(rpcError(request, -32602, "Invalid Thread steering params"));
40915
+ return;
40916
+ }
40917
+ let delivery;
40918
+ try {
40919
+ const location = await this.#locateExternalThread(params.data.threadId);
40920
+ if (await this.#writeResolutionError(request, location)) return;
40921
+ const thread = location.kind === "external" ? this.#externalRuntime.get(params.data.threadId) : void 0;
40922
+ delivery = location.kind !== "external" ? "official" : thread ? await externalSteeringDelivery(thread, params.data.text) : "newTurn";
40923
+ } catch {
40924
+ await this.#writer.json(
40925
+ rpcError(request, -32081, "Thread steering metadata could not be read")
40926
+ );
40927
+ return;
40928
+ }
40929
+ const result = threadSteeringInspectResultSchema.parse({ delivery });
40930
+ await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(result) }));
40931
+ }
40443
40932
  async #inspectThreadCommands(request) {
40444
40933
  const params = threadCommandsInspectParamsSchema.safeParse(request.params);
40445
40934
  if (!params.success) {
@@ -40603,7 +41092,7 @@ var AppServerHost = class {
40603
41092
  if (thread.running || thread.activeTurnId) {
40604
41093
  throw new ExternalCommandError(-32072, "External Thread already has an active operation");
40605
41094
  }
40606
- const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID14());
41095
+ const turnId = requestedTurnId ?? hostTurnIdSchema.parse(randomUUID16());
40607
41096
  const projection = {
40608
41097
  projector: new CodexTurnProjector({
40609
41098
  threadId: thread.id,
@@ -40691,6 +41180,26 @@ var AppServerHost = class {
40691
41180
  if (!projected.effectiveModel) {
40692
41181
  throw new Error("Harness Session did not report an effective Model");
40693
41182
  }
41183
+ const transportModelId = encodeExternalTransportSelection(thread.harnessId, {
41184
+ ...decodeExternalTransportSelection(thread.harnessId, thread.transportModelId) ?? {},
41185
+ model: projected.effectiveModel
41186
+ });
41187
+ thread.transportModelId = transportModelId;
41188
+ thread.requestedModel = projected.effectiveModel;
41189
+ try {
41190
+ thread.record = await this.#repository.setTransportModelId(
41191
+ thread.record.hostThreadId,
41192
+ transportModelId
41193
+ );
41194
+ } catch (error51) {
41195
+ this.#diagnose(error51);
41196
+ }
41197
+ thread.thread = externalThreadValue({
41198
+ record: { ...thread.record, transportModelId },
41199
+ turns: thread.turns,
41200
+ sessionId: thread.sessionId,
41201
+ running: thread.running
41202
+ });
40694
41203
  await this.#writer.json(rpcEnvelope(request, { result: jsonValueSchema.parse(projected) }));
40695
41204
  } catch (error51) {
40696
41205
  await this.#writer.json(
@@ -41020,9 +41529,20 @@ var AppServerHost = class {
41020
41529
  await this.#writer.json(rpcError(request, resolution.error.code, resolution.error.message));
41021
41530
  return true;
41022
41531
  }
41532
+ /** Refresh history before Desktop acts on native Turn boundaries. */
41023
41533
  #refreshExternalThread(thread) {
41024
41534
  return this.#externalRuntime.refresh(thread);
41025
41535
  }
41536
+ #markExternalHistoryRead(thread, turns) {
41537
+ if (!thread.historyHydrated) return;
41538
+ for (const turnId of thread.steeredTurnIds) {
41539
+ if (turnId !== thread.activeTurnId && turns.some(
41540
+ (turn) => turn.id === turnId && (turn.status === "completed" || turn.status === "failed" || turn.status === "interrupted")
41541
+ )) {
41542
+ thread.steeredTurnIds.delete(turnId);
41543
+ }
41544
+ }
41545
+ }
41026
41546
  #persistTerminalIdentity(thread, event) {
41027
41547
  return this.#externalRuntime.persistTerminalIdentity(thread, event);
41028
41548
  }
@@ -41224,17 +41744,19 @@ var AppServerHost = class {
41224
41744
  return;
41225
41745
  }
41226
41746
  }
41747
+ const readTurns = includeTurns ? [...this.#externalHistoryTurns(thread)] : [];
41227
41748
  await this.#writer.json(
41228
41749
  rpcEnvelope(request, {
41229
41750
  result: {
41230
41751
  thread: {
41231
41752
  ...thread.thread,
41232
41753
  ...await this.#externalSectionFields(thread.record.hostThreadId),
41233
- turns: includeTurns ? this.#externalHistoryTurns(thread) : []
41754
+ turns: readTurns
41234
41755
  }
41235
41756
  }
41236
41757
  })
41237
41758
  );
41759
+ if (includeTurns) this.#markExternalHistoryRead(thread, readTurns);
41238
41760
  await this.#replayExternalUsage(thread);
41239
41761
  }
41240
41762
  async #listExternalHistory(request, thread, params, historyFresh) {
@@ -41251,6 +41773,9 @@ var AppServerHost = class {
41251
41773
  const turns = this.#externalHistoryTurns(thread);
41252
41774
  const result = request.method === "thread/turns/list" ? listExternalTurns(turns, params) : listExternalItems(turns, params);
41253
41775
  await this.#writer.json(rpcEnvelope(request, { result }));
41776
+ if (request.method === "thread/turns/list") {
41777
+ this.#markExternalHistoryRead(thread, result.data);
41778
+ }
41254
41779
  } catch (error51) {
41255
41780
  await this.#writer.json(
41256
41781
  rpcError(
@@ -41269,7 +41794,7 @@ var AppServerHost = class {
41269
41794
  return;
41270
41795
  }
41271
41796
  }
41272
- const turns = this.#externalHistoryTurns(thread);
41797
+ const turns = [...this.#externalHistoryTurns(thread)];
41273
41798
  const responseThread = {
41274
41799
  ...await this.#withExternalSection(thread.thread),
41275
41800
  turns: params.excludeTurns === true ? [] : turns
@@ -41301,6 +41826,8 @@ var AppServerHost = class {
41301
41826
  }
41302
41827
  })
41303
41828
  );
41829
+ if (params.excludeTurns !== true) this.#markExternalHistoryRead(thread, turns);
41830
+ else if (initialTurnsPage) this.#markExternalHistoryRead(thread, initialTurnsPage.data);
41304
41831
  } catch (error51) {
41305
41832
  await this.#writer.json(
41306
41833
  rpcError(
@@ -41443,10 +41970,15 @@ var AppServerHost = class {
41443
41970
  assertActive,
41444
41971
  typeof requestObject(request).clientUserMessageId === "string" ? requestObject(request).clientUserMessageId : void 0,
41445
41972
  requestObject(request)[THREAD_REFERENCE_SOURCE_HOST_PARAM]
41446
- )
41973
+ ),
41974
+ (input) => this.#insertExternalInput(thread, input)
41447
41975
  );
41448
41976
  try {
41449
- await this.#writer.json(rpcEnvelope(request, { result: { turnId: started.turnId } }));
41977
+ await this.#writer.json(
41978
+ rpcEnvelope(request, {
41979
+ result: { turnId: started.turnId, delivery: started.delivery }
41980
+ })
41981
+ );
41450
41982
  } finally {
41451
41983
  started.gate.resolve();
41452
41984
  }
@@ -41462,6 +41994,34 @@ var AppServerHost = class {
41462
41994
  this.#signalActiveWorkChanged();
41463
41995
  }
41464
41996
  }
41997
+ /** Native same-Turn input; `insertNativeSteer` owns the delivery and its fallback signal. */
41998
+ async #insertExternalInput(thread, input) {
41999
+ await insertNativeSteer(thread, input, {
42000
+ project: async (turnId, item, clientUserMessageId) => {
42001
+ const projection = this.#projectedTurn(thread, turnId);
42002
+ if (clientUserMessageId) {
42003
+ projection.projector.bindUserMessageClientId(item.itemId, clientUserMessageId);
42004
+ }
42005
+ await this.#projectHarnessOutput(thread, {
42006
+ kind: "event",
42007
+ event: { type: "item.started", turnId, item }
42008
+ });
42009
+ await this.#projectHarnessOutput(thread, {
42010
+ kind: "event",
42011
+ event: {
42012
+ type: "item.completed",
42013
+ turnId,
42014
+ snapshot: { item, outcome: { status: "succeeded" } }
42015
+ }
42016
+ });
42017
+ },
42018
+ diagnose: (error51) => this.#diagnose(error51)
42019
+ });
42020
+ return {
42021
+ turnId: input.turnId,
42022
+ gate: { promise: Promise.resolve(), resolve: () => void 0 }
42023
+ };
42024
+ }
41465
42025
  /** Keep command restoration and dispatch identical for start and steer submissions. */
41466
42026
  async #beginExternalInputTurn(thread, inputText, assertActive, clientUserMessageId, sourceHostId) {
41467
42027
  const text = restoreHarnessCommandMentions(inputText);
@@ -41519,7 +42079,7 @@ var AppServerHost = class {
41519
42079
  if (thread.running || thread.activeTurnId || this.#pendingExternalCommandRequests.has(thread.id)) {
41520
42080
  throw new ExternalSteerError(-32072, "External Thread already has an active Turn");
41521
42081
  }
41522
- const turnId = hostTurnIdSchema.parse(randomUUID14());
42082
+ const turnId = hostTurnIdSchema.parse(randomUUID16());
41523
42083
  const startedAtMs = Date.now();
41524
42084
  const projection = {
41525
42085
  projector: new CodexTurnProjector({
@@ -41779,6 +42339,10 @@ var AppServerHost = class {
41779
42339
  return;
41780
42340
  }
41781
42341
  if (event.type === "session.faulted") {
42342
+ for (const pending of [...this.#pendingDesktopQuestions.values()]) {
42343
+ if (pending.shared && pending.thread === thread)
42344
+ this.#retireDesktopQuestion(pending.interaction.interactionId);
42345
+ }
41782
42346
  this.#externalSteering.fault(thread.id, new Error(event.error.message));
41783
42347
  thread.stateObserver.fault(new Error(event.error.message));
41784
42348
  this.#externalRuntime.markSessionUnavailable(thread);
@@ -41814,11 +42378,20 @@ var AppServerHost = class {
41814
42378
  }
41815
42379
  return;
41816
42380
  }
42381
+ if (event.type === "turn.completed" && thread.pendingSteerProjections.size > 0) {
42382
+ await Promise.allSettled([...thread.pendingSteerProjections]);
42383
+ }
41817
42384
  const projection = this.#projectedTurn(thread, event.turnId);
41818
42385
  await this.#waitForTurnResponse(thread, event.turnId);
41819
42386
  if (event.type === "interaction.closed" && thread.ignoredInteractionIds.delete(event.interactionId)) {
41820
42387
  return;
41821
42388
  }
42389
+ if (event.type === "turn.completed") {
42390
+ for (const pending of [...this.#pendingDesktopQuestions.values()]) {
42391
+ if (pending.shared && pending.thread === thread && pending.interaction.turnId === event.turnId)
42392
+ this.#retireDesktopQuestion(pending.interaction.interactionId);
42393
+ }
42394
+ }
41822
42395
  if (event.type === "interaction.closed") {
41823
42396
  await this.#resolveDesktopApproval(event.interactionId);
41824
42397
  await this.#resolveDesktopQuestion(event.interactionId);
@@ -41863,6 +42436,7 @@ var AppServerHost = class {
41863
42436
  thread.activeTurnId = null;
41864
42437
  if (!projection.projector.hasOpenDetachedItems) thread.projectedTurns.delete(event.turnId);
41865
42438
  thread.responseGates.delete(event.turnId);
42439
+ thread.pendingSteerProjections.clear();
41866
42440
  this.#signalActiveWorkChanged();
41867
42441
  const delegation = await this.#repository.getDelegationByChild(thread.record.hostThreadId);
41868
42442
  if (delegation) {
@@ -42146,14 +42720,75 @@ var AppServerHost = class {
42146
42720
  this.#nextApprovalRequestId -= 1;
42147
42721
  return requestId;
42148
42722
  }
42723
+ async #handleSharedQuestionRequest(request) {
42724
+ const responding = request.method === THREAD_QUESTION_RESPOND_METHOD;
42725
+ const parsed2 = (responding ? threadQuestionRespondParamsSchema : threadQuestionsListParamsSchema).safeParse(request.params);
42726
+ if (!parsed2.success) {
42727
+ await this.#writer.json(rpcError(request, -32602, "Invalid Question params"));
42728
+ return;
42729
+ }
42730
+ const { threadId: threadId2 } = parsed2.data;
42731
+ const thread = this.#externalRuntime.get(threadId2);
42732
+ const pendingQuestions = () => [...this.#pendingDesktopQuestions.values()].filter(
42733
+ (pending) => pending.shared && pending.thread === thread && pending.interaction.turnId === thread?.activeTurnId && (!Number.isFinite(Date.parse(pending.interaction.expiresAt ?? "")) || Date.parse(pending.interaction.expiresAt ?? "") > Date.now())
42734
+ );
42735
+ if (!responding) {
42736
+ const questions = thread && !thread.sessionUnavailable && !this.#externalRuntime.idleRelease.failure(thread) ? pendingQuestions().map((pending) => sharedQuestion(pending.interaction)) : [];
42737
+ await this.#writer.json(
42738
+ rpcEnvelope(request, { result: jsonValueSchema.parse({ questions }) })
42739
+ );
42740
+ return;
42741
+ }
42742
+ const params = threadQuestionRespondParamsSchema.parse(parsed2.data);
42743
+ try {
42744
+ await this.#externalRuntime.idleRelease.runOperation(threadId2, async () => {
42745
+ const pending = pendingQuestions().find(
42746
+ ({ interaction }) => interaction.interactionId === params.interactionId && interaction.turnId === params.turnId
42747
+ );
42748
+ if (!thread || this.#externalRuntime.get(threadId2) !== thread || thread.sessionUnavailable || this.#externalRuntime.idleRelease.failure(thread) || !pending || pending.responding) {
42749
+ throw new Error("Question is no longer pending on this Thread and Turn");
42750
+ }
42751
+ const response = {
42752
+ type: "question",
42753
+ answers: params.answers,
42754
+ cancelled: params.cancelled
42755
+ };
42756
+ validateSharedQuestionResponse(pending.interaction, response);
42757
+ pending.responding = true;
42758
+ let result;
42759
+ try {
42760
+ result = await thread.session.execute({
42761
+ type: "interaction.respond",
42762
+ interactionId: pending.interaction.interactionId,
42763
+ response
42764
+ });
42765
+ } catch (error51) {
42766
+ this.#retireDesktopQuestion(pending.interaction.interactionId);
42767
+ throw error51;
42768
+ }
42769
+ if (!result.ok) {
42770
+ pending.responding = false;
42771
+ if (result.error.code === "invalidState")
42772
+ this.#retireDesktopQuestion(pending.interaction.interactionId);
42773
+ throw new Error(result.error.message);
42774
+ }
42775
+ this.#retireDesktopQuestion(pending.interaction.interactionId);
42776
+ await this.#writer.json(rpcEnvelope(request, { result: { accepted: true } }));
42777
+ });
42778
+ } catch (error51) {
42779
+ await this.#writer.json(rpcError(request, -32602, errorMessage4(error51)));
42780
+ }
42781
+ }
42149
42782
  async #projectQuestion(thread, interaction) {
42150
42783
  const projection = this.#projectedTurn(thread, interaction.turnId);
42151
42784
  await this.#waitForTurnResponse(thread, interaction.turnId);
42152
42785
  let result;
42786
+ const shared = usesSharedQuestionCard(interaction);
42153
42787
  try {
42788
+ if (shared) sharedQuestion(interaction);
42154
42789
  result = projection.projector.projectQuestion(
42155
42790
  interaction,
42156
- hostItemIdSchema.parse(randomUUID14())
42791
+ hostItemIdSchema.parse(randomUUID16())
42157
42792
  );
42158
42793
  } catch (error51) {
42159
42794
  this.#diagnose(error51);
@@ -42174,6 +42809,8 @@ var AppServerHost = class {
42174
42809
  const expiresAtMs = interaction.expiresAt ? Date.parse(interaction.expiresAt) : Number.NaN;
42175
42810
  const timeoutMs = Number.isFinite(expiresAtMs) ? Math.max(0, expiresAtMs - Date.now()) : null;
42176
42811
  const pending = {
42812
+ shared,
42813
+ responding: false,
42177
42814
  thread,
42178
42815
  interaction,
42179
42816
  projection: result.questionRequest,
@@ -42185,6 +42822,7 @@ var AppServerHost = class {
42185
42822
  }, timeoutMs);
42186
42823
  }
42187
42824
  this.#pendingDesktopQuestions.set(requestId, pending);
42825
+ if (shared) return;
42188
42826
  try {
42189
42827
  await this.#writer.json({ id: requestId, ...result.questionRequest.request });
42190
42828
  } catch (error51) {
@@ -42201,7 +42839,7 @@ var AppServerHost = class {
42201
42839
  if (!isRecord18(value2) || !isHostQuestionRequestId(value2.id)) return false;
42202
42840
  const requestId = value2.id;
42203
42841
  const pending = this.#pendingDesktopQuestions.get(requestId);
42204
- if (!pending) return true;
42842
+ if (!pending || pending.shared) return true;
42205
42843
  return this.#externalRuntime.idleRelease.runOperation(pending.thread.id, async () => {
42206
42844
  if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
42207
42845
  return true;
@@ -42234,6 +42872,7 @@ var AppServerHost = class {
42234
42872
  if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
42235
42873
  return;
42236
42874
  await this.#resolveDesktopQuestion(pending.interaction.interactionId);
42875
+ if (pending.responding) return;
42237
42876
  const result = await pending.thread.session.execute({
42238
42877
  type: "interaction.respond",
42239
42878
  interactionId: pending.interaction.interactionId,
@@ -42256,6 +42895,7 @@ var AppServerHost = class {
42256
42895
  if (pending.interaction.interactionId !== interactionId) continue;
42257
42896
  if (pending.timeout) clearTimeout(pending.timeout);
42258
42897
  this.#pendingDesktopQuestions.delete(requestId);
42898
+ if (pending.shared) continue;
42259
42899
  await this.#writer.json({
42260
42900
  method: "serverRequest/resolved",
42261
42901
  params: { threadId: pending.thread.id, requestId }
@@ -42392,7 +43032,7 @@ var import_websocket_server = __toESM(require_websocket_server(), 1);
42392
43032
  var wrapper_default = import_websocket.default;
42393
43033
 
42394
43034
  // packages/host-runtime/src/remote-socket-lock.ts
42395
- import { randomUUID as randomUUID15 } from "node:crypto";
43035
+ import { randomUUID as randomUUID17 } from "node:crypto";
42396
43036
  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
43037
  import { uptime } from "node:os";
42398
43038
  import path26 from "node:path";
@@ -42518,7 +43158,7 @@ async function preparePrivateLockDirectory(lockDirectory) {
42518
43158
  await chmod3(lockDirectory, 448);
42519
43159
  }
42520
43160
  async function writeLockRecordAtomic(lockDirectory, entryPath, record4) {
42521
- const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${randomUUID15()}`);
43161
+ const temporary = path26.join(lockDirectory, `.tmp-${record4.ownerToken}-${randomUUID17()}`);
42522
43162
  const handle = await open9(temporary, "wx", 384);
42523
43163
  try {
42524
43164
  await handle.writeFile(`${JSON.stringify(record4)}
@@ -42593,7 +43233,7 @@ async function withRemoteAppServerSocketInitializationLock(socketPath, action) {
42593
43233
  const legacyPath = `${socketPath}.initializing`;
42594
43234
  const lockDirectory = `${socketPath}.initializers`;
42595
43235
  await preparePrivateLockDirectory(lockDirectory);
42596
- const ownerToken = randomUUID15();
43236
+ const ownerToken = randomUUID17();
42597
43237
  const entryPath = path26.join(lockDirectory, lockEntryName(ownerToken));
42598
43238
  const baseRecord = {
42599
43239
  version: 2,
@@ -43104,12 +43744,12 @@ function createRemoteAppServerWebSocketListener(input) {
43104
43744
 
43105
43745
  // packages/host-runtime/src/remote-official-app-server.ts
43106
43746
  import { spawn as spawn5 } from "node:child_process";
43107
- import { randomUUID as randomUUID16 } from "node:crypto";
43747
+ import { randomUUID as randomUUID18 } from "node:crypto";
43108
43748
  import { lstat as lstat7, rm as rm13, stat as stat7 } from "node:fs/promises";
43109
43749
  import path28 from "node:path";
43110
43750
  var DEFAULT_CLOSE_TIMEOUT_MS = 2e3;
43111
43751
  var DEFAULT_LISTEN_TIMEOUT_MS = 1e4;
43112
- function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID16()) {
43752
+ function remoteOfficialAppServerSocketPath(desktopControlSocketPath, token = randomUUID18()) {
43113
43753
  if (!path28.posix.isAbsolute(desktopControlSocketPath)) {
43114
43754
  throw new Error("Desktop control socket path must be absolute");
43115
43755
  }
@@ -44035,10 +44675,10 @@ var DelegationControlRegistry = class {
44035
44675
  );
44036
44676
  }
44037
44677
  #compareThreads(left, right, sort) {
44038
- const field = sort.startsWith("created") ? "createdAt" : "updatedAt";
44678
+ const field2 = sort.startsWith("created") ? "createdAt" : "updatedAt";
44039
44679
  const direction = sort.endsWith("asc") ? 1 : -1;
44040
- const leftValue = left[field] ? Date.parse(left[field]) : 0;
44041
- const rightValue = right[field] ? Date.parse(right[field]) : 0;
44680
+ const leftValue = left[field2] ? Date.parse(left[field2]) : 0;
44681
+ const rightValue = right[field2] ? Date.parse(right[field2]) : 0;
44042
44682
  return (leftValue - rightValue) * direction || left.threadId.localeCompare(right.threadId);
44043
44683
  }
44044
44684
  async #matching(predicate) {
@@ -44328,11 +44968,11 @@ async function readRemoteDelegationThread(environment, input) {
44328
44968
  }
44329
44969
 
44330
44970
  // packages/host-runtime/src/shared-thread-owner.ts
44331
- import { randomUUID as randomUUID18 } from "node:crypto";
44971
+ import { randomUUID as randomUUID20 } from "node:crypto";
44332
44972
  import { PassThrough as PassThrough3 } from "node:stream";
44333
44973
 
44334
44974
  // packages/host-runtime/src/shared-thread-peer.ts
44335
- import { randomUUID as randomUUID17 } from "node:crypto";
44975
+ import { randomUUID as randomUUID19 } from "node:crypto";
44336
44976
  function object5(value2) {
44337
44977
  return value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
44338
44978
  }
@@ -44346,7 +44986,7 @@ var StreamThreadPeer = class {
44346
44986
  input;
44347
44987
  output;
44348
44988
  stop;
44349
- #prefix = `shared:${randomUUID17()}:`;
44989
+ #prefix = `shared:${randomUUID19()}:`;
44350
44990
  #pending = /* @__PURE__ */ new Map();
44351
44991
  #listeners = /* @__PURE__ */ new Set();
44352
44992
  #ended = Promise.withResolvers();
@@ -44424,7 +45064,7 @@ var SharedThreadOwner = class {
44424
45064
  input = new PassThrough3();
44425
45065
  output = new PassThrough3();
44426
45066
  #peer = new StreamThreadPeer(this.output, this.input, () => this.input.end());
44427
- #prefix = `shared-interaction:${randomUUID18()}:`;
45067
+ #prefix = `shared-interaction:${randomUUID20()}:`;
44428
45068
  #interactions = /* @__PURE__ */ new Map();
44429
45069
  #listeners = /* @__PURE__ */ new Set();
44430
45070
  #receipts = /* @__PURE__ */ new Map();
@@ -44734,7 +45374,7 @@ var SharedThreadBridge = class {
44734
45374
  };
44735
45375
 
44736
45376
  // packages/host-runtime/src/remote-control-app-server.ts
44737
- import { randomUUID as randomUUID19 } from "node:crypto";
45377
+ import { randomUUID as randomUUID21 } from "node:crypto";
44738
45378
  import { mkdir as mkdir15, open as open10, rename as rename12, rm as rm14 } from "node:fs/promises";
44739
45379
  import path33 from "node:path";
44740
45380
  var REMOTE_CONTROL_BRIDGE_PIPE_ENV = "CODEXHOST_REMOTE_CONTROL_BRIDGE_PIPE";
@@ -44755,7 +45395,7 @@ function nodeCompatibleWindowsPath(value2) {
44755
45395
  if (value2.startsWith("\\\\?\\")) return value2.slice(4);
44756
45396
  return value2;
44757
45397
  }
44758
- function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID19()) {
45398
+ function remoteControlBridgePipePath(processId = process.pid, instanceId = randomUUID21()) {
44759
45399
  const safeInstance = instanceId.replaceAll(/[^a-zA-Z0-9-]/gu, "");
44760
45400
  if (!safeInstance) throw new Error("Remote Control bridge instance ID is invalid");
44761
45401
  return `\\\\.\\pipe\\codexhost-remote-control-${processId}-${safeInstance}`;
@@ -44770,7 +45410,7 @@ async function publishRemoteControlAppServerDescriptor(plan) {
44770
45410
  await mkdir15(directory, { recursive: true, mode: 448 });
44771
45411
  const temporaryPath = path33.join(
44772
45412
  directory,
44773
- `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID19()}.tmp`
45413
+ `.${REMOTE_CONTROL_BRIDGE_DESCRIPTOR_FILE}.${plan.descriptor.ownerPid}.${randomUUID21()}.tmp`
44774
45414
  );
44775
45415
  const handle = await open10(temporaryPath, "wx", 384);
44776
45416
  try {
@@ -45292,12 +45932,19 @@ function createHostUpdateCoordinator(options2) {
45292
45932
  }
45293
45933
 
45294
45934
  // packages/host-runtime/src/usage-statistics.ts
45295
- import { randomUUID as randomUUID20 } from "node:crypto";
45935
+ import { randomUUID as randomUUID22 } from "node:crypto";
45296
45936
  import { mkdir as mkdir17, readFile as readFile17, readdir as readdir6, rename as rename14, rm as rm16, writeFile as writeFile10 } from "node:fs/promises";
45297
45937
  import path36 from "node:path";
45298
45938
  import { setImmediate as yieldToEventLoop } from "node:timers/promises";
45299
45939
 
45300
45940
  // packages/harness-adapter/dist/usage-statistics.js
45941
+ var HarnessUsageSourceChangedError = class extends Error {
45942
+ code = "HARNESS_USAGE_SOURCE_CHANGED";
45943
+ /** Plugins may bundle their own copy of this contract, so instanceof is insufficient. */
45944
+ static is(error51) {
45945
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "HARNESS_USAGE_SOURCE_CHANGED";
45946
+ }
45947
+ };
45301
45948
  var MAX_SESSION_ID_LENGTH = 512;
45302
45949
  var MAX_CWD_LENGTH = 4096;
45303
45950
  var MAX_SESSION_TITLE_LENGTH = 200;
@@ -45309,10 +45956,13 @@ function usageSessionTitle(value2) {
45309
45956
  return void 0;
45310
45957
  if (normalized.length <= MAX_SESSION_TITLE_LENGTH)
45311
45958
  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()}…`;
45959
+ let title = "";
45960
+ for (const character of normalized) {
45961
+ if (title.length + character.length >= MAX_SESSION_TITLE_LENGTH)
45962
+ break;
45963
+ title += character;
45964
+ }
45965
+ return `${title.trimEnd()}…`;
45316
45966
  }
45317
45967
  function sessionIdOk(value2) {
45318
45968
  return typeof value2 === "string" && value2.length > 0 && value2.length <= MAX_SESSION_ID_LENGTH;
@@ -45336,13 +45986,13 @@ function parseHarnessUsageEntry(value2) {
45336
45986
  }
45337
45987
  if (!tokenCount(entry.inputTokens) || !tokenCount(entry.outputTokens))
45338
45988
  return null;
45339
- for (const field of [
45989
+ for (const field2 of [
45340
45990
  "cachedInputTokens",
45341
45991
  "cacheWriteInputTokens",
45342
45992
  "cacheWrite1hInputTokens",
45343
45993
  "reasoningOutputTokens"
45344
45994
  ]) {
45345
- if (entry[field] !== void 0 && !tokenCount(entry[field]))
45995
+ if (entry[field2] !== void 0 && !tokenCount(entry[field2]))
45346
45996
  return null;
45347
45997
  }
45348
45998
  const cached2 = entry.cachedInputTokens ?? 0;
@@ -45397,6 +46047,95 @@ function withHostSessionTitles(result, records) {
45397
46047
  };
45398
46048
  }
45399
46049
 
46050
+ // packages/host-runtime/src/usage-statistics-sources.ts
46051
+ import { setTimeout as delay6 } from "node:timers/promises";
46052
+ async function* readUsageStatisticsSources(capability, sources, signal) {
46053
+ let pending = sources;
46054
+ for (let attempt = 0; ; attempt++) {
46055
+ const changed = [];
46056
+ for (const source of pending) {
46057
+ signal.throwIfAborted();
46058
+ try {
46059
+ const entries = (await capability.readSource(source.id, signal)).map(parseHarnessUsageEntry).filter((entry) => entry !== null);
46060
+ yield { source, entries };
46061
+ } catch (error51) {
46062
+ signal.throwIfAborted();
46063
+ if (HarnessUsageSourceChangedError.is(error51) && attempt < 2) changed.push(source);
46064
+ else yield { source, error: error51 };
46065
+ }
46066
+ }
46067
+ if (!changed.length) return;
46068
+ await delay6(50 * (attempt + 1), void 0, { signal });
46069
+ let current;
46070
+ try {
46071
+ current = new Map(
46072
+ (await capability.listSources(signal)).map((source) => [source.id, source])
46073
+ );
46074
+ } catch (error51) {
46075
+ signal.throwIfAborted();
46076
+ for (const source of changed) yield { source, error: error51 };
46077
+ return;
46078
+ }
46079
+ const next = [];
46080
+ for (const source of changed) {
46081
+ const fresh = current.get(source.id);
46082
+ if (fresh) next.push(fresh);
46083
+ else yield { source, removed: true };
46084
+ }
46085
+ pending = next;
46086
+ }
46087
+ }
46088
+
46089
+ // packages/host-runtime/src/usage-statistics-calendar.ts
46090
+ function dateKey(year, month, day) {
46091
+ return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
46092
+ }
46093
+ function createUsageStatisticsCalendar(timeZone) {
46094
+ const localZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
46095
+ const zone = timeZone ?? localZone;
46096
+ if (zone === localZone) {
46097
+ return {
46098
+ timeZone: zone,
46099
+ at(ms) {
46100
+ const date5 = new Date(ms);
46101
+ return {
46102
+ date: dateKey(date5.getFullYear(), date5.getMonth() + 1, date5.getDate()),
46103
+ weekday: date5.getDay(),
46104
+ hour: date5.getHours()
46105
+ };
46106
+ }
46107
+ };
46108
+ }
46109
+ const format = new Intl.DateTimeFormat("en-US", {
46110
+ timeZone: zone,
46111
+ calendar: "gregory",
46112
+ numberingSystem: "latn",
46113
+ year: "numeric",
46114
+ month: "2-digit",
46115
+ day: "2-digit",
46116
+ hour: "2-digit",
46117
+ hourCycle: "h23"
46118
+ });
46119
+ return {
46120
+ timeZone: zone,
46121
+ at(ms) {
46122
+ const parts = format.formatToParts(ms);
46123
+ const part = (type) => Number(parts.find((value2) => value2.type === type)?.value);
46124
+ const year = part("year"), month = part("month"), day = part("day");
46125
+ return {
46126
+ date: dateKey(year, month, day),
46127
+ weekday: new Date(Date.UTC(year, month - 1, day)).getUTCDay(),
46128
+ hour: part("hour")
46129
+ };
46130
+ }
46131
+ };
46132
+ }
46133
+ function shiftUsageDate(date5, days) {
46134
+ const value2 = /* @__PURE__ */ new Date(`${date5}T12:00:00Z`);
46135
+ value2.setUTCDate(value2.getUTCDate() + days);
46136
+ return dateKey(value2.getUTCFullYear(), value2.getUTCMonth() + 1, value2.getUTCDate());
46137
+ }
46138
+
45400
46139
  // packages/host-runtime/src/usage-statistics.ts
45401
46140
  var CACHE_VERSION = 7;
45402
46141
  var STALE_AFTER_MS = 1e4;
@@ -45457,17 +46196,6 @@ function expand(value2, intern) {
45457
46196
  function message(error51) {
45458
46197
  return error51 instanceof Error ? error51.message : String(error51);
45459
46198
  }
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
46199
  var SESSIONS_PER_MEASURE = 50;
45472
46200
  var MODELS_PER_SESSION = 16;
45473
46201
  function emptyTotals() {
@@ -45654,23 +46382,27 @@ var UsageStatistics = class {
45654
46382
  }
45655
46383
  for (const { harness: harness2, capability, ids } of listed) {
45656
46384
  const cache = this.#cache(harness2);
45657
- const present = /* @__PURE__ */ new Set();
46385
+ const present = new Set(ids.map(({ id: id2 }) => id2));
45658
46386
  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 });
46387
+ const pending = ids.filter(
46388
+ ({ id: id2, fingerprint }) => cache.sources.get(id2)?.fingerprint !== fingerprint
46389
+ );
46390
+ this.#progress.read += ids.length - pending.length;
46391
+ try {
46392
+ for await (const result of readUsageStatisticsSources(capability, pending, signal)) {
46393
+ const { id: id2, fingerprint } = result.source;
46394
+ if ("entries" in result) {
46395
+ cache.sources.set(id2, { fingerprint, entries: result.entries });
45665
46396
  cache.dirty = true;
45666
46397
  this.#generation += 1;
45667
- } catch (error51) {
45668
- if (signal.aborted) return;
45669
- failed ??= message(error51);
45670
- }
46398
+ } else if ("error" in result) failed ??= message(result.error);
46399
+ else present.delete(id2);
46400
+ this.#progress.read += 1;
45671
46401
  await yieldToEventLoop();
45672
46402
  }
45673
- this.#progress.read += 1;
46403
+ } catch (error51) {
46404
+ if (signal.aborted) return;
46405
+ throw error51;
45674
46406
  }
45675
46407
  for (const id2 of cache.sources.keys()) {
45676
46408
  if (!present.has(id2)) {
@@ -45735,7 +46467,7 @@ var UsageStatistics = class {
45735
46467
  async #persist(harness2, cache) {
45736
46468
  if (!cache.dirty || this.#now() - cache.persistedAtMs < PERSIST_INTERVAL_MS) return;
45737
46469
  const file2 = this.#file(harness2);
45738
- const temporary = `${file2}.${randomUUID20()}.tmp`;
46470
+ const temporary = `${file2}.${randomUUID22()}.tmp`;
45739
46471
  try {
45740
46472
  await mkdir17(this.#directory, { recursive: true });
45741
46473
  const sources = [...cache.sources].map(([id2, source]) => [
@@ -45753,9 +46485,10 @@ var UsageStatistics = class {
45753
46485
  await rm16(temporary, { force: true });
45754
46486
  }
45755
46487
  }
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;
46488
+ /** Every request once, per Harness in source order, in the requested calendar. */
46489
+ #indexed(calendar) {
46490
+ if (this.#index?.generation === this.#generation && this.#index.timeZone === calendar.timeZone)
46491
+ return this.#index.entries;
45759
46492
  const entries = [];
45760
46493
  for (const [harness2, cache] of this.#caches) {
45761
46494
  const seen = /* @__PURE__ */ new Set();
@@ -45763,26 +46496,20 @@ var UsageStatistics = class {
45763
46496
  for (const entry of parsed2) {
45764
46497
  if (seen.has(entry.id)) continue;
45765
46498
  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
- });
46499
+ entries.push({ harness: harness2, entry, ...calendar.at(entry.occurredAtMs) });
45774
46500
  }
45775
46501
  }
45776
46502
  }
45777
- this.#index = { generation: this.#generation, entries };
46503
+ this.#index = { generation: this.#generation, timeZone: calendar.timeZone, entries };
45778
46504
  return entries;
45779
46505
  }
45780
46506
  #aggregate(params, now, lookup) {
45781
46507
  const { range } = params;
45782
46508
  const days = RANGE_DAYS[range];
45783
- const to = localDate2(now);
46509
+ const calendar = createUsageStatisticsCalendar(params.timeZone);
46510
+ const to = calendar.at(now).date;
45784
46511
  let from = null;
45785
- if (days !== null) from = shiftDate(to, -days + 1);
46512
+ if (days !== null) from = shiftUsageDate(to, -days + 1);
45786
46513
  const inRange = (date5) => (from === null || date5 >= from) && date5 <= to;
45787
46514
  const day = params.date !== void 0 && inRange(params.date) ? params.date : null;
45788
46515
  const harnessFilter = params.harness ?? null;
@@ -45823,7 +46550,7 @@ var UsageStatistics = class {
45823
46550
  const harnessPriced = /* @__PURE__ */ new Map();
45824
46551
  const byProject = /* @__PURE__ */ new Map();
45825
46552
  const sessions = /* @__PURE__ */ new Map();
45826
- for (const indexed of this.#indexed()) {
46553
+ for (const indexed of this.#indexed(calendar)) {
45827
46554
  const { harness: harness2, entry, date: date5 } = indexed;
45828
46555
  if (!inRange(date5)) continue;
45829
46556
  const model2 = entry.model ?? null;
@@ -46351,7 +47078,7 @@ async function runHostRuntime(input) {
46351
47078
  }
46352
47079
 
46353
47080
  // packages/host-runtime/src/remote-host-install.ts
46354
- import { createHash as createHash11, randomUUID as randomUUID21 } from "node:crypto";
47081
+ import { createHash as createHash11, randomUUID as randomUUID23 } from "node:crypto";
46355
47082
  import { constants as fsConstants } from "node:fs";
46356
47083
  import {
46357
47084
  access as access3,
@@ -46450,7 +47177,7 @@ async function writeAtomic(filePath, contents, mode) {
46450
47177
  await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
46451
47178
  const temporary = path38.join(
46452
47179
  path38.dirname(filePath),
46453
- `.${path38.basename(filePath)}.${process.pid}.${randomUUID21()}.tmp`
47180
+ `.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
46454
47181
  );
46455
47182
  try {
46456
47183
  if (typeof contents === "string") {
@@ -46474,7 +47201,7 @@ async function writeAtomicExecutable(filePath, sourcePath) {
46474
47201
  await mkdir18(path38.dirname(filePath), { recursive: true, mode: 448 });
46475
47202
  const temporary = path38.join(
46476
47203
  path38.dirname(filePath),
46477
- `.${path38.basename(filePath)}.${process.pid}.${randomUUID21()}.tmp`
47204
+ `.${path38.basename(filePath)}.${process.pid}.${randomUUID23()}.tmp`
46478
47205
  );
46479
47206
  try {
46480
47207
  await copyFile4(sourcePath, temporary);
@@ -47206,6 +47933,7 @@ async function runRemoteHostCli(input) {
47206
47933
  var HARNESS_BROKER_PROTOCOL_VERSION = 1;
47207
47934
  var HARNESS_BROKER_MAX_FRAME_BYTES = 8 * 1024 * 1024;
47208
47935
  var HARNESS_BROKER_MAX_PENDING_REQUESTS = 32;
47936
+ var HARNESS_BROKER_SESSION_IMPORT_PAGE_SIZE = 100;
47209
47937
  var HARNESS_BROKER_IDLE_TIMEOUT_MS = 60 * 60 * 1e3;
47210
47938
  var HARNESS_BROKER_RETIRING_ERROR_CODE = "brokerRetiring";
47211
47939
  var harnessBrokerMethodSchema = external_exports.enum([
@@ -47213,8 +47941,11 @@ var harnessBrokerMethodSchema = external_exports.enum([
47213
47941
  "adapter.inspectAccount",
47214
47942
  "adapter.credits",
47215
47943
  "adapter.open",
47944
+ "adapter.sessionImport.list",
47945
+ "adapter.sessionImport.resolve",
47216
47946
  "adapter.subagent.readSnapshot",
47217
47947
  "session.readSnapshot",
47948
+ "session.readCapabilities",
47218
47949
  "session.refreshUsage",
47219
47950
  "session.execute",
47220
47951
  "session.commands.list",
@@ -47317,29 +48048,6 @@ function consumeBrokerFrames(socket, onFrame, onError) {
47317
48048
  });
47318
48049
  }
47319
48050
 
47320
- // packages/harness-broker/dist/paths.js
47321
- import os11 from "node:os";
47322
- import path40 from "node:path";
47323
- var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
47324
- var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
47325
- var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
47326
- function defaultHarnessBrokerDirectory(environment = process.env) {
47327
- const home = environment.HOME || os11.homedir();
47328
- return path40.join(home, ".codexhost", "harness-broker");
47329
- }
47330
- function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
47331
- harnessPluginIdSchema.parse(harnessId);
47332
- if (harnessId !== "claude-code")
47333
- return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
47334
- return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
47335
- }
47336
- function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
47337
- harnessPluginIdSchema.parse(harnessId);
47338
- if (harnessId !== "claude-code")
47339
- return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
47340
- return path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
47341
- }
47342
-
47343
48051
  // packages/harness-broker/dist/validation.js
47344
48052
  var cwdSchema = external_exports.string().min(1).max(16384);
47345
48053
  var brokerEnvironmentSchema = external_exports.object({
@@ -47390,13 +48098,42 @@ var brokerOpenInputSchema = external_exports.discriminatedUnion("kind", [
47390
48098
  forkSchema,
47391
48099
  rollbackSchema
47392
48100
  ]);
47393
- var brokerInspectInputSchema = external_exports.object({ cwd: cwdSchema.optional(), refresh: external_exports.boolean().optional() }).strict();
48101
+ var brokerInspectInputSchema = external_exports.object({
48102
+ cwd: cwdSchema.optional(),
48103
+ refresh: external_exports.boolean().optional(),
48104
+ purpose: external_exports.literal("availability").optional()
48105
+ }).strict();
48106
+ var brokerSessionImportListParamsSchema = external_exports.object({
48107
+ offset: external_exports.number().int().nonnegative().safe(),
48108
+ limit: external_exports.number().int().min(1).max(HARNESS_BROKER_SESSION_IMPORT_PAGE_SIZE)
48109
+ }).strict();
48110
+ var brokerSessionImportResolveParamsSchema = external_exports.object({ nativeSessionId: harnessSessionImportIdSchema }).strict();
48111
+ var brokerSessionImportPageSchema = external_exports.object({
48112
+ candidates: external_exports.array(harnessSessionImportCandidateSchema).max(HARNESS_BROKER_SESSION_IMPORT_PAGE_SIZE),
48113
+ total: external_exports.number().int().nonnegative().safe()
48114
+ }).strict();
48115
+ var brokerSessionImportSourceSchema = external_exports.object({
48116
+ candidate: harnessSessionImportCandidateSchema,
48117
+ nativeRef: nativeSessionRefSchema
48118
+ }).strict().superRefine((source, context) => {
48119
+ if (source.nativeRef.nativeSessionId !== source.candidate.nativeSessionId) {
48120
+ context.addIssue({
48121
+ code: "custom",
48122
+ message: "Session import source identity does not match"
48123
+ });
48124
+ }
48125
+ });
47394
48126
  var textInputSchema = external_exports.object({ type: external_exports.literal("text"), text: external_exports.string().max(4e6) }).strict();
47395
48127
  var turnStartSchema = external_exports.object({
47396
48128
  type: external_exports.literal("turn.start"),
47397
48129
  turnId: hostTurnIdSchema,
47398
48130
  input: external_exports.array(textInputSchema)
47399
48131
  }).strict();
48132
+ var turnSteerSchema = external_exports.object({
48133
+ type: external_exports.literal("turn.steer"),
48134
+ turnId: hostTurnIdSchema,
48135
+ input: external_exports.array(textInputSchema)
48136
+ }).strict();
47400
48137
  var turnCancelSchema = external_exports.object({ type: external_exports.literal("turn.cancel"), turnId: hostTurnIdSchema }).strict();
47401
48138
  var interactionResponseSchema = external_exports.union([
47402
48139
  external_exports.object({
@@ -47422,6 +48159,7 @@ var permissionSelectSchema = external_exports.object({
47422
48159
  }).strict();
47423
48160
  var brokerHostCommandSchema = external_exports.discriminatedUnion("type", [
47424
48161
  turnStartSchema,
48162
+ turnSteerSchema,
47425
48163
  turnCancelSchema,
47426
48164
  interactionRespondSchema,
47427
48165
  modelSelectSchema,
@@ -47555,8 +48293,31 @@ var harnessOutputSchema = external_exports.custom((value2) => {
47555
48293
  return false;
47556
48294
  });
47557
48295
 
48296
+ // packages/harness-broker/dist/paths.js
48297
+ import os11 from "node:os";
48298
+ import path40 from "node:path";
48299
+ var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
48300
+ var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
48301
+ var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
48302
+ function defaultHarnessBrokerDirectory(environment = process.env) {
48303
+ const home = environment.HOME || os11.homedir();
48304
+ return path40.join(home, ".codexhost", "harness-broker");
48305
+ }
48306
+ function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
48307
+ harnessPluginIdSchema.parse(harnessId);
48308
+ if (harnessId !== "claude-code")
48309
+ return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
48310
+ return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
48311
+ }
48312
+ function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
48313
+ harnessPluginIdSchema.parse(harnessId);
48314
+ if (harnessId !== "claude-code")
48315
+ return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
48316
+ return path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
48317
+ }
48318
+
47558
48319
  // packages/harness-broker/dist/server.js
47559
- import { randomBytes as randomBytes5, randomUUID as randomUUID22 } from "node:crypto";
48320
+ import { randomBytes as randomBytes5, randomUUID as randomUUID24 } from "node:crypto";
47560
48321
  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
48322
  import net4, {} from "node:net";
47562
48323
  import path41 from "node:path";
@@ -47615,7 +48376,7 @@ async function assertNoLiveDescriptor(descriptorPath) {
47615
48376
  }
47616
48377
  }
47617
48378
  async function publishDescriptor(descriptorPath, descriptor) {
47618
- const temporary = `${descriptorPath}.${process.pid}.${randomUUID22()}.tmp`;
48379
+ const temporary = `${descriptorPath}.${process.pid}.${randomUUID24()}.tmp`;
47619
48380
  const handle = await open11(temporary, "wx", 384);
47620
48381
  try {
47621
48382
  await handle.writeFile(`${JSON.stringify(descriptor)}
@@ -47640,6 +48401,7 @@ function sessionMetadata(record4) {
47640
48401
  sessionId: record4.id,
47641
48402
  sessionGeneration: record4.generation,
47642
48403
  capabilities: record4.session.capabilities,
48404
+ readCapabilities: true,
47643
48405
  initialState: {
47644
48406
  ...initialState,
47645
48407
  ...record4.nativeRef ? { nativeRef: record4.nativeRef } : {},
@@ -47692,7 +48454,7 @@ async function startHarnessBrokerServer(input) {
47692
48454
  await assertNoLiveDescriptor(input.descriptorPath);
47693
48455
  if (process.platform !== "win32")
47694
48456
  await prepareUnixSocketPath(input.socketPath);
47695
- const generation = input.generation ?? randomUUID22();
48457
+ const generation = input.generation ?? randomUUID24();
47696
48458
  const token = input.token ?? randomBytes5(32).toString("hex");
47697
48459
  const descriptor = {
47698
48460
  schemaVersion: 1,
@@ -47733,7 +48495,7 @@ async function startHarnessBrokerServer(input) {
47733
48495
  };
47734
48496
  const server = net4.createServer((socket) => {
47735
48497
  const state = {
47736
- id: randomUUID22(),
48498
+ id: randomUUID24(),
47737
48499
  socket,
47738
48500
  authenticated: false,
47739
48501
  inputSequence: 0,
@@ -47924,11 +48686,74 @@ async function startHarnessBrokerServer(input) {
47924
48686
  const parsed2 = brokerInspectInputSchema.parse(request.params);
47925
48687
  const inspection = await input.adapter.inspect({
47926
48688
  ...parsed2.cwd ? { cwd: parsed2.cwd } : {},
47927
- ...parsed2.refresh !== void 0 ? { refresh: parsed2.refresh } : {}
48689
+ ...parsed2.refresh !== void 0 ? { refresh: parsed2.refresh } : {},
48690
+ ...parsed2.purpose !== void 0 ? { purpose: parsed2.purpose } : {}
47928
48691
  });
47929
48692
  retireWhenIdle = inspection.status !== "ready";
47930
48693
  return inspection;
47931
48694
  }
48695
+ if (request.method === "adapter.sessionImport.list") {
48696
+ const { limit, offset } = brokerSessionImportListParamsSchema.parse(request.params);
48697
+ const capability = input.adapter.sessionImport;
48698
+ if (!capability?.resolveCandidate) {
48699
+ return {
48700
+ ok: false,
48701
+ error: {
48702
+ code: "unsupported",
48703
+ message: "Harness Session import is unavailable",
48704
+ retryable: false
48705
+ }
48706
+ };
48707
+ }
48708
+ if (offset === 0) {
48709
+ delete state.sessionImportCandidates;
48710
+ const result = await capability.listCandidates();
48711
+ if (!result.ok)
48712
+ return result;
48713
+ state.sessionImportCandidates = result.value.map((candidate) => harnessSessionImportCandidateSchema.parse(candidate));
48714
+ }
48715
+ const candidates = state.sessionImportCandidates;
48716
+ if (!candidates) {
48717
+ return {
48718
+ ok: false,
48719
+ error: {
48720
+ code: "invalidState",
48721
+ message: "Session import snapshot is unavailable; refresh the list",
48722
+ retryable: true
48723
+ }
48724
+ };
48725
+ }
48726
+ const page = candidates.slice(offset, offset + limit);
48727
+ const total = candidates.length;
48728
+ if (offset + page.length >= total)
48729
+ delete state.sessionImportCandidates;
48730
+ return { ok: true, value: { candidates: page, total } };
48731
+ }
48732
+ if (request.method === "adapter.sessionImport.resolve") {
48733
+ const { nativeSessionId } = brokerSessionImportResolveParamsSchema.parse(request.params);
48734
+ const capability = input.adapter.sessionImport;
48735
+ if (!capability?.resolveCandidate) {
48736
+ return {
48737
+ ok: false,
48738
+ error: {
48739
+ code: "unsupported",
48740
+ message: "Harness Session import is unavailable",
48741
+ retryable: false
48742
+ }
48743
+ };
48744
+ }
48745
+ const result = await capability.resolveCandidate(nativeSessionId);
48746
+ if (!result.ok)
48747
+ return result;
48748
+ const source = brokerSessionImportSourceSchema.safeParse(result.value);
48749
+ if (!source.success || source.data.nativeRef.harnessId !== input.adapter.harnessId || source.data.candidate.nativeSessionId !== nativeSessionId) {
48750
+ return {
48751
+ ok: false,
48752
+ error: protocolError("Session import source identity does not match")
48753
+ };
48754
+ }
48755
+ return { ok: true, value: source.data };
48756
+ }
47932
48757
  if (request.method === "adapter.subagent.readSnapshot") {
47933
48758
  const subagents = input.adapter.subagents;
47934
48759
  if (!subagents)
@@ -47971,7 +48796,7 @@ async function startHarnessBrokerServer(input) {
47971
48796
  }
47972
48797
  };
47973
48798
  }
47974
- const openReservation = randomUUID22();
48799
+ const openReservation = randomUUID24();
47975
48800
  if (sourceKey)
47976
48801
  nativeWriters.set(sourceKey, openReservation);
47977
48802
  const provisionalReservation = openInput.kind === "create" ? openReservation : void 0;
@@ -48115,6 +48940,8 @@ async function startHarnessBrokerServer(input) {
48115
48940
  let result;
48116
48941
  if (command.type === "turn.start")
48117
48942
  result = await record5.session.execute(command);
48943
+ else if (command.type === "turn.steer")
48944
+ result = await record5.session.execute(command);
48118
48945
  else if (command.type === "turn.cancel")
48119
48946
  result = await record5.session.execute(command);
48120
48947
  else if (command.type === "interaction.respond") {
@@ -48146,6 +48973,10 @@ async function startHarnessBrokerServer(input) {
48146
48973
  }
48147
48974
  return result;
48148
48975
  }
48976
+ if (request.method === "session.readCapabilities") {
48977
+ const session = requireSession(request.params).session;
48978
+ return session.readCapabilities ? session.readCapabilities() : session.capabilities;
48979
+ }
48149
48980
  if (request.method === "session.readSnapshot") {
48150
48981
  return requireSession(request.params).session.readSnapshot();
48151
48982
  }
@@ -48272,7 +49103,7 @@ async function startHarnessBrokerServer(input) {
48272
49103
  }
48273
49104
  state.authenticated = true;
48274
49105
  state.inputSequence = 1;
48275
- await send({ kind: "response", id: randomUUID22(), ok: true, value: { ready: true } });
49106
+ await send({ kind: "response", id: randomUUID24(), ok: true, value: { ready: true } });
48276
49107
  return;
48277
49108
  }
48278
49109
  const parsed2 = harnessBrokerRequestSchema.safeParse(raw);