@codexhost/cli-linux-x64 0.2.6 → 0.3.0-test.1

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.
@@ -36,6 +36,7 @@
36
36
  #ownershipRequestGenerations = /* @__PURE__ */ new WeakMap();
37
37
  #states = /* @__PURE__ */ new WeakMap();
38
38
  #switching = /* @__PURE__ */ new Set();
39
+ #pendingSubmissions = /* @__PURE__ */ new Set();
39
40
  #composerSequence = 0;
40
41
  #modelRequestSequence = 0;
41
42
  #ownershipRequestSequence = 0;
@@ -95,6 +96,7 @@
95
96
  rebindConversation(composer, target) {
96
97
  if (!isConversationTarget(target)) return null;
97
98
  const previous = this.#state(composer);
99
+ this.#pendingSubmissions.delete(previous);
98
100
  this.#modelRequestGenerations.set(previous, ++this.#modelRequestSequence);
99
101
  this.#ownershipRequestGenerations.set(previous, ++this.#ownershipRequestSequence);
100
102
  let state = this.#conversationState(target);
@@ -114,6 +116,7 @@
114
116
  restore(composer, agent, model, thinkingOptionId, permissionModeId) {
115
117
  if (!this.#enabledAgents.has(agent)) return null;
116
118
  const state = this.#state(composer);
119
+ this.#pendingSubmissions.delete(state);
117
120
  state.agent = agent;
118
121
  state.phase = "locked";
119
122
  if (agent === "pi" && model) state.piModel = model;
@@ -204,9 +207,21 @@
204
207
  }
205
208
  lock(composer) {
206
209
  const state = this.#state(composer);
210
+ this.#pendingSubmissions.delete(state);
207
211
  state.phase = "locked";
208
212
  return state;
209
213
  }
214
+ markSubmissionPending(composer) {
215
+ const state = this.#state(composer);
216
+ if (state.phase === "draft") this.#pendingSubmissions.add(state);
217
+ return state;
218
+ }
219
+ isSubmissionPending(composer) {
220
+ return this.#pendingSubmissions.has(this.#state(composer));
221
+ }
222
+ clearPendingSubmission(composer) {
223
+ this.#pendingSubmissions.delete(this.#state(composer));
224
+ }
210
225
  recordSubmission(composer) {
211
226
  const state = this.#state(composer);
212
227
  this.#lastSubmittedAgent = state.agent;
@@ -224,6 +239,9 @@
224
239
  if (isConversationTarget(target) && !bound) {
225
240
  this.#conversationStates.push({ target, state });
226
241
  }
242
+ if (isConversationTarget(target) && this.#pendingSubmissions.delete(state)) {
243
+ state.phase = "locked";
244
+ }
227
245
  return true;
228
246
  }
229
247
  async switchAgent(composer, nextAgent, operations) {
@@ -231,6 +249,7 @@
231
249
  if (!this.#enabledAgents.has(nextAgent)) return false;
232
250
  if (state.phase !== "draft" || this.#switching.has(state)) return false;
233
251
  if (state.agent === nextAgent) return true;
252
+ this.#pendingSubmissions.delete(state);
234
253
  this.#switching.add(state);
235
254
  try {
236
255
  if (!operations.applyAgent(nextAgent)) return false;
@@ -15783,21 +15802,88 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15783
15802
  return view;
15784
15803
  }
15785
15804
 
15805
+ // src/renderer-model-picker-positioning.ts
15806
+ var MENU_GAP = 4;
15807
+ var MAIN_MENU_SIDE_OFFSET = 8;
15808
+ var COLLISION_PADDING = 8;
15809
+ var RENDERER_MODEL_PICKER_MAIN_MENU_WIDTH = 260;
15810
+ var RENDERER_MODEL_PICKER_MODEL_MENU_WIDTH = 280;
15811
+ var RENDERER_MODEL_PICKER_MODEL_MENU_MAX_HEIGHT = 360;
15812
+ function clampPosition(value, minimum, maximum) {
15813
+ return Math.min(Math.max(value, minimum), Math.max(minimum, maximum));
15814
+ }
15815
+ function fitWidth(preferredWidth, viewportWidth) {
15816
+ return Math.max(
15817
+ COLLISION_PADDING,
15818
+ Math.min(preferredWidth, viewportWidth - COLLISION_PADDING * 2)
15819
+ );
15820
+ }
15821
+ function fitHeight(viewport, top = COLLISION_PADDING) {
15822
+ return Math.max(
15823
+ COLLISION_PADDING,
15824
+ Math.min(
15825
+ RENDERER_MODEL_PICKER_MODEL_MENU_MAX_HEIGHT,
15826
+ viewport.height * 0.6,
15827
+ viewport.height - top - COLLISION_PADDING
15828
+ )
15829
+ );
15830
+ }
15831
+ function rendererModelPickerMainMenuPlacement(triggerRect, viewport, width = RENDERER_MODEL_PICKER_MAIN_MENU_WIDTH) {
15832
+ const maxLeft = viewport.width - COLLISION_PADDING - width;
15833
+ return {
15834
+ left: clampPosition(triggerRect.right - width, COLLISION_PADDING, maxLeft),
15835
+ width,
15836
+ bottom: Math.max(COLLISION_PADDING, viewport.height - triggerRect.top + MAIN_MENU_SIDE_OFFSET)
15837
+ };
15838
+ }
15839
+ function rendererModelPickerStandaloneModelMenuPlacement(triggerRect, viewport) {
15840
+ const width = fitWidth(RENDERER_MODEL_PICKER_MODEL_MENU_WIDTH, viewport.width);
15841
+ const maxLeft = viewport.width - COLLISION_PADDING - width;
15842
+ return {
15843
+ left: clampPosition(triggerRect.right - width, COLLISION_PADDING, maxLeft),
15844
+ width,
15845
+ maxHeight: fitHeight(viewport),
15846
+ bottom: Math.max(COLLISION_PADDING, viewport.height - triggerRect.top + MAIN_MENU_SIDE_OFFSET)
15847
+ };
15848
+ }
15849
+ function rendererModelPickerModelMenuPlacement(mainRect, viewport) {
15850
+ const preferredWidth = fitWidth(RENDERER_MODEL_PICKER_MODEL_MENU_WIDTH, viewport.width);
15851
+ const rightLeft = mainRect.right + MENU_GAP;
15852
+ const leftLeft = mainRect.left - MENU_GAP - preferredWidth;
15853
+ const rightAvailable = viewport.width - rightLeft - COLLISION_PADDING;
15854
+ const leftAvailable = mainRect.left - MENU_GAP - COLLISION_PADDING;
15855
+ let width;
15856
+ let left;
15857
+ if (rightAvailable >= preferredWidth) {
15858
+ width = preferredWidth;
15859
+ left = rightLeft;
15860
+ } else if (leftAvailable >= preferredWidth) {
15861
+ width = preferredWidth;
15862
+ left = leftLeft;
15863
+ } else if (rightAvailable >= leftAvailable) {
15864
+ width = Math.max(COLLISION_PADDING, rightAvailable);
15865
+ left = rightLeft;
15866
+ } else {
15867
+ width = Math.max(COLLISION_PADDING, leftAvailable);
15868
+ left = mainRect.left - MENU_GAP - width;
15869
+ }
15870
+ const top = clampPosition(mainRect.top, COLLISION_PADDING, viewport.height - COLLISION_PADDING);
15871
+ const maxHeight = fitHeight(viewport, top);
15872
+ return {
15873
+ left: clampPosition(left, COLLISION_PADDING, viewport.width - COLLISION_PADDING - width),
15874
+ top,
15875
+ width,
15876
+ maxHeight
15877
+ };
15878
+ }
15879
+
15786
15880
  // src/renderer-model-picker.ts
15787
15881
  var RENDERER_MODEL_TRIGGER_FALLBACK_CLASSES = "border-token-border no-drag cursor-interaction items-center gap-1 border whitespace-nowrap select-none focus:outline-none disabled:cursor-not-allowed disabled:opacity-40 flex rounded-full text-token-text-tertiary enabled:hover:bg-token-list-hover-background enabled:active:bg-token-foreground/15 data-[state=open]:bg-token-list-hover-background border-transparent h-token-button-composer px-2 py-0 text-sm leading-[18px] min-w-0";
15788
15882
  var MENU_CLASSES = "fixed z-50 overflow-hidden rounded-xl bg-token-dropdown-background/90 text-token-foreground shadow-lg backdrop-blur-xl";
15789
15883
  var SEARCH_INPUT_CLASSES = "mb-1 w-full shrink-0 rounded-lg border border-token-border bg-token-dropdown-background/95 px-2 py-1.5 text-sm text-token-foreground outline-none placeholder:text-token-text-tertiary disabled:cursor-not-allowed disabled:opacity-40";
15790
15884
  var OPTION_CLASSES = "flex w-full cursor-interaction items-center gap-2 rounded-lg px-2 py-2 text-left text-sm text-token-foreground outline-none enabled:hover:bg-token-list-hover-background enabled:active:bg-token-foreground/15 disabled:cursor-not-allowed disabled:opacity-40";
15791
15885
  var HEADING_CLASSES = "px-2 pb-1 pt-1.5 text-sm text-token-text-tertiary";
15792
- var MAIN_MENU_MIN_WIDTH = 160;
15793
- var MAIN_MENU_MAX_WIDTH = 180;
15794
- var MODEL_MENU_PREFERRED_WIDTH = 360;
15795
- var MODEL_MENU_MAX_WIDTH = 420;
15796
- var MODEL_MENU_MAX_HEIGHT = 360;
15797
15886
  var MODEL_TRIGGER_MAX_WIDTH = "min(200px, 26vw)";
15798
- var MAIN_MENU_LEFT_OFFSET = 96;
15799
- var MENU_GAP = 4;
15800
- var VIEWPORT_MARGIN = 8;
15801
15887
  var MODEL_SCROLLBAR_STYLE_ATTRIBUTE = "data-codexhost-model-picker-scrollbar";
15802
15888
  function popoverOpen2(menu) {
15803
15889
  return menu.matches(":popover-open");
@@ -15877,47 +15963,38 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
15877
15963
  }
15878
15964
  function positionMainMenu(control) {
15879
15965
  const triggerRect = control.trigger.getBoundingClientRect();
15880
- const width = Math.min(MAIN_MENU_MAX_WIDTH, Math.max(MAIN_MENU_MIN_WIDTH, triggerRect.width));
15881
- const modelMenuWidth = Math.min(
15882
- MODEL_MENU_MAX_WIDTH,
15883
- Math.min(MODEL_MENU_PREFERRED_WIDTH, window.innerWidth - VIEWPORT_MARGIN * 2)
15966
+ const placement = rendererModelPickerMainMenuPlacement(
15967
+ triggerRect,
15968
+ { width: window.innerWidth, height: window.innerHeight },
15969
+ RENDERER_MODEL_PICKER_MAIN_MENU_WIDTH
15884
15970
  );
15885
- const preferredLeft = triggerRect.right - width - MAIN_MENU_LEFT_OFFSET;
15886
- const rightReservedLeft = window.innerWidth - VIEWPORT_MARGIN - modelMenuWidth - MENU_GAP - width;
15887
- const maxLeft = window.innerWidth - VIEWPORT_MARGIN - width;
15888
- const left = Math.max(
15889
- VIEWPORT_MARGIN,
15890
- Math.min(preferredLeft, Math.max(rightReservedLeft, VIEWPORT_MARGIN), maxLeft)
15891
- );
15892
- control.menu.style.setProperty("width", `${width}px`, "important");
15893
- control.menu.style.left = `${left}px`;
15894
- control.menu.style.maxWidth = `${width}px`;
15971
+ control.menu.style.setProperty("width", `${placement.width}px`, "important");
15972
+ control.menu.style.left = `${placement.left}px`;
15973
+ control.menu.style.maxWidth = `${placement.width}px`;
15895
15974
  control.menu.style.right = "auto";
15896
15975
  control.menu.style.top = "auto";
15897
- control.menu.style.bottom = `${Math.max(
15898
- VIEWPORT_MARGIN,
15899
- window.innerHeight - triggerRect.top + 6
15900
- )}px`;
15901
- }
15902
- function positionModelMenu(control) {
15903
- const mainRect = control.menu.getBoundingClientRect();
15904
- const availableRight = window.innerWidth - mainRect.right - VIEWPORT_MARGIN;
15905
- const width = Math.min(MODEL_MENU_MAX_WIDTH, Math.max(VIEWPORT_MARGIN, availableRight));
15906
- const left = mainRect.right + MENU_GAP;
15907
- control.modelMenu.style.setProperty("width", `${width}px`, "important");
15908
- control.modelMenu.style.left = `${left}px`;
15909
- control.modelMenu.style.maxWidth = `${width}px`;
15910
- const maxHeight = Math.max(
15911
- VIEWPORT_MARGIN,
15912
- Math.min(MODEL_MENU_MAX_HEIGHT, window.innerHeight * 0.6, mainRect.bottom - VIEWPORT_MARGIN)
15913
- );
15914
- control.modelMenu.style.maxHeight = `${maxHeight}px`;
15976
+ control.menu.style.bottom = `${placement.bottom}px`;
15977
+ }
15978
+ function positionAdvancedMenus(control) {
15979
+ positionMainMenu(control);
15980
+ positionModelMenu(control);
15981
+ }
15982
+ function positionModelMenu(control, standalone = false) {
15983
+ const anchorRect = standalone ? control.trigger.getBoundingClientRect() : control.menu.getBoundingClientRect();
15984
+ const placement = standalone ? rendererModelPickerStandaloneModelMenuPlacement(anchorRect, {
15985
+ width: window.innerWidth,
15986
+ height: window.innerHeight
15987
+ }) : rendererModelPickerModelMenuPlacement(anchorRect, {
15988
+ width: window.innerWidth,
15989
+ height: window.innerHeight
15990
+ });
15991
+ control.modelMenu.style.setProperty("width", `${placement.width}px`, "important");
15992
+ control.modelMenu.style.left = `${placement.left}px`;
15993
+ control.modelMenu.style.maxWidth = `${placement.width}px`;
15994
+ control.modelMenu.style.maxHeight = `${placement.maxHeight}px`;
15915
15995
  control.modelMenu.style.right = "auto";
15916
- control.modelMenu.style.top = "auto";
15917
- control.modelMenu.style.bottom = `${Math.max(
15918
- VIEWPORT_MARGIN,
15919
- window.innerHeight - mainRect.bottom
15920
- )}px`;
15996
+ control.modelMenu.style.top = placement.top === void 0 ? "auto" : `${placement.top}px`;
15997
+ control.modelMenu.style.bottom = placement.bottom === void 0 ? "auto" : `${placement.bottom}px`;
15921
15998
  }
15922
15999
  function syncRendererModelTriggerClass(control, nativeClassName) {
15923
16000
  control.trigger.className = nativeClassName?.trim() || RENDERER_MODEL_TRIGGER_FALLBACK_CLASSES;
@@ -16012,7 +16089,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16012
16089
  modelMenu.style.margin = "0";
16013
16090
  modelMenu.style.padding = "4px";
16014
16091
  modelMenu.style.border = "0";
16015
- modelMenu.style.maxHeight = "min(360px, 60vh)";
16092
+ modelMenu.style.maxHeight = `min(${RENDERER_MODEL_PICKER_MODEL_MENU_MAX_HEIGHT}px, 60vh)`;
16016
16093
  modelMenu.style.overflowY = "auto";
16017
16094
  modelButton.setAttribute("aria-controls", modelMenu.id);
16018
16095
  const options = /* @__PURE__ */ new Map();
@@ -16073,33 +16150,41 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16073
16150
  applyModelSearchFilter(control);
16074
16151
  }
16075
16152
  };
16153
+ const pickerOpen = () => popoverOpen2(menu) || popoverOpen2(modelMenu);
16076
16154
  const close = () => {
16077
16155
  closeModelMenu();
16078
16156
  if (popoverOpen2(menu)) menu.hidePopover();
16079
16157
  };
16080
- const openModelMenu = () => {
16081
- if (!popoverOpen2(menu) || popoverOpen2(modelMenu)) return;
16158
+ const openModelMenu = (standalone = false) => {
16159
+ if (!standalone && !popoverOpen2(menu) || popoverOpen2(modelMenu)) return;
16082
16160
  modelMenu.showPopover();
16083
- positionModelMenu(control);
16161
+ positionModelMenu(control, standalone);
16084
16162
  modelButton.setAttribute("aria-expanded", "true");
16085
16163
  };
16086
16164
  const open = () => {
16087
- if (trigger.disabled || popoverOpen2(menu)) return;
16165
+ if (trigger.disabled || pickerOpen()) return;
16166
+ if (control.thinkingOptions.size === 0) {
16167
+ openModelMenu(true);
16168
+ return;
16169
+ }
16088
16170
  menu.showPopover();
16089
- positionMainMenu(control);
16171
+ positionAdvancedMenus(control);
16090
16172
  };
16091
16173
  const onTriggerClick = () => {
16092
- if (popoverOpen2(menu)) close();
16174
+ if (pickerOpen()) close();
16093
16175
  else open();
16094
16176
  };
16095
16177
  const onToggle = () => {
16096
16178
  const openState = popoverOpen2(menu);
16097
- trigger.setAttribute("aria-expanded", String(openState));
16179
+ trigger.setAttribute("aria-expanded", String(openState || popoverOpen2(modelMenu)));
16098
16180
  trigger.setAttribute("data-state", openState ? "open" : "closed");
16099
16181
  if (!openState) closeModelMenu();
16100
16182
  };
16101
16183
  const onModelToggle = () => {
16102
- modelButton.setAttribute("aria-expanded", String(popoverOpen2(modelMenu)));
16184
+ const openState = popoverOpen2(modelMenu);
16185
+ modelButton.setAttribute("aria-expanded", String(openState));
16186
+ trigger.setAttribute("aria-expanded", String(openState || popoverOpen2(menu)));
16187
+ trigger.setAttribute("data-state", openState || popoverOpen2(menu) ? "open" : "closed");
16103
16188
  };
16104
16189
  const onRootClick = (event) => {
16105
16190
  const target = event.target instanceof Element ? event.target.closest("button") : null;
@@ -16138,21 +16223,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16138
16223
  trigger.focus();
16139
16224
  };
16140
16225
  const onViewportChange = () => {
16141
- if (popoverOpen2(menu)) positionMainMenu(control);
16142
- if (popoverOpen2(modelMenu)) positionModelMenu(control);
16226
+ if (popoverOpen2(menu)) positionAdvancedMenus(control);
16227
+ else if (popoverOpen2(modelMenu)) positionModelMenu(control, true);
16143
16228
  };
16144
16229
  trigger.addEventListener("click", onTriggerClick);
16145
16230
  menu.addEventListener("toggle", onToggle);
16146
16231
  modelMenu.addEventListener("toggle", onModelToggle);
16147
16232
  modelButton.addEventListener("mouseenter", onModelHover);
16148
- root.addEventListener("click", onRootClick);
16233
+ menu.addEventListener("click", onRootClick);
16149
16234
  modelMenu.addEventListener("click", onModelMenuClick);
16150
16235
  document.addEventListener("pointerdown", onDocumentPointerDown, true);
16151
16236
  document.addEventListener("keydown", onDocumentKeyDown, true);
16152
16237
  window.addEventListener("resize", onViewportChange);
16153
16238
  window.addEventListener("scroll", onViewportChange, true);
16154
- root.append(trigger, menu);
16155
- document.body.append(modelMenu);
16239
+ root.append(trigger);
16240
+ document.body.append(menu, modelMenu);
16156
16241
  searchHeader.append(searchInput);
16157
16242
  modelMenu.append(searchHeader, searchEmpty);
16158
16243
  const control = {
@@ -16175,7 +16260,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16175
16260
  menu.removeEventListener("toggle", onToggle);
16176
16261
  modelMenu.removeEventListener("toggle", onModelToggle);
16177
16262
  modelButton.removeEventListener("mouseenter", onModelHover);
16178
- root.removeEventListener("click", onRootClick);
16263
+ menu.removeEventListener("click", onRootClick);
16179
16264
  modelMenu.removeEventListener("click", onModelMenuClick);
16180
16265
  searchInput.removeEventListener("input", onSearchInput);
16181
16266
  for (const type of silencedEventTypes) {
@@ -16186,6 +16271,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
16186
16271
  document.removeEventListener("keydown", onDocumentKeyDown, true);
16187
16272
  window.removeEventListener("resize", onViewportChange);
16188
16273
  window.removeEventListener("scroll", onViewportChange, true);
16274
+ menu.remove();
16189
16275
  modelMenu.remove();
16190
16276
  root.remove();
16191
16277
  }
@@ -17138,7 +17224,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17138
17224
  var CONTROL_ATTRIBUTE2 = "data-codexhost-harness-command-control";
17139
17225
  var MENU_ATTRIBUTE = "data-codexhost-harness-command-menu";
17140
17226
  var MENU_WIDTH = 320;
17141
- var VIEWPORT_MARGIN2 = 8;
17227
+ var VIEWPORT_MARGIN = 8;
17142
17228
  var MENU_GAP2 = 8;
17143
17229
  var SVG_NS = "http://www.w3.org/2000/svg";
17144
17230
  var COMMAND_ICON_PATHS = [
@@ -17254,7 +17340,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17254
17340
  menu.style.inset = "auto";
17255
17341
  menu.style.zIndex = "2147483647";
17256
17342
  menu.style.width = `${MENU_WIDTH}px`;
17257
- menu.style.maxWidth = `calc(100vw - ${VIEWPORT_MARGIN2 * 2}px)`;
17343
+ menu.style.maxWidth = `calc(100vw - ${VIEWPORT_MARGIN * 2}px)`;
17258
17344
  menu.style.maxHeight = "min(360px, calc(100vh - 16px))";
17259
17345
  menu.style.overflowY = "auto";
17260
17346
  menu.style.padding = "4px";
@@ -17275,14 +17361,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17275
17361
  const positionMenu2 = () => {
17276
17362
  const rect = trigger.getBoundingClientRect();
17277
17363
  const menuHeight = menu.getBoundingClientRect().height;
17278
- const opensAbove = rect.top >= menuHeight + MENU_GAP2 + VIEWPORT_MARGIN2;
17364
+ const opensAbove = rect.top >= menuHeight + MENU_GAP2 + VIEWPORT_MARGIN;
17279
17365
  const left = clamp(
17280
17366
  rect.left,
17281
- VIEWPORT_MARGIN2,
17282
- window.innerWidth - MENU_WIDTH - VIEWPORT_MARGIN2
17367
+ VIEWPORT_MARGIN,
17368
+ window.innerWidth - MENU_WIDTH - VIEWPORT_MARGIN
17283
17369
  );
17284
17370
  menu.style.left = `${left}px`;
17285
- menu.style.top = opensAbove ? `${Math.max(VIEWPORT_MARGIN2, rect.top - menuHeight - MENU_GAP2)}px` : `${Math.min(window.innerHeight - menuHeight - VIEWPORT_MARGIN2, rect.bottom + MENU_GAP2)}px`;
17371
+ menu.style.top = opensAbove ? `${Math.max(VIEWPORT_MARGIN, rect.top - menuHeight - MENU_GAP2)}px` : `${Math.min(window.innerHeight - menuHeight - VIEWPORT_MARGIN, rect.bottom + MENU_GAP2)}px`;
17286
17372
  };
17287
17373
  const focusActive = () => {
17288
17374
  const item = items[activeIndex];
@@ -17457,23 +17543,86 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17457
17543
  if (target instanceof Element) return target;
17458
17544
  return target instanceof Node ? target.parentElement : null;
17459
17545
  }
17546
+ function controlDescription(element) {
17547
+ const typed = element;
17548
+ const read = (name) => typeof element.getAttribute === "function" ? element.getAttribute(name) : null;
17549
+ return [typed.type, read("aria-label"), read("title"), read("data-testid")].filter((value) => typeof value === "string").join(" ").toLowerCase();
17550
+ }
17460
17551
  function buttonText(button) {
17461
- return [
17462
- button.type,
17463
- button.getAttribute("aria-label"),
17464
- button.getAttribute("title"),
17465
- button.getAttribute("data-testid")
17466
- ].filter((value) => typeof value === "string").join(" ").toLowerCase();
17552
+ return controlDescription(button);
17553
+ }
17554
+ function isOwnedRendererControl(element) {
17555
+ return element.hasAttribute(CONTROL_ATTRIBUTE) || element.hasAttribute("data-codexhost-model-control") || element.hasAttribute("data-codexhost-permission-mode-control") || element.hasAttribute("data-codexhost-usage-control") || element.hasAttribute("data-codexhost-credits-control") || element.hasAttribute("data-codexhost-harness-command-control");
17467
17556
  }
17468
17557
  function isComposerSubmitButton(button) {
17469
17558
  if (button.type === "submit") return true;
17470
17559
  return /(^|\s)(send|submit|发送|提交)(\s|$)/u.test(buttonText(button));
17471
17560
  }
17561
+ var VOICE_CONTROL_PATTERN = /(dictat|microphone|speech(?:[-_\s]?to[-_\s]?text)?|voice[-_\s]?input|(^|\s)voice(\s|$)|composer[-_](?:speech|dictat|mic)|语音|听写|麦克风|pause|暂停|stop recording|stop dictation|停止录音|停止听写|(^|\s)stop(\s|$))/iu;
17562
+ var CANCEL_CONTROL_PATTERN = /(cancel|discard|close|dismiss|取消|关闭|丢弃)/iu;
17563
+ var ATTACH_CONTROL_PATTERN = /(add files|attach files|attach file|attachment|composer[-_]attach|添加文件|附件)/iu;
17564
+ var TRAILING_ACTION_WALK_DEPTH = 3;
17565
+ function isComposerCancelButton(element) {
17566
+ if (isOwnedRendererControl(element)) return false;
17567
+ return CANCEL_CONTROL_PATTERN.test(controlDescription(element));
17568
+ }
17569
+ function isComposerVoiceButton(element) {
17570
+ if (isOwnedRendererControl(element) || isComposerCancelButton(element)) return false;
17571
+ const description = controlDescription(element);
17572
+ if (/(^|\s)(send|submit|发送|提交)(\s|$)/u.test(description)) return false;
17573
+ return VOICE_CONTROL_PATTERN.test(description);
17574
+ }
17575
+ function isComposerAttachButton(element) {
17576
+ if (isOwnedRendererControl(element)) return false;
17577
+ return ATTACH_CONTROL_PATTERN.test(controlDescription(element));
17578
+ }
17579
+ function isComposerTrailingActionButton(element) {
17580
+ return isComposerVoiceButton(element) || isComposerSubmitButton(element);
17581
+ }
17582
+ function isTrailingActionNode(element) {
17583
+ if (isComposerCancelButton(element)) return false;
17584
+ if (isComposerTrailingActionButton(element)) return true;
17585
+ if (typeof element.querySelectorAll !== "function") return false;
17586
+ const buttons = [...element.querySelectorAll("button")];
17587
+ return buttons.length > 0 && buttons.every((button) => isComposerTrailingActionButton(button));
17588
+ }
17589
+ function attachControlWithin(root) {
17590
+ if (isComposerAttachButton(root)) return root;
17591
+ if (typeof root.querySelectorAll !== "function") return null;
17592
+ const matches = [
17593
+ ...root.querySelectorAll("button, [aria-label], [title], [data-testid]")
17594
+ ].filter(isComposerAttachButton);
17595
+ return matches.length === 1 ? matches[0] ?? null : null;
17596
+ }
17472
17597
  function sendButtonWithin(root) {
17473
17598
  return [...root.querySelectorAll("button")].find(
17474
17599
  (button) => isComposerSubmitButton(button)
17475
17600
  ) ?? null;
17476
17601
  }
17602
+ function leftmostTrailingSibling(container, before) {
17603
+ for (const child of container.children) {
17604
+ if (child === before) break;
17605
+ if (typeof child.hasAttribute !== "function") continue;
17606
+ const element = child;
17607
+ if (isOwnedRendererControl(element) || isComposerCancelButton(element)) continue;
17608
+ if (isTrailingActionNode(element)) return element;
17609
+ }
17610
+ return null;
17611
+ }
17612
+ function trailingActionAnchor(sendButton) {
17613
+ let container = sendButton.parentElement;
17614
+ let before = sendButton;
17615
+ for (let depth = 0; container && depth < TRAILING_ACTION_WALK_DEPTH; depth += 1) {
17616
+ if (typeof container.matches === "function" && container.matches(CODEX_COMPOSER_SELECTOR)) {
17617
+ break;
17618
+ }
17619
+ const candidate = leftmostTrailingSibling(container, before);
17620
+ if (candidate) return candidate;
17621
+ before = container;
17622
+ container = container.parentElement;
17623
+ }
17624
+ return sendButton;
17625
+ }
17477
17626
  function editorForElement(element) {
17478
17627
  return element.matches(EDITOR_SELECTOR) ? element : element.closest(EDITOR_SELECTOR);
17479
17628
  }
@@ -17619,7 +17768,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17619
17768
  for (const child of parent.children) {
17620
17769
  if (typeof child.hasAttribute !== "function") continue;
17621
17770
  const element = child;
17622
- if (element.hasAttribute("data-codexhost-credits-control") || element.hasAttribute("data-codexhost-harness-command-control")) {
17771
+ if (element.hasAttribute("data-codexhost-credits-control") || element.hasAttribute("data-codexhost-harness-command-control") || isTrailingActionNode(element)) {
17623
17772
  continue;
17624
17773
  }
17625
17774
  return element;
@@ -17632,12 +17781,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17632
17781
  const parent = current.parentElement;
17633
17782
  if (!parent) break;
17634
17783
  const first = firstMaterialChild(parent);
17635
- if (first && first !== current && !first.contains(usageRoot)) return first;
17784
+ if (first && first !== current && !first.contains(usageRoot)) {
17785
+ return attachControlWithin(first) ?? first;
17786
+ }
17636
17787
  if (parent === composer) break;
17637
17788
  current = parent;
17638
17789
  }
17639
17790
  return null;
17640
17791
  }
17792
+ function refreshTrailingClusterPlacement(control) {
17793
+ const sendButton = control.sendButton;
17794
+ const modelRoot = control.modelPicker?.root;
17795
+ const agentRoot = control.root ?? control.picker?.root;
17796
+ if (!sendButton || !modelRoot || !agentRoot) return;
17797
+ const anchor = trailingActionAnchor(sendButton);
17798
+ const parent = anchor.parentElement;
17799
+ if (!parent || typeof parent.insertBefore !== "function") return;
17800
+ if (modelRoot.parentElement === parent && agentRoot.parentElement === parent && modelRoot.nextElementSibling === agentRoot && agentRoot.nextElementSibling === anchor) {
17801
+ return;
17802
+ }
17803
+ parent.insertBefore(modelRoot, anchor);
17804
+ parent.insertBefore(agentRoot, anchor);
17805
+ }
17641
17806
  function refreshUsagePlacement(control) {
17642
17807
  const anchor = usagePlacementAnchor(control);
17643
17808
  if (!anchor) {
@@ -17690,6 +17855,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17690
17855
  }
17691
17856
  function reconcileComposerNativeControls(control, hideModel, hidePermissionMode) {
17692
17857
  refreshNativeModelControl(control);
17858
+ refreshTrailingClusterPlacement(control);
17693
17859
  refreshUsagePlacement(control);
17694
17860
  refreshNativePermissionModeControl(control);
17695
17861
  setNativeControlHidden(control.nativeModelControl, hideModel);
@@ -17717,7 +17883,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17717
17883
  const toolbar = sendButton.parentElement;
17718
17884
  const harnessCommands = mountRendererHarnessCommandControl(
17719
17885
  toolbar ?? composer,
17720
- sendButton,
17886
+ trailingActionAnchor(sendButton),
17721
17887
  onSelectCommand
17722
17888
  );
17723
17889
  const permissionParent = nativePermissionModeControl?.element.parentElement;
@@ -17726,12 +17892,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17726
17892
  } else {
17727
17893
  composer.append(permissionModePicker.root);
17728
17894
  }
17729
- if (toolbar) {
17730
- toolbar.insertBefore(modelPicker.root, sendButton);
17731
- toolbar.insertBefore(picker.root, sendButton);
17732
- } else {
17733
- composer.append(modelPicker.root, picker.root);
17734
- }
17895
+ if (!toolbar) composer.append(modelPicker.root, picker.root);
17735
17896
  const control = {
17736
17897
  composer,
17737
17898
  root: picker.root,
@@ -17747,6 +17908,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
17747
17908
  sendButton,
17748
17909
  sendDisabledBeforeSwitch: null
17749
17910
  };
17911
+ refreshTrailingClusterPlacement(control);
17750
17912
  refreshUsagePlacement(control);
17751
17913
  return control;
17752
17914
  }
@@ -18467,28 +18629,38 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18467
18629
  }
18468
18630
  return `${CLAUDE_CODE_TRANSPORT_MODEL_PREFIX}${parsedModel.id}${parsedPermissionMode ? `@${parsedPermissionMode}` : ""}`;
18469
18631
  }
18470
- function grokTransportModelId(model, thinkingOptionId) {
18632
+ function grokTransportModelId(model, permissionModeId, thinkingOptionId) {
18471
18633
  if (!model) {
18472
- if (thinkingOptionId) throw new Error("Grok transport Thinking requires a Model Ref");
18634
+ if (permissionModeId || thinkingOptionId) {
18635
+ throw new Error("Grok transport configuration requires a Model Ref");
18636
+ }
18473
18637
  return GROK_TRANSPORT_MODEL_ID;
18474
18638
  }
18475
18639
  const parsedModel = harnessModelRefSchema.parse(model);
18640
+ const parsedPermissionMode = permissionModeId ? harnessPermissionModeIdSchema.parse(permissionModeId) : void 0;
18476
18641
  const parsedThinking = thinkingOptionId ? harnessThinkingOptionIdSchema.parse(thinkingOptionId) : void 0;
18477
- return `${GROK_TRANSPORT_MODEL_PREFIX}${parsedModel.id}${parsedThinking ? `@@${parsedThinking}` : ""}`;
18642
+ if (parsedThinking) {
18643
+ return `${GROK_TRANSPORT_MODEL_PREFIX}${parsedModel.id}@${parsedPermissionMode ?? ""}@${parsedThinking}`;
18644
+ }
18645
+ return `${GROK_TRANSPORT_MODEL_PREFIX}${parsedModel.id}${parsedPermissionMode ? `@${parsedPermissionMode}` : ""}`;
18478
18646
  }
18479
18647
  function decodeGrokTransportModelId(value) {
18480
18648
  if (value === GROK_TRANSPORT_MODEL_ID) return {};
18481
18649
  if (typeof value !== "string" || !value.startsWith(GROK_TRANSPORT_MODEL_PREFIX)) return null;
18482
18650
  const components = value.slice(GROK_TRANSPORT_MODEL_PREFIX.length).split("@");
18483
- if (components.length !== 1 && components.length !== 3) return null;
18484
- const [modelId, emptyPermissionMode, thinkingOptionId] = components;
18485
- if (components.length === 3 && (emptyPermissionMode !== "" || !thinkingOptionId)) return null;
18651
+ if (components.length < 1 || components.length > 3) return null;
18652
+ const [modelId, permissionModeId, thinkingOptionId] = components;
18653
+ if (components.length === 2 && !permissionModeId) return null;
18654
+ if (components.length === 3 && !thinkingOptionId) return null;
18486
18655
  const model = harnessModelRefSchema.safeParse({ id: modelId });
18487
18656
  if (!model.success) return null;
18657
+ const permissionMode = permissionModeId ? harnessPermissionModeIdSchema.safeParse(permissionModeId) : null;
18658
+ if (permissionMode && !permissionMode.success) return null;
18488
18659
  const thinking = thinkingOptionId ? harnessThinkingOptionIdSchema.safeParse(thinkingOptionId) : null;
18489
18660
  if (thinking && !thinking.success) return null;
18490
18661
  return {
18491
18662
  model: model.data,
18663
+ ...permissionMode?.success ? { permissionModeId: permissionMode.data } : {},
18492
18664
  ...thinking?.success ? { thinkingOptionId: thinking.data } : {}
18493
18665
  };
18494
18666
  }
@@ -18560,7 +18732,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18560
18732
  }
18561
18733
  function matchesCurrentPrewarmSignature(target) {
18562
18734
  const bridge = target.requestClient ?? target;
18563
- const stableApiShape = bridge.hostId === "local" && typeof bridge.sendRequest === "function" && typeof bridge.prewarmThreadStart === "function" && typeof bridge.enqueueRequest === "function";
18735
+ const stableApiShape = typeof bridge.hostId === "string" && bridge.hostId.length > 0 && typeof bridge.sendRequest === "function" && typeof bridge.prewarmThreadStart === "function" && typeof bridge.enqueueRequest === "function";
18564
18736
  if (stableApiShape) return true;
18565
18737
  const prewarm = target.prewarmThreadStart ?? target.requestClient?.prewarmThreadStart;
18566
18738
  if (!prewarm) return false;
@@ -18651,10 +18823,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18651
18823
  return false;
18652
18824
  }
18653
18825
  }
18654
- function findComposerModelTarget(composer) {
18655
- const conversationThreadId = findComposerConversationThreadId(composer);
18656
- if (conversationThreadId === null) return null;
18657
- if (conversationThreadId !== void 0) return ["conversation", conversationThreadId];
18826
+ function findComposerDomIdentity(composer) {
18827
+ const children = Array.from(composer.children ?? []);
18828
+ const portals = children.filter((child) => child.hasAttribute("data-above-composer-portal"));
18829
+ if (portals.length === 0) return { kind: "unsupported" };
18830
+ if (portals.length !== 1) return { kind: "ambiguous" };
18831
+ const value = portals[0]?.getAttribute("data-above-composer-conversation-id");
18832
+ if (value === null) return { kind: "draft" };
18833
+ const candidate = hostThreadIdSchema.safeParse(value);
18834
+ return candidate.success ? { kind: "conversation", threadId: candidate.data } : { kind: "ambiguous" };
18835
+ }
18836
+ function findComposerDraftIds(composer) {
18658
18837
  const draftIds = /* @__PURE__ */ new Set();
18659
18838
  let fiber = findComposerFiber(composer);
18660
18839
  for (let depth = 0; fiber && depth < 120; depth += 1) {
@@ -18669,6 +18848,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18669
18848
  const parent = fiber.return;
18670
18849
  fiber = (typeof parent === "object" || typeof parent === "function") && parent !== null ? parent : null;
18671
18850
  }
18851
+ return draftIds;
18852
+ }
18853
+ function findComposerModelTarget(composer) {
18854
+ const draftIds = findComposerDraftIds(composer);
18855
+ const domIdentity = findComposerDomIdentity(composer);
18856
+ if (domIdentity.kind === "ambiguous") return null;
18857
+ if (domIdentity.kind === "conversation") {
18858
+ return ["conversation", domIdentity.threadId];
18859
+ }
18860
+ if (domIdentity.kind === "draft") {
18861
+ return draftIds.size === 1 ? ["default", draftIds.values().next().value] : null;
18862
+ }
18863
+ const conversationThreadId = findComposerConversationThreadId(composer);
18864
+ if (conversationThreadId === null) return null;
18865
+ if (conversationThreadId !== void 0) return ["conversation", conversationThreadId];
18672
18866
  if (draftIds.size !== 1) return null;
18673
18867
  return ["default", draftIds.values().next().value];
18674
18868
  }
@@ -18676,7 +18870,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18676
18870
  return isRecord5(value) && value.state === "ready";
18677
18871
  }
18678
18872
  function isDraftPrewarmPolicyReady(value) {
18679
- return isRecord5(value) && value.state === "ready" && typeof value.select === "function" && typeof value.clear === "function";
18873
+ return isRecord5(value) && value.state === "ready" && typeof value.hostId === "string" && value.hostId.length > 0 && typeof value.select === "function" && typeof value.clear === "function";
18874
+ }
18875
+ function activeRendererDraftPrewarmTargets(policy, targets) {
18876
+ if (!isDraftPrewarmPolicyReady(policy)) return null;
18877
+ const activeTargets = targets.filter((target) => {
18878
+ const bridge = target.requestClient ?? target;
18879
+ return (target.getHostId?.() ?? bridge.hostId) === policy.hostId;
18880
+ });
18881
+ return activeTargets.length === 1 ? activeTargets : null;
18882
+ }
18883
+ function resolveRendererRequestRoute(policy, discoveredTargets, previous) {
18884
+ const activeTargets = activeRendererDraftPrewarmTargets(policy, discoveredTargets);
18885
+ if (isDraftPrewarmPolicyReady(policy) && activeTargets) {
18886
+ return { policy, targets: activeTargets };
18887
+ }
18888
+ return discoveredTargets.length === 0 && isDraftPrewarmPolicyReady(policy) && previous?.policy === policy ? previous : null;
18889
+ }
18890
+ function createRendererRequestRouteResolver(readPolicy, discoverTargets) {
18891
+ let route = null;
18892
+ return {
18893
+ resolve() {
18894
+ route = resolveRendererRequestRoute(readPolicy(), discoverTargets(), route);
18895
+ return route;
18896
+ },
18897
+ clear() {
18898
+ route = null;
18899
+ }
18900
+ };
18680
18901
  }
18681
18902
  async function waitForRendererDraftPrewarmPolicy(target) {
18682
18903
  const deadline = Date.now() + DRAFT_PREWARM_POLICY_WAIT_TIMEOUT_MS;
@@ -18691,7 +18912,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18691
18912
  }
18692
18913
  }
18693
18914
  function modelSelectionForAgent(officialSelection, reasoningEffort, agent, model, thinkingOptionId, permissionModeId) {
18694
- const transportModelId = agent === "pi" ? piTransportModelId(model, thinkingOptionId) : agent === "claude-code" ? claudeTransportModelId(model, permissionModeId, thinkingOptionId) : agent === "deepseek-harness" ? deepSeekHarnessTransportModelId(model) : agent === "grok" ? grokTransportModelId(model, thinkingOptionId) : transportModelIdForAgent(agent);
18915
+ const transportModelId = agent === "pi" ? piTransportModelId(model, thinkingOptionId) : agent === "claude-code" ? claudeTransportModelId(model, permissionModeId, thinkingOptionId) : agent === "deepseek-harness" ? deepSeekHarnessTransportModelId(model) : agent === "grok" ? grokTransportModelId(model, permissionModeId, thinkingOptionId) : transportModelIdForAgent(agent);
18695
18916
  return transportModelId ? { model: transportModelId, reasoningEffort } : officialSelection;
18696
18917
  }
18697
18918
  function installCurrentRendererAdapter() {
@@ -18717,8 +18938,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18717
18938
  }
18718
18939
  });
18719
18940
  const usageSubscription = createThreadUsageSubscriptionRelay();
18941
+ const requestRouteResolver = createRendererRequestRouteResolver(
18942
+ () => window.__codexhostDraftPrewarmPolicyV1,
18943
+ () => findActivePrewarmTargets(document)
18944
+ );
18945
+ const currentRequestRoute = () => requestRouteResolver.resolve();
18720
18946
  const currentModelClient = () => {
18721
- const client = createRendererModelClient(findActivePrewarmTargets(document));
18947
+ const client = createRendererModelClient(currentRequestRoute()?.targets ?? []);
18722
18948
  if (!client) throw new Error("Renderer Model request manager is unavailable");
18723
18949
  usageSubscription.connect(client);
18724
18950
  return client;
@@ -18754,10 +18980,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18754
18980
  });
18755
18981
  let routingPolicy = null;
18756
18982
  let policyTimer = null;
18983
+ let desiredCarrier = null;
18757
18984
  const captureRoutingPolicy = () => {
18758
- const discovered = window.__codexhostDraftPrewarmPolicyV1;
18759
- if (!isDraftPrewarmPolicyReady(discovered)) return false;
18760
- routingPolicy = discovered;
18985
+ const route = currentRequestRoute();
18986
+ if (!route) return false;
18987
+ routingPolicy = route.policy;
18988
+ routingPolicy.select(desiredCarrier);
18761
18989
  if (policyTimer !== null) {
18762
18990
  window.clearInterval(policyTimer);
18763
18991
  policyTimer = null;
@@ -18769,8 +18997,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18769
18997
  updateStatus("installing", "draft-routing-policy-unavailable", null);
18770
18998
  policyTimer = window.setInterval(captureRoutingPolicy, DRAFT_PREWARM_POLICY_POLL_INTERVAL_MS);
18771
18999
  }
19000
+ const handleRoutingPolicyChange = () => {
19001
+ captureRoutingPolicy();
19002
+ };
19003
+ window.addEventListener("codexhost:draft-prewarm-policy-changed", handleRoutingPolicyChange);
18772
19004
  const applyAgent = (agent, model, thinkingOptionId, permissionModeId) => {
18773
- if (disposed || routingPolicy === null) return false;
19005
+ if (disposed) return false;
18774
19006
  const selection = modelSelectionForAgent(
18775
19007
  null,
18776
19008
  null,
@@ -18781,7 +19013,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18781
19013
  );
18782
19014
  const carrier = selection?.model;
18783
19015
  if (carrier !== null && carrier !== void 0 && typeof carrier !== "string") return false;
18784
- if (routingPolicy.select(carrier ?? null)) {
19016
+ desiredCarrier = carrier ?? null;
19017
+ const route = currentRequestRoute();
19018
+ if (!route) return false;
19019
+ routingPolicy = route.policy;
19020
+ if (route.policy.select(desiredCarrier)) {
18785
19021
  modelUpdates += 1;
18786
19022
  liveStatus.modelUpdates = modelUpdates;
18787
19023
  }
@@ -18795,8 +19031,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18795
19031
  if (disposed) return;
18796
19032
  disposed = true;
18797
19033
  if (policyTimer !== null) window.clearInterval(policyTimer);
19034
+ window.removeEventListener(
19035
+ "codexhost:draft-prewarm-policy-changed",
19036
+ handleRoutingPolicyChange
19037
+ );
18798
19038
  routingPolicy?.select(null);
18799
19039
  routingPolicy = null;
19040
+ requestRouteResolver.clear();
18800
19041
  forkControl.dispose();
18801
19042
  usageSubscription.dispose();
18802
19043
  }
@@ -18848,9 +19089,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18848
19089
  const model = harnessModelRefSchema.safeParse(value.model);
18849
19090
  if (!model.success) return void 0;
18850
19091
  const thinkingOptionId = harnessThinkingOptionIdSchema.safeParse(value.thinkingOptionId);
19092
+ const permissionModeId = harnessPermissionModeIdSchema.safeParse(value.permissionModeId);
18851
19093
  return {
18852
19094
  model: model.data,
18853
- ...thinkingOptionId.success ? { thinkingOptionId: thinkingOptionId.data } : {}
19095
+ ...thinkingOptionId.success ? { thinkingOptionId: thinkingOptionId.data } : {},
19096
+ ...permissionModeId.success ? { permissionModeId: permissionModeId.data } : {}
18854
19097
  };
18855
19098
  }
18856
19099
  function readPreference(storage) {
@@ -18890,15 +19133,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18890
19133
  const agent = readPreference(storage)?.lastAgent;
18891
19134
  return agent && enabledAgents.has(agent) ? agent : void 0;
18892
19135
  }
18893
- function readNewThreadExternalConfigurationPreference(agent, catalog, storage = rendererStorage2()) {
19136
+ function readNewThreadExternalConfigurationPreference(agent, catalog, permissionModes, storage = rendererStorage2()) {
18894
19137
  const preference = readPreference(storage)?.externalByAgent[agent];
18895
19138
  if (!preference) return void 0;
18896
19139
  const catalogModel = catalog.models.find(({ ref }) => ref.id === preference.model.id);
18897
19140
  if (!catalogModel) return void 0;
18898
19141
  const thinkingOptionId = preference.thinkingOptionId && catalogModel.supportedThinkingOptionIds?.includes(preference.thinkingOptionId) ? preference.thinkingOptionId : void 0;
19142
+ const permissionModeId = preference.permissionModeId && permissionModes?.modes.some(({ id }) => id === preference.permissionModeId) ? preference.permissionModeId : void 0;
18899
19143
  return {
18900
19144
  model: catalogModel.ref,
18901
- ...thinkingOptionId ? { thinkingOptionId } : {}
19145
+ ...thinkingOptionId ? { thinkingOptionId } : {},
19146
+ ...permissionModeId ? { permissionModeId } : {}
18902
19147
  };
18903
19148
  }
18904
19149
  function writeNewThreadAgentPreference(agent, storage = rendererStorage2()) {
@@ -18912,7 +19157,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18912
19157
  storage
18913
19158
  );
18914
19159
  }
18915
- function writeNewThreadExternalConfigurationPreference(agent, model, thinkingOptionId, storage = rendererStorage2()) {
19160
+ function writeNewThreadExternalConfigurationPreference(agent, model, thinkingOptionId, permissionModeId, storage = rendererStorage2()) {
18916
19161
  const current = readPreference(storage);
18917
19162
  writePreference(
18918
19163
  {
@@ -18922,7 +19167,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
18922
19167
  ...current?.externalByAgent,
18923
19168
  [agent]: {
18924
19169
  model: harnessModelRefSchema.parse(model),
18925
- ...thinkingOptionId ? { thinkingOptionId: harnessThinkingOptionIdSchema.parse(thinkingOptionId) } : {}
19170
+ ...thinkingOptionId ? { thinkingOptionId: harnessThinkingOptionIdSchema.parse(thinkingOptionId) } : {},
19171
+ ...permissionModeId ? { permissionModeId: harnessPermissionModeIdSchema.parse(permissionModeId) } : {}
18926
19172
  }
18927
19173
  }
18928
19174
  },
@@ -21034,6 +21280,9 @@ ${error51.stderrTail}`] : []
21034
21280
  function draftPermissionMode(catalog, requested) {
21035
21281
  return catalog.modes.find(({ id }) => id === requested)?.id ?? catalog.modes.find(({ id }) => id === catalog.defaultModeId)?.id ?? catalog.defaultModeId;
21036
21282
  }
21283
+ function shouldPersistNewThreadConfigurationSelection(phase) {
21284
+ return phase === "draft";
21285
+ }
21037
21286
  function restoredThreadOwnership(inspection) {
21038
21287
  if (inspection.owner === "codex") return { agent: "codex" };
21039
21288
  if (inspection.harnessId === "pi") {
@@ -21057,10 +21306,12 @@ ${error51.stderrTail}`] : []
21057
21306
  }
21058
21307
  const model = inspection.effectiveModel ?? transportSelection.model;
21059
21308
  const thinkingOptionId = selectableThinkingOptionId(inspection) ?? transportSelection.thinkingOptionId;
21309
+ const permissionModeId = inspection.effectivePermissionModeId ?? transportSelection.permissionModeId;
21060
21310
  return {
21061
21311
  agent: "grok",
21062
21312
  ...model ? { model } : {},
21063
- ...thinkingOptionId ? { thinkingOptionId } : {}
21313
+ ...thinkingOptionId ? { thinkingOptionId } : {},
21314
+ ...permissionModeId ? { permissionModeId } : {}
21064
21315
  };
21065
21316
  }
21066
21317
  if (inspection.harnessId === "claude-code") {
@@ -21091,10 +21342,10 @@ ${error51.stderrTail}`] : []
21091
21342
  function isOwnershipSubmissionBlocked(status) {
21092
21343
  return status === "loading" || status === "error";
21093
21344
  }
21094
- function shouldTransferComposerState(sourceTarget, replacementTarget, sourcePhase) {
21345
+ function shouldTransferComposerState(sourceTarget, replacementTarget, sourcePhase, submissionPending = false) {
21095
21346
  if (!sourceTarget || !replacementTarget) return false;
21096
21347
  if (sourceTarget === replacementTarget) return true;
21097
- return sourcePhase === "locked" && sourceTarget[0] === "default" && replacementTarget[0] === "conversation";
21348
+ return (sourcePhase === "locked" || submissionPending) && sourceTarget[0] === "default" && replacementTarget[0] === "conversation";
21098
21349
  }
21099
21350
  function isLateConversationTarget(mountedTarget, currentTarget) {
21100
21351
  if (currentTarget?.[0] !== "conversation") return false;
@@ -21103,13 +21354,16 @@ ${error51.stderrTail}`] : []
21103
21354
  if (mountedTarget?.[0] !== "conversation") return false;
21104
21355
  return mountedTarget.length !== currentTarget.length || mountedTarget.some((value, index) => value !== currentTarget[index]);
21105
21356
  }
