@codexhost/cli-darwin-x64 0.14.0 → 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.
@@ -8461,10 +8461,10 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
8461
8461
  const shape = def.shape;
8462
8462
  const propValues = {};
8463
8463
  for (const key in shape) {
8464
- const field = shape[key]._zod;
8465
- if (field.values) {
8464
+ const field2 = shape[key]._zod;
8465
+ if (field2.values) {
8466
8466
  propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
8467
- for (const v of field.values)
8467
+ for (const v of field2.values)
8468
8468
  propValues[key].add(v);
8469
8469
  }
8470
8470
  }
@@ -20223,6 +20223,53 @@ var THREAD_PREWARM_DISCARD_METHOD = "codexhost/thread/prewarm/discard";
20223
20223
  var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
20224
20224
  var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
20225
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
+
20226
20273
  // packages/shared-contracts/dist/console.js
20227
20274
  var consoleAnnouncementSchema = external_exports.strictObject({
20228
20275
  title: external_exports.string().trim().min(1).max(200),
@@ -24474,9 +24521,9 @@ function parseModelPriceOverrides(value2) {
24474
24521
  if (key.length === 0 || !isRecord3(entry)) {
24475
24522
  throw new Error(`Price override '${key}' is invalid`);
24476
24523
  }
24477
- for (const field of Object.keys(entry)) {
24478
- if (!["input", "output", "cacheRead", "cacheWrite", "cacheWrite1h"].includes(field)) {
24479
- 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}'`);
24480
24527
  }
24481
24528
  }
24482
24529
  const input = price(entry.input);
@@ -24485,11 +24532,11 @@ function parseModelPriceOverrides(value2) {
24485
24532
  throw new Error(`Price override '${key}' needs non-negative 'input' and 'output'`);
24486
24533
  }
24487
24534
  const resolved = { input, output };
24488
- for (const field of ["cacheRead", "cacheWrite", "cacheWrite1h"]) {
24489
- if (entry[field] === void 0) continue;
24490
- const candidate = price(entry[field]);
24491
- if (candidate === null) throw new Error(`Price override '${key}' has invalid '${field}'`);
24492
- 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;
24493
24540
  }
24494
24541
  overrides.set(key, resolved);
24495
24542
  }
@@ -25180,6 +25227,42 @@ function parseHarnessAccountCredits(value2) {
25180
25227
  return parsed2.success ? parsed2.data : null;
25181
25228
  }
25182
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
+
25183
25266
  // packages/harness-adapter/dist/output-channel.js
25184
25267
  var HarnessOutputChannel = class {
25185
25268
  outputs;
@@ -25286,26 +25369,26 @@ function parseHostUsage(value2) {
25286
25369
  }
25287
25370
  }
25288
25371
  const indicators = value2.composerIndicators === void 0 ? {} : { composerIndicators: composerIndicatorsSchema.parse(value2.composerIndicators) };
25289
- for (const field of [
25372
+ for (const field2 of [
25290
25373
  "totalCredits",
25291
25374
  "contextUsagePercent",
25292
25375
  "apiOutputTokensPerSecond"
25293
25376
  ]) {
25294
- const candidate = value2[field];
25377
+ const candidate = value2[field2];
25295
25378
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
25296
- 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`);
25297
25380
  }
25298
25381
  }
25299
- for (const field of tokenFields) {
25300
- const candidate = value2[field];
25382
+ for (const field2 of tokenFields) {
25383
+ const candidate = value2[field2];
25301
25384
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
25302
- 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`);
25303
25386
  }
25304
25387
  }
25305
- for (const field of safeIntegerFields) {
25306
- const candidate = value2[field];
25388
+ for (const field2 of safeIntegerFields) {
25389
+ const candidate = value2[field2];
25307
25390
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
25308
- 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`);
25309
25392
  }
25310
25393
  }
25311
25394
  if (value2.outputTokensPerSecond !== void 0 && (typeof value2.outputTokensPerSecond !== "number" || !Number.isFinite(value2.outputTokensPerSecond) || value2.outputTokensPerSecond < 0)) {
@@ -25314,10 +25397,10 @@ function parseHostUsage(value2) {
25314
25397
  if (value2.totalCostUsd !== void 0 && (typeof value2.totalCostUsd !== "number" || !Number.isFinite(value2.totalCostUsd) || value2.totalCostUsd < 0)) {
25315
25398
  throw new Error("Harness Usage 'totalCostUsd' must be a finite non-negative number");
25316
25399
  }
25317
- for (const field of percentFields) {
25318
- const candidate = value2[field];
25400
+ for (const field2 of percentFields) {
25401
+ const candidate = value2[field2];
25319
25402
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0 || candidate > 100)) {
25320
- 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`);
25321
25404
  }
25322
25405
  }
25323
25406
  if (value2.sessionCacheUsage !== void 0) {
@@ -25388,19 +25471,19 @@ function parseHostUsageRequest(value2) {
25388
25471
  if (typeof value2.requestId !== "string" || value2.requestId.length === 0) {
25389
25472
  throw new Error("Harness Usage request 'requestId' must be a non-empty string");
25390
25473
  }
25391
- for (const field of ["model", "provider"]) {
25392
- const candidate = value2[field];
25474
+ for (const field2 of ["model", "provider"]) {
25475
+ const candidate = value2[field2];
25393
25476
  if (candidate !== void 0 && (typeof candidate !== "string" || candidate.length === 0)) {
25394
- 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`);
25395
25478
  }
25396
25479
  }
25397
25480
  if (value2.historical !== void 0 && typeof value2.historical !== "boolean") {
25398
25481
  throw new Error("Harness Usage request 'historical' must be a boolean");
25399
25482
  }
25400
- for (const field of requestTokenFields) {
25401
- const candidate = value2[field];
25483
+ for (const field2 of requestTokenFields) {
25484
+ const candidate = value2[field2];
25402
25485
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
25403
- 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`);
25404
25487
  }
25405
25488
  }
25406
25489
  if (value2.inputTokens === void 0 || value2.outputTokens === void 0) {
@@ -25916,10 +25999,15 @@ function processIdentity(pid) {
25916
25999
  }
25917
26000
  const query = [
25918
26001
  "$ErrorActionPreference = 'Stop'",
25919
- `$process = Get-Process -Id ${pid}`,
25920
- "$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 }"
25921
26004
  ].join("; ");
25922
- 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();
25923
26011
  if (!result)
25924
26012
  return { executablePath: null, startedAt: null };
25925
26013
  const parsed2 = JSON.parse(result);
@@ -26790,17 +26878,17 @@ var ELLIPSIS = "…";
26790
26878
  function isRecord7(value2) {
26791
26879
  return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
26792
26880
  }
26793
- function boundedText(value2, field, maxLength) {
26881
+ function boundedText(value2, field2, maxLength) {
26794
26882
  const text = value2.trim();
26795
26883
  if (text.length === 0 || text.length > maxLength) {
26796
- 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`);
26797
26885
  }
26798
26886
  return text;
26799
26887
  }
26800
- function clampedText(value2, field, maxLength) {
26888
+ function clampedText(value2, field2, maxLength) {
26801
26889
  const text = value2.trim();
26802
26890
  if (text.length === 0) {
26803
- 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`);
26804
26892
  }
26805
26893
  const characters = [...text];
26806
26894
  if (characters.length <= maxLength)
@@ -28015,9 +28103,9 @@ function nestedString(value2, keys, preserveText = false) {
28015
28103
  if (!isRecord10(value2))
28016
28104
  return void 0;
28017
28105
  for (const key of keys) {
28018
- const field = value2[key];
28019
- if (typeof field === "string" && (preserveText || field.trim().length > 0))
28020
- 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();
28021
28109
  }
28022
28110
  for (const wrapper of ["input", "arguments", "params"]) {
28023
28111
  const nested = nestedString(value2[wrapper], keys, preserveText);
@@ -31410,6 +31498,22 @@ var SessionImportRequests = class {
31410
31498
  }
31411
31499
  };
31412
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
+
31413
31517
  // packages/host-runtime/src/external-thread-history.ts
31414
31518
  var DEFAULT_PAGE_SIZE2 = 25;
31415
31519
  var MAX_PAGE_SIZE2 = 100;
@@ -32367,7 +32471,7 @@ var UsageMeter = class {
32367
32471
  derive(native, prices) {
32368
32472
  const usage = Object.fromEntries(
32369
32473
  Object.entries(native ?? {}).filter(
32370
- ([field]) => !hostDerivedUsageFields.includes(field)
32474
+ ([field2]) => !hostDerivedUsageFields.includes(field2)
32371
32475
  )
32372
32476
  );
32373
32477
  const sessionCacheUsage = usage.sessionCacheUsage;
@@ -34059,10 +34163,10 @@ var HarnessDelegationCoordinator = class {
34059
34163
  }
34060
34164
  };
34061
34165
  });
34062
- const [field, direction] = input.sort.split("-");
34166
+ const [field2, direction] = input.sort.split("-");
34063
34167
  rows.sort((left, right) => {
34064
- const leftTimestamp = field === "created" ? left.createdAt : left.updatedAt;
34065
- 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;
34066
34170
  const leftTime = Date.parse(leftTimestamp ?? "");
34067
34171
  const rightTime = Date.parse(rightTimestamp ?? "");
34068
34172
  return direction === "asc" ? leftTime - rightTime : rightTime - leftTime;
@@ -37461,9 +37565,9 @@ var RequestRouteObservationTracker = class {
37461
37565
  };
37462
37566
 
37463
37567
  // packages/host-runtime/src/external-thread-list.ts
37464
- function unixTimestamp(value2, field) {
37568
+ function unixTimestamp(value2, field2) {
37465
37569
  const parsed2 = Date.parse(value2);
37466
- 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`);
37467
37571
  return Math.floor(parsed2 / 1e3);
37468
37572
  }
37469
37573
  function threadId(thread) {
@@ -37473,11 +37577,11 @@ function threadId(thread) {
37473
37577
  return thread.id;
37474
37578
  }
37475
37579
  function threadListTimestamp(thread, sortKey) {
37476
- const field = sortKey === "created_at" ? thread.createdAt : sortKey === "updated_at" ? thread.updatedAt : thread.recencyAt ?? thread.updatedAt;
37477
- 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)) {
37478
37582
  throw new Error(`Thread list row has no valid ${sortKey} timestamp`);
37479
37583
  }
37480
- return field;
37584
+ return field2;
37481
37585
  }
37482
37586
  function compareTimestamp(left, right, direction) {
37483
37587
  if (left === right) return 0;
@@ -39298,6 +39402,15 @@ var AppServerHost = class {
39298
39402
  await this.#listThreadOwnership(request);
39299
39403
  return;
39300
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
+ }
39301
39414
  if (request.method === "codexhost/thread/steering/inspect") {
39302
39415
  await this.#inspectThreadSteering(request);
39303
39416
  return;
@@ -42226,6 +42339,10 @@ var AppServerHost = class {
42226
42339
  return;
42227
42340
  }
42228
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
+ }
42229
42346
  this.#externalSteering.fault(thread.id, new Error(event.error.message));
42230
42347
  thread.stateObserver.fault(new Error(event.error.message));
42231
42348
  this.#externalRuntime.markSessionUnavailable(thread);
@@ -42269,6 +42386,12 @@ var AppServerHost = class {
42269
42386
  if (event.type === "interaction.closed" && thread.ignoredInteractionIds.delete(event.interactionId)) {
42270
42387
  return;
42271
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
+ }
42272
42395
  if (event.type === "interaction.closed") {
42273
42396
  await this.#resolveDesktopApproval(event.interactionId);
42274
42397
  await this.#resolveDesktopQuestion(event.interactionId);
@@ -42597,11 +42720,72 @@ var AppServerHost = class {
42597
42720
  this.#nextApprovalRequestId -= 1;
42598
42721
  return requestId;
42599
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
+ }
42600
42782
  async #projectQuestion(thread, interaction) {
42601
42783
  const projection = this.#projectedTurn(thread, interaction.turnId);
42602
42784
  await this.#waitForTurnResponse(thread, interaction.turnId);
42603
42785
  let result;
42786
+ const shared = usesSharedQuestionCard(interaction);
42604
42787
  try {
42788
+ if (shared) sharedQuestion(interaction);
42605
42789
  result = projection.projector.projectQuestion(
42606
42790
  interaction,
42607
42791
  hostItemIdSchema.parse(randomUUID16())
@@ -42625,6 +42809,8 @@ var AppServerHost = class {
42625
42809
  const expiresAtMs = interaction.expiresAt ? Date.parse(interaction.expiresAt) : Number.NaN;
42626
42810
  const timeoutMs = Number.isFinite(expiresAtMs) ? Math.max(0, expiresAtMs - Date.now()) : null;
42627
42811
  const pending = {
42812
+ shared,
42813
+ responding: false,
42628
42814
  thread,
42629
42815
  interaction,
42630
42816
  projection: result.questionRequest,
@@ -42636,6 +42822,7 @@ var AppServerHost = class {
42636
42822
  }, timeoutMs);
42637
42823
  }
42638
42824
  this.#pendingDesktopQuestions.set(requestId, pending);
42825
+ if (shared) return;
42639
42826
  try {
42640
42827
  await this.#writer.json({ id: requestId, ...result.questionRequest.request });
42641
42828
  } catch (error51) {
@@ -42652,7 +42839,7 @@ var AppServerHost = class {
42652
42839
  if (!isRecord18(value2) || !isHostQuestionRequestId(value2.id)) return false;
42653
42840
  const requestId = value2.id;
42654
42841
  const pending = this.#pendingDesktopQuestions.get(requestId);
42655
- if (!pending) return true;
42842
+ if (!pending || pending.shared) return true;
42656
42843
  return this.#externalRuntime.idleRelease.runOperation(pending.thread.id, async () => {
42657
42844
  if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
42658
42845
  return true;
@@ -42685,6 +42872,7 @@ var AppServerHost = class {
42685
42872
  if (this.#externalRuntime.get(pending.thread.id) !== pending.thread || this.#externalRuntime.idleRelease.failure(pending.thread))
42686
42873
  return;
42687
42874
  await this.#resolveDesktopQuestion(pending.interaction.interactionId);
42875
+ if (pending.responding) return;
42688
42876
  const result = await pending.thread.session.execute({
42689
42877
  type: "interaction.respond",
42690
42878
  interactionId: pending.interaction.interactionId,
@@ -42707,6 +42895,7 @@ var AppServerHost = class {
42707
42895
  if (pending.interaction.interactionId !== interactionId) continue;
42708
42896
  if (pending.timeout) clearTimeout(pending.timeout);
42709
42897
  this.#pendingDesktopQuestions.delete(requestId);
42898
+ if (pending.shared) continue;
42710
42899
  await this.#writer.json({
42711
42900
  method: "serverRequest/resolved",
42712
42901
  params: { threadId: pending.thread.id, requestId }
@@ -44486,10 +44675,10 @@ var DelegationControlRegistry = class {
44486
44675
  );
44487
44676
  }
44488
44677
  #compareThreads(left, right, sort) {
44489
- const field = sort.startsWith("created") ? "createdAt" : "updatedAt";
44678
+ const field2 = sort.startsWith("created") ? "createdAt" : "updatedAt";
44490
44679
  const direction = sort.endsWith("asc") ? 1 : -1;
44491
- const leftValue = left[field] ? Date.parse(left[field]) : 0;
44492
- 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;
44493
44682
  return (leftValue - rightValue) * direction || left.threadId.localeCompare(right.threadId);
44494
44683
  }
44495
44684
  async #matching(predicate) {
@@ -45797,13 +45986,13 @@ function parseHarnessUsageEntry(value2) {
45797
45986
  }
45798
45987
  if (!tokenCount(entry.inputTokens) || !tokenCount(entry.outputTokens))
45799
45988
  return null;
45800
- for (const field of [
45989
+ for (const field2 of [
45801
45990
  "cachedInputTokens",
45802
45991
  "cacheWriteInputTokens",
45803
45992
  "cacheWrite1hInputTokens",
45804
45993
  "reasoningOutputTokens"
45805
45994
  ]) {
45806
- if (entry[field] !== void 0 && !tokenCount(entry[field]))
45995
+ if (entry[field2] !== void 0 && !tokenCount(entry[field2]))
45807
45996
  return null;
45808
45997
  }
45809
45998
  const cached2 = entry.cachedInputTokens ?? 0;
@@ -47744,6 +47933,7 @@ async function runRemoteHostCli(input) {
47744
47933
  var HARNESS_BROKER_PROTOCOL_VERSION = 1;
47745
47934
  var HARNESS_BROKER_MAX_FRAME_BYTES = 8 * 1024 * 1024;
47746
47935
  var HARNESS_BROKER_MAX_PENDING_REQUESTS = 32;
47936
+ var HARNESS_BROKER_SESSION_IMPORT_PAGE_SIZE = 100;
47747
47937
  var HARNESS_BROKER_IDLE_TIMEOUT_MS = 60 * 60 * 1e3;
47748
47938
  var HARNESS_BROKER_RETIRING_ERROR_CODE = "brokerRetiring";
47749
47939
  var harnessBrokerMethodSchema = external_exports.enum([
@@ -47751,6 +47941,8 @@ var harnessBrokerMethodSchema = external_exports.enum([
47751
47941
  "adapter.inspectAccount",
47752
47942
  "adapter.credits",
47753
47943
  "adapter.open",
47944
+ "adapter.sessionImport.list",
47945
+ "adapter.sessionImport.resolve",
47754
47946
  "adapter.subagent.readSnapshot",
47755
47947
  "session.readSnapshot",
47756
47948
  "session.readCapabilities",
@@ -47856,29 +48048,6 @@ function consumeBrokerFrames(socket, onFrame, onError) {
47856
48048
  });
47857
48049
  }
47858
48050
 
47859
- // packages/harness-broker/dist/paths.js
47860
- import os11 from "node:os";
47861
- import path40 from "node:path";
47862
- var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
47863
- var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
47864
- var HARNESS_BROKER_SOCKET_FILE = "claude-code-broker-v1.sock";
47865
- function defaultHarnessBrokerDirectory(environment = process.env) {
47866
- const home = environment.HOME || os11.homedir();
47867
- return path40.join(home, ".codexhost", "harness-broker");
47868
- }
47869
- function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
47870
- harnessPluginIdSchema.parse(harnessId);
47871
- if (harnessId !== "claude-code")
47872
- return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
47873
- return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
47874
- }
47875
- function defaultHarnessBrokerSocketPath(environment = process.env, harnessId = "claude-code") {
47876
- harnessPluginIdSchema.parse(harnessId);
47877
- if (harnessId !== "claude-code")
47878
- return path40.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.sock`);
47879
- return path40.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_SOCKET_FILE);
47880
- }
47881
-
47882
48051
  // packages/harness-broker/dist/validation.js
47883
48052
  var cwdSchema = external_exports.string().min(1).max(16384);
47884
48053
  var brokerEnvironmentSchema = external_exports.object({
@@ -47929,7 +48098,31 @@ var brokerOpenInputSchema = external_exports.discriminatedUnion("kind", [
47929
48098
  forkSchema,
47930
48099
  rollbackSchema
47931
48100
  ]);
47932
- 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
+ });
47933
48126
  var textInputSchema = external_exports.object({ type: external_exports.literal("text"), text: external_exports.string().max(4e6) }).strict();
47934
48127
  var turnStartSchema = external_exports.object({
47935
48128
  type: external_exports.literal("turn.start"),
@@ -48100,6 +48293,29 @@ var harnessOutputSchema = external_exports.custom((value2) => {
48100
48293
  return false;
48101
48294
  });
48102
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
+
48103
48319
  // packages/harness-broker/dist/server.js
48104
48320
  import { randomBytes as randomBytes5, randomUUID as randomUUID24 } from "node:crypto";
48105
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";
@@ -48470,11 +48686,74 @@ async function startHarnessBrokerServer(input) {
48470
48686
  const parsed2 = brokerInspectInputSchema.parse(request.params);
48471
48687
  const inspection = await input.adapter.inspect({
48472
48688
  ...parsed2.cwd ? { cwd: parsed2.cwd } : {},
48473
- ...parsed2.refresh !== void 0 ? { refresh: parsed2.refresh } : {}
48689
+ ...parsed2.refresh !== void 0 ? { refresh: parsed2.refresh } : {},
48690
+ ...parsed2.purpose !== void 0 ? { purpose: parsed2.purpose } : {}
48474
48691
  });
48475
48692
  retireWhenIdle = inspection.status !== "ready";
48476
48693
  return inspection;
48477
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
+ }
48478
48757
  if (request.method === "adapter.subagent.readSnapshot") {
48479
48758
  const subagents = input.adapter.subagents;
48480
48759
  if (!subagents)