21106
- function lateConversationTargetResolution(mountedTarget, currentTarget, sourcePhase) {
21357
+ function lateConversationTargetResolution(mountedTarget, currentTarget, sourcePhase, submissionPending = false) {
21107
21358
  if (!isLateConversationTarget(mountedTarget, currentTarget)) return "none";
21108
- return mountedTarget?.[0] === "default" && sourcePhase === "locked" ? "transfer" : "inspect";
21359
+ return mountedTarget?.[0] === "default" && (sourcePhase === "locked" || submissionPending) ? "transfer" : "inspect";
21109
21360
  }
21110
21361
  function isComposerModelWriteAllowed(target) {
21111
21362
  return target?.[0] === "default";
21112
21363
  }
21364
+ function shouldApplyDraftAgentCarrier(agent, model) {
21365
+ return agent === "codex" || model !== void 0;
21366
+ }
21113
21367
  function applyComposerModelWrite(target, write) {
21114
21368
  if (target?.[0] === "conversation") return true;
21115
21369
  if (!isComposerModelWriteAllowed(target)) return false;
@@ -21217,7 +21471,8 @@ ${error51.stderrTail}`] : []
21217
21471
  writeNewThreadExternalConfigurationPreference(
21218
21472
  state.agent,
21219
21473
  model,
21220
- controller.thinkingOptionForAgent(composer, state.agent)
21474
+ controller.thinkingOptionForAgent(composer, state.agent),
21475
+ controller.permissionModeForAgent(composer, state.agent)
21221
21476
  );
21222
21477
  }
21223
21478
  }
@@ -21426,7 +21681,8 @@ ${error51.stderrTail}`] : []
21426
21681
  const resolution = lateConversationTargetResolution(
21427
21682
  mounted.modelTarget,
21428
21683
  currentTarget,
21429
- controller.get(mounted.composer).phase
21684
+ controller.get(mounted.composer).phase,
21685
+ controller.isSubmissionPending(mounted.composer)
21430
21686
  );
21431
21687
  if (resolution === "none") return false;
21432
21688
  const previousTarget = mounted.modelTarget;
@@ -21493,6 +21749,16 @@ ${error51.stderrTail}`] : []
21493
21749
  }
21494
21750
  if (inspection.status !== "ready") throw new Error(inspection.error.message);
21495
21751
  const current = controller.get(mounted.composer);
21752
+ const previousModel = controller.modelForAgent(mounted.composer, agent);
21753
+ const previousModelAvailable = previousModel !== void 0 && inspection.catalog.models.some((model) => model.ref.id === previousModel.id);
21754
+ if (current.phase === "locked" && previousModel && !previousModelAvailable) {
21755
+ throw new Error("Existing Thread Model is absent from the current Catalog");
21756
+ }
21757
+ const preferredConfiguration = current.phase === "draft" && !previousModelAvailable ? readNewThreadExternalConfigurationPreference(
21758
+ agent,
21759
+ inspection.catalog,
21760
+ inspection.permissionModes
21761
+ ) : void 0;
21496
21762
  const previousPermissionModeId = controller.permissionModeForAgent(mounted.composer, agent);
21497
21763
  let selectedPermissionModeId;
21498
21764
  if (inspection.capabilities.configuration.selectPermissionMode) {
@@ -21502,7 +21768,7 @@ ${error51.stderrTail}`] : []
21502
21768
  }
21503
21769
  mounted.permissionModeView = { status: "loading", catalog: permissionModes };
21504
21770
  const effectivePermissionModeId = current.phase === "locked" ? mounted.threadConfiguration?.effectivePermissionModeId : void 0;
21505
- const preferredPermissionModeId = agent === "claude-code" ? readClaudePermissionModePreference(permissionModes) : void 0;
21771
+ const preferredPermissionModeId = preferredConfiguration?.permissionModeId ?? (agent === "claude-code" ? readClaudePermissionModePreference(permissionModes) : void 0);
21506
21772
  selectedPermissionModeId = draftPermissionMode(
21507
21773
  permissionModes,
21508
21774
  effectivePermissionModeId ?? previousPermissionModeId ?? preferredPermissionModeId
@@ -21531,12 +21797,6 @@ ${error51.stderrTail}`] : []
21531
21797
  }
21532
21798
  return;
21533
21799
  }
21534
- const previousModel = controller.modelForAgent(mounted.composer, agent);
21535
- const previousModelAvailable = previousModel !== void 0 && inspection.catalog.models.some((model) => model.ref.id === previousModel.id);
21536
- if (current.phase === "locked" && previousModel && !previousModelAvailable) {
21537
- throw new Error("Existing Thread Model is absent from the current Catalog");
21538
- }
21539
- const preferredConfiguration = current.phase === "draft" && !previousModelAvailable ? readNewThreadExternalConfigurationPreference(agent, inspection.catalog) : void 0;
21540
21800
  const selected = previousModelAvailable ? previousModel : preferredConfiguration?.model ?? inspection.catalog.defaultModel;
21541
21801
  if (!selected) throw new Error("External Harness did not report its default Model");
21542
21802
  const effectiveCatalog = current.phase === "locked" && mounted.threadConfiguration ? catalogWithConfigurationState(inspection.catalog, selected, mounted.threadConfiguration) : inspection.catalog;
@@ -21616,6 +21876,7 @@ ${error51.stderrTail}`] : []
21616
21876
  }
21617
21877
  };
21618
21878
  const selectExternalModel = async (mounted, modelId) => {
21879
+ controller.clearPendingSubmission(mounted.composer);
21619
21880
  const current = controller.get(mounted.composer);
21620
21881
  if (current.agent === "codex") return;
21621
21882
  const agent = current.agent;
@@ -21687,13 +21948,13 @@ ${error51.stderrTail}`] : []
21687
21948
  effectiveThinkingOptionId = supportsThinkingSelection ? selectableThinkingOptionId(state) : void 0;
21688
21949
  effectiveCatalog = supportsThinkingSelection ? catalogWithConfigurationState(catalog, effectiveModel, state) : catalog;
21689
21950
  resolvedModelLabel = state.resolvedModelLabel;
21690
- const effectivePermissionModeId = state.effectivePermissionModeId ?? previousPermissionModeId;
21951
+ const effectivePermissionModeId2 = state.effectivePermissionModeId ?? previousPermissionModeId;
21691
21952
  if (!applyExternalConfiguration(
21692
21953
  mounted,
21693
21954
  agent,
21694
21955
  effectiveModel,
21695
21956
  effectiveThinkingOptionId,
21696
- effectivePermissionModeId
21957
+ effectivePermissionModeId2
21697
21958
  )) {
21698
21959
  throw new Error("Confirmed external Model could not be applied to the Composer");
21699
21960
  }
@@ -21702,11 +21963,18 @@ ${error51.stderrTail}`] : []
21702
21963
  if (!isCurrentModelRequest(mounted, generation)) return;
21703
21964
  controller.setExternalModel(mounted.composer, agent, effectiveModel);
21704
21965
  controller.setExternalThinkingOption(mounted.composer, agent, effectiveThinkingOptionId);
21705
- writeNewThreadExternalConfigurationPreference(
21706
- agent,
21707
- effectiveModel,
21708
- effectiveThinkingOptionId
21709
- );
21966
+ const effectivePermissionModeId = mounted.threadConfiguration?.effectivePermissionModeId ?? previousPermissionModeId;
21967
+ if (effectivePermissionModeId) {
21968
+ controller.setExternalPermissionMode(mounted.composer, agent, effectivePermissionModeId);
21969
+ }
21970
+ if (shouldPersistNewThreadConfigurationSelection(current.phase)) {
21971
+ writeNewThreadExternalConfigurationPreference(
21972
+ agent,
21973
+ effectiveModel,
21974
+ effectiveThinkingOptionId,
21975
+ effectivePermissionModeId
21976
+ );
21977
+ }
21710
21978
  mounted.modelView = {
21711
21979
  status: "ready",
21712
21980
  catalog: effectiveCatalog,
@@ -21739,6 +22007,7 @@ ${error51.stderrTail}`] : []
21739
22007
  }
21740
22008
  };
21741
22009
  const selectPermissionMode = async (mounted, permissionModeId) => {
22010
+ controller.clearPendingSubmission(mounted.composer);
21742
22011
  const current = controller.get(mounted.composer);
21743
22012
  if (current.agent === "codex") return;
21744
22013
  const agent = current.agent;
@@ -21747,9 +22016,6 @@ ${error51.stderrTail}`] : []
21747
22016
  const model = controller.modelForAgent(mounted.composer, agent);
21748
22017
  if (!catalog || !selectedPermissionModeId || !model || !modelControl) return;
21749
22018
  const previousPermissionModeId = controller.permissionModeForAgent(mounted.composer, agent);
21750
- if (agent === "claude-code") {
21751
- writeClaudePermissionModePreference(selectedPermissionModeId);
21752
- }
21753
22019
  const thinkingOptionId = controller.thinkingOptionForAgent(mounted.composer, agent);
21754
22020
  const generation = controller.beginModelRequest(mounted.composer);
21755
22021
  mounted.permissionModeView = {
@@ -21814,6 +22080,17 @@ ${error51.stderrTail}`] : []
21814
22080
  }
21815
22081
  if (!isCurrentModelRequest(mounted, generation)) return;
21816
22082
  controller.setExternalPermissionMode(mounted.composer, agent, effectivePermissionModeId);
22083
+ if (shouldPersistNewThreadConfigurationSelection(current.phase)) {
22084
+ writeNewThreadExternalConfigurationPreference(
22085
+ agent,
22086
+ model,
22087
+ thinkingOptionId,
22088
+ effectivePermissionModeId
22089
+ );
22090
+ if (agent === "claude-code") {
22091
+ writeClaudePermissionModePreference(effectivePermissionModeId);
22092
+ }
22093
+ }
21817
22094
  mounted.permissionModeView = {
21818
22095
  status: "ready",
21819
22096
  catalog,
@@ -21841,6 +22118,7 @@ ${error51.stderrTail}`] : []
21841
22118
  }
21842
22119
  };
21843
22120
  const selectExternalThinking = async (mounted, thinkingOptionId) => {
22121
+ controller.clearPendingSubmission(mounted.composer);
21844
22122
  const current = controller.get(mounted.composer);
21845
22123
  if (current.agent === "codex") return;
21846
22124
  const agent = current.agent;
@@ -21919,7 +22197,18 @@ ${error51.stderrTail}`] : []
21919
22197
  }
21920
22198
  if (!isCurrentModelRequest(mounted, generation)) return;
21921
22199
  controller.setExternalThinkingOption(mounted.composer, agent, effectiveThinkingOptionId);
21922
- writeNewThreadExternalConfigurationPreference(agent, model, effectiveThinkingOptionId);
22200
+ const effectivePermissionModeId = mounted.threadConfiguration?.effectivePermissionModeId ?? permissionModeId;
22201
+ if (effectivePermissionModeId) {
22202
+ controller.setExternalPermissionMode(mounted.composer, agent, effectivePermissionModeId);
22203
+ }
22204
+ if (shouldPersistNewThreadConfigurationSelection(current.phase)) {
22205
+ writeNewThreadExternalConfigurationPreference(
22206
+ agent,
22207
+ model,
22208
+ effectiveThinkingOptionId,
22209
+ effectivePermissionModeId
22210
+ );
22211
+ }
21923
22212
  mounted.modelView = {
21924
22213
  status: "ready",
21925
22214
  catalog: effectiveCatalog,
@@ -21944,13 +22233,16 @@ ${error51.stderrTail}`] : []
21944
22233
  };
21945
22234
  const switchComposerAgent = async (mounted, agent) => {
21946
22235
  if (agent !== "codex" && harnessAvailability[agent] !== "ready") return false;
22236
+ controller.clearPendingSubmission(mounted.composer);
21947
22237
  const composerId = controller.get(mounted.composer).composerId;
21948
22238
  controller.invalidateModelRequests(mounted.composer);
21949
22239
  const switching = controller.switchAgent(mounted.composer, agent, {
21950
22240
  applyAgent(nextAgent) {
22241
+ const model = controller.modelForAgent(mounted.composer, nextAgent);
22242
+ if (!shouldApplyDraftAgentCarrier(nextAgent, model)) return true;
21951
22243
  return applyAdapterAgent?.(
21952
22244
  nextAgent,
21953
- controller.modelForAgent(mounted.composer, nextAgent),
22245
+ model,
21954
22246
  nextAgent !== "codex" ? controller.thinkingOptionForAgent(mounted.composer, nextAgent) : void 0,
21955
22247
  nextAgent !== "codex" ? controller.permissionModeForAgent(mounted.composer, nextAgent) : void 0,
21956
22248
  mounted.composer
@@ -22169,13 +22461,16 @@ ${error51.stderrTail}`] : []
22169
22461
  };
22170
22462
  mountedByComposer.set(composer, mounted);
22171
22463
  if (isComposerModelWriteAllowed(modelTarget)) {
22172
- applyAdapterAgent?.(
22173
- state.agent,
22174
- controller.modelForAgent(composer, state.agent),
22175
- state.agent !== "codex" ? controller.thinkingOptionForAgent(composer, state.agent) : void 0,
22176
- state.agent !== "codex" ? controller.permissionModeForAgent(composer, state.agent) : void 0,
22177
- composer
22178
- );
22464
+ const model = controller.modelForAgent(composer, state.agent);
22465
+ if (shouldApplyDraftAgentCarrier(state.agent, model)) {
22466
+ applyAdapterAgent?.(
22467
+ state.agent,
22468
+ model,
22469
+ state.agent !== "codex" ? controller.thinkingOptionForAgent(composer, state.agent) : void 0,
22470
+ state.agent !== "codex" ? controller.permissionModeForAgent(composer, state.agent) : void 0,
22471
+ composer
22472
+ );
22473
+ }
22179
22474
  }
22180
22475
  renderMounted(mounted);
22181
22476
  sidebarAgentIcons.refresh();
@@ -22200,7 +22495,8 @@ ${error51.stderrTail}`] : []
22200
22495
  if (!shouldTransferComposerState(
22201
22496
  replacement.sourceModelTarget,
22202
22497
  replacementTarget,
22203
- sourceState.phase
22498
+ sourceState.phase,
22499
+ controller.isSubmissionPending(replacement.source.composer)
22204
22500
  ) || !controller.transfer(replacement.source.composer, target, replacementTarget)) {
22205
22501
  pendingReplacements.delete(target);
22206
22502
  }
@@ -22282,11 +22578,13 @@ ${error51.stderrTail}`] : []
22282
22578
  return state.phase === "locked" && mounted.ownershipStatus === "ready";
22283
22579
  }
22284
22580
  if (!mounted || !isComposerModelWriteAllowed(mounted.modelTarget)) return false;
22581
+ const model = controller.modelForAgent(composer, state.agent);
22582
+ if (!shouldApplyDraftAgentCarrier(state.agent, model)) return false;
22285
22583
  return applyComposerModelWrite(
22286
22584
  mounted.modelTarget,
22287
22585
  () => applyAdapterAgent?.(
22288
22586
  state.agent,
22289
- controller.modelForAgent(composer, state.agent),
22587
+ model,
22290
22588
  state.agent !== "codex" ? controller.thinkingOptionForAgent(composer, state.agent) : void 0,
22291
22589
  state.agent !== "codex" ? controller.permissionModeForAgent(composer, state.agent) : void 0,
22292
22590
  composer
@@ -22308,7 +22606,7 @@ ${error51.stderrTail}`] : []
22308
22606
  if (!isExternalConfigurationReady(mounted)) return false;
22309
22607
  if (current.phase === "locked") return true;
22310
22608
  if (!applyComposerAgent(composer)) return false;
22311
- controller.lock(composer);
22609
+ controller.markSubmissionPending(composer);
22312
22610
  renderMounted(mounted);
22313
22611
  return true;
22314
22612
  };
@@ -22321,6 +22619,7 @@ ${error51.stderrTail}`] : []
22321
22619
  const onBeforeInput = (event) => {
22322
22620
  const composer = composerForTarget(event.target);
22323
22621
  if (!composer) return;
22622
+ controller.clearPendingSubmission(composer);
22324
22623
  const mounted = mountedByComposer.get(composer);
22325
22624
  if (mounted && isOwnershipSubmissionBlocked(mounted.ownershipStatus)) return;
22326
22625
  if (controller.isSwitching(composer) || !applyComposerAgent(composer)) blockEvent(event);