aicodeman 1.28.2 → 1.29.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.
Files changed (183) hide show
  1. package/README.md +1 -1
  2. package/dist/attachment-registry.d.ts +20 -0
  3. package/dist/attachment-registry.d.ts.map +1 -1
  4. package/dist/attachment-registry.js +75 -10
  5. package/dist/attachment-registry.js.map +1 -1
  6. package/dist/config/cli-registry/schema.d.ts +25 -0
  7. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  8. package/dist/config/cli-registry/schema.js +43 -0
  9. package/dist/config/cli-registry/schema.js.map +1 -1
  10. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  11. package/dist/config/cli-registry/stock.js +157 -2
  12. package/dist/config/cli-registry/stock.js.map +1 -1
  13. package/dist/config/cli-registry/types.d.ts +60 -0
  14. package/dist/config/cli-registry/types.d.ts.map +1 -1
  15. package/dist/custom-model-hosts.d.ts +39 -0
  16. package/dist/custom-model-hosts.d.ts.map +1 -0
  17. package/dist/custom-model-hosts.js +35 -0
  18. package/dist/custom-model-hosts.js.map +1 -0
  19. package/dist/custom-model-injection-apply.d.ts +49 -0
  20. package/dist/custom-model-injection-apply.d.ts.map +1 -0
  21. package/dist/custom-model-injection-apply.js +77 -0
  22. package/dist/custom-model-injection-apply.js.map +1 -0
  23. package/dist/custom-model-injection.d.ts +79 -0
  24. package/dist/custom-model-injection.d.ts.map +1 -0
  25. package/dist/custom-model-injection.js +169 -0
  26. package/dist/custom-model-injection.js.map +1 -0
  27. package/dist/docker-hosts.d.ts +42 -0
  28. package/dist/docker-hosts.d.ts.map +1 -1
  29. package/dist/docker-hosts.js +18 -0
  30. package/dist/docker-hosts.js.map +1 -1
  31. package/dist/generated-artifact-attachments.d.ts +3 -0
  32. package/dist/generated-artifact-attachments.d.ts.map +1 -1
  33. package/dist/generated-artifact-attachments.js +18 -8
  34. package/dist/generated-artifact-attachments.js.map +1 -1
  35. package/dist/mux-interface.d.ts +7 -0
  36. package/dist/mux-interface.d.ts.map +1 -1
  37. package/dist/remote-files.d.ts +145 -0
  38. package/dist/remote-files.d.ts.map +1 -0
  39. package/dist/remote-files.js +347 -0
  40. package/dist/remote-files.js.map +1 -0
  41. package/dist/remote-hosts.d.ts +12 -0
  42. package/dist/remote-hosts.d.ts.map +1 -1
  43. package/dist/remote-hosts.js +7 -1
  44. package/dist/remote-hosts.js.map +1 -1
  45. package/dist/remote-ssh-limiter.d.ts +42 -0
  46. package/dist/remote-ssh-limiter.d.ts.map +1 -0
  47. package/dist/remote-ssh-limiter.js +84 -0
  48. package/dist/remote-ssh-limiter.js.map +1 -0
  49. package/dist/session-manager.d.ts.map +1 -1
  50. package/dist/session-manager.js +8 -1
  51. package/dist/session-manager.js.map +1 -1
  52. package/dist/session.d.ts +79 -2
  53. package/dist/session.d.ts.map +1 -1
  54. package/dist/session.js +163 -2
  55. package/dist/session.js.map +1 -1
  56. package/dist/tmux-manager.d.ts.map +1 -1
  57. package/dist/tmux-manager.js +27 -13
  58. package/dist/tmux-manager.js.map +1 -1
  59. package/dist/types/api.d.ts +6 -0
  60. package/dist/types/api.d.ts.map +1 -1
  61. package/dist/types/api.js.map +1 -1
  62. package/dist/types/session.d.ts +30 -0
  63. package/dist/types/session.d.ts.map +1 -1
  64. package/dist/types/session.js.map +1 -1
  65. package/dist/web/middleware/auth.d.ts +11 -1
  66. package/dist/web/middleware/auth.d.ts.map +1 -1
  67. package/dist/web/middleware/auth.js +69 -1
  68. package/dist/web/middleware/auth.js.map +1 -1
  69. package/dist/web/public/admin-ui.js.gz +0 -0
  70. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  71. package/dist/web/public/{app.78bf0bf8.js → app.556be563.js} +7 -7
  72. package/dist/web/public/app.556be563.js.br +0 -0
  73. package/dist/web/public/app.556be563.js.gz +0 -0
  74. package/dist/web/public/approvals-ui.js.gz +0 -0
  75. package/dist/web/public/constants.258b140f.js.gz +0 -0
  76. package/dist/web/public/cron-ui.js.gz +0 -0
  77. package/dist/web/public/entrance-animations.js.gz +0 -0
  78. package/dist/web/public/home-sessions.js.gz +0 -0
  79. package/dist/web/public/i18n.561ca09c.js.gz +0 -0
  80. package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
  81. package/dist/web/public/index.html +14 -7
  82. package/dist/web/public/index.html.br +0 -0
  83. package/dist/web/public/index.html.gz +0 -0
  84. package/dist/web/public/input-cjk.8bc46081.js +1 -0
  85. package/dist/web/public/input-cjk.8bc46081.js.br +0 -0
  86. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  87. package/dist/web/public/{keyboard-accessory.1d0dda9b.js → keyboard-accessory.2cf04f17.js} +38 -3
  88. package/dist/web/public/keyboard-accessory.2cf04f17.js.br +0 -0
  89. package/dist/web/public/keyboard-accessory.2cf04f17.js.gz +0 -0
  90. package/dist/web/public/mobile-handlers.6f354a87.js.gz +0 -0
  91. package/dist/web/public/mobile-overview.js.gz +0 -0
  92. package/dist/web/public/mobile.e9d0b53e.css.gz +0 -0
  93. package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
  94. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  95. package/dist/web/public/panels-ui.5b07ad14.js.gz +0 -0
  96. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  97. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  98. package/dist/web/public/readmymind-ui.js.gz +0 -0
  99. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  100. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  101. package/dist/web/public/session-lineage.js.gz +0 -0
  102. package/dist/web/public/{session-ui.5d0a7b15.js → session-ui.42b81477.js} +13 -13
  103. package/dist/web/public/session-ui.42b81477.js.br +0 -0
  104. package/dist/web/public/session-ui.42b81477.js.gz +0 -0
  105. package/dist/web/public/settings-ui.e0c7f6b4.js.gz +0 -0
  106. package/dist/web/public/{styles.5d36726d.css → styles.6add175d.css} +1 -1
  107. package/dist/web/public/styles.6add175d.css.br +0 -0
  108. package/dist/web/public/{styles.5d36726d.css.gz → styles.6add175d.css.gz} +0 -0
  109. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  110. package/dist/web/public/sw.js.gz +0 -0
  111. package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
  112. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.gz +0 -0
  113. package/dist/web/public/terminal-ui.38c49244.js +2 -0
  114. package/dist/web/public/terminal-ui.38c49244.js.br +0 -0
  115. package/dist/web/public/terminal-ui.38c49244.js.gz +0 -0
  116. package/dist/web/public/ultracode-panel.js.gz +0 -0
  117. package/dist/web/public/ultracode-windows.js.gz +0 -0
  118. package/dist/web/public/upload.html.gz +0 -0
  119. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  120. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  121. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  122. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  123. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  124. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  125. package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
  126. package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
  127. package/dist/web/public/vendor/xterm.css.gz +0 -0
  128. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  129. package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
  130. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  131. package/dist/web/public/webview-tabs.js +56 -4
  132. package/dist/web/public/webview-tabs.js.br +0 -0
  133. package/dist/web/public/webview-tabs.js.gz +0 -0
  134. package/dist/web/route-helpers.d.ts +20 -0
  135. package/dist/web/route-helpers.d.ts.map +1 -1
  136. package/dist/web/route-helpers.js +29 -2
  137. package/dist/web/route-helpers.js.map +1 -1
  138. package/dist/web/routes/case-routes.d.ts.map +1 -1
  139. package/dist/web/routes/case-routes.js +23 -6
  140. package/dist/web/routes/case-routes.js.map +1 -1
  141. package/dist/web/routes/custom-model-routes.d.ts +18 -0
  142. package/dist/web/routes/custom-model-routes.d.ts.map +1 -0
  143. package/dist/web/routes/custom-model-routes.js +136 -0
  144. package/dist/web/routes/custom-model-routes.js.map +1 -0
  145. package/dist/web/routes/file-routes.d.ts.map +1 -1
  146. package/dist/web/routes/file-routes.js +484 -100
  147. package/dist/web/routes/file-routes.js.map +1 -1
  148. package/dist/web/routes/index.d.ts +1 -0
  149. package/dist/web/routes/index.d.ts.map +1 -1
  150. package/dist/web/routes/index.js +1 -0
  151. package/dist/web/routes/index.js.map +1 -1
  152. package/dist/web/routes/session-routes.d.ts.map +1 -1
  153. package/dist/web/routes/session-routes.js +81 -1
  154. package/dist/web/routes/session-routes.js.map +1 -1
  155. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  156. package/dist/web/routes/ws-routes.js +26 -2
  157. package/dist/web/routes/ws-routes.js.map +1 -1
  158. package/dist/web/schemas.d.ts +20 -0
  159. package/dist/web/schemas.d.ts.map +1 -1
  160. package/dist/web/schemas.js +31 -0
  161. package/dist/web/schemas.js.map +1 -1
  162. package/dist/web/server.d.ts +8 -0
  163. package/dist/web/server.d.ts.map +1 -1
  164. package/dist/web/server.js +65 -3
  165. package/dist/web/server.js.map +1 -1
  166. package/dist/web/webview-proxy.d.ts +41 -0
  167. package/dist/web/webview-proxy.d.ts.map +1 -1
  168. package/dist/web/webview-proxy.js +102 -1
  169. package/dist/web/webview-proxy.js.map +1 -1
  170. package/package.json +2 -2
  171. package/dist/web/public/app.78bf0bf8.js.br +0 -0
  172. package/dist/web/public/app.78bf0bf8.js.gz +0 -0
  173. package/dist/web/public/input-cjk.87f14251.js +0 -1
  174. package/dist/web/public/input-cjk.87f14251.js.br +0 -0
  175. package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
  176. package/dist/web/public/keyboard-accessory.1d0dda9b.js.br +0 -0
  177. package/dist/web/public/keyboard-accessory.1d0dda9b.js.gz +0 -0
  178. package/dist/web/public/session-ui.5d0a7b15.js.br +0 -0
  179. package/dist/web/public/session-ui.5d0a7b15.js.gz +0 -0
  180. package/dist/web/public/styles.5d36726d.css.br +0 -0
  181. package/dist/web/public/terminal-ui.0cbe8637.js +0 -2
  182. package/dist/web/public/terminal-ui.0cbe8637.js.br +0 -0
  183. package/dist/web/public/terminal-ui.0cbe8637.js.gz +0 -0
Binary file
Binary file
Binary file
Binary file
@@ -16,7 +16,7 @@
16
16
  <link rel="manifest" href="manifest.json">
17
17
  <title>Codeman</title>
18
18
  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%2360a5fa'/%3E%3Cstop offset='100%25' stop-color='%233b82f6'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='32' height='32' rx='6' fill='%230a0a0a'/%3E%3Cpath d='M18 4L8 18h6l-2 10 10-14h-6z' fill='url(%23g)'/%3E%3C/svg%3E">
19
- <link rel="stylesheet" href="styles.5d36726d.css">
19
+ <link rel="stylesheet" href="styles.6add175d.css">
20
20
  <link rel="stylesheet" href="mobile.e9d0b53e.css" media="(max-width: 1023px)">
21
21
  <!-- xterm.css loaded async — terminal won't display until xterm.js runs anyway -->
22
22
  <link rel="preload" href="vendor/xterm.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
@@ -28,7 +28,7 @@
28
28
  leaves tofu in xterm's glyph atlas until something forces a re-render. -->
29
29
  <link rel="preload" href="fonts/symbols-nerd-font-mono.woff2" as="font" type="font/woff2" crossorigin>
30
30
  <link rel="preload" href="constants.258b140f.js" as="script">
31
- <link rel="preload" href="app.78bf0bf8.js" as="script">
31
+ <link rel="preload" href="app.556be563.js" as="script">
32
32
  <!-- Self-hosted xterm.js — eliminates CDN DNS/TLS latency (~100ms).
33
33
  'defer' preserves execution order (xterm loads before fit addon). -->
34
34
  <script defer src="vendor/xterm.min.js"></script>
@@ -2906,6 +2906,13 @@
2906
2906
  <label class="checkbox-row"><input type="checkbox" id="dockerAdoptExisting"> Attach to an existing container</label>
2907
2907
  <span class="form-hint">On: Codeman only runs docker exec into a container you already built and run — it never creates, starts, stops or removes it. The CLIs must already be installed and logged in inside it.</span>
2908
2908
  </div>
2909
+ <div class="form-row docker-adopt-only" id="dockerAdoptCloneRow" hidden>
2910
+ <label>Duplicate an Existing Case</label>
2911
+ <select id="dockerAdoptCloneFrom" onchange="app.applyDockerCloneSource()">
2912
+ <option value="">Start from scratch</option>
2913
+ </select>
2914
+ <span class="form-hint">Same container, another directory inside it. Picks up the container, host and workspace below &mdash; you only set a new name and container workdir. Adopted containers only: an owned container&#39;s lifecycle belongs to its one case.</span>
2915
+ </div>
2909
2916
  <div class="form-row docker-adopt-only">
2910
2917
  <label>Container Name</label>
2911
2918
  <input type="text" id="dockerContainerName" list="dockerContainerList" placeholder="my-dev-box" pattern="[a-zA-Z0-9][a-zA-Z0-9_.-]+" autocomplete="off" autocapitalize="off" spellcheck="false">
@@ -3503,15 +3510,15 @@
3503
3510
  <script defer src="mobile-handlers.6f354a87.js"></script>
3504
3511
  <script defer src="voice-input.c4b51eb6.js"></script>
3505
3512
  <script defer src="notification-manager.36ea4624.js"></script>
3506
- <script defer src="keyboard-accessory.1d0dda9b.js"></script>
3507
- <script defer src="input-cjk.87f14251.js"></script>
3513
+ <script defer src="keyboard-accessory.2cf04f17.js"></script>
3514
+ <script defer src="input-cjk.8bc46081.js"></script>
3508
3515
  <!-- Forwards committed input events that xterm drops on Android/GBoard soft keyboards. Must precede terminal-ui.js. -->
3509
3516
  <script defer src="terminal-keycode229-recovery.6ea8fe37.js"></script>
3510
3517
  <!-- Hardened markdown HTML sanitizer (wires DOMPurify). Must precede app.js. -->
3511
3518
  <script defer src="sanitize-html.bc7078d6.js"></script>
3512
- <script defer src="app.78bf0bf8.js"></script>
3519
+ <script defer src="app.556be563.js"></script>
3513
3520
  <script defer src="tab-rail-resize.42c24949.js"></script>
3514
- <script defer src="terminal-ui.0cbe8637.js"></script>
3521
+ <script defer src="terminal-ui.38c49244.js"></script>
3515
3522
  <script defer src="respawn-ui.ff0dae4c.js"></script>
3516
3523
  <script defer src="ralph-panel.6de2d0f8.js"></script>
3517
3524
  <script defer src="orchestrator-panel.js"></script>
@@ -3522,7 +3529,7 @@
3522
3529
  <script defer src="ultracode-panel.js"></script>
3523
3530
  <script defer src="approvals-ui.js"></script>
3524
3531
  <script defer src="admin-ui.js"></script>
3525
- <script defer src="session-ui.5d0a7b15.js"></script>
3532
+ <script defer src="session-ui.42b81477.js"></script>
3526
3533
  <script defer src="webview-tabs.js"></script>
3527
3534
  <script defer src="mobile-overview.js"></script>
3528
3535
  <script defer src="home-sessions.js"></script>
Binary file
Binary file
@@ -0,0 +1 @@
1
+ "use strict";const CjkInput=(()=>{let t=null,l=null,v=!1,o=!1,f=null,a=null,T=!1,_=null,u=null;const i={},p="\u200B",b=200,w=[];function m(n){const e=String(n??"");return`len=${g(e).length}${e.includes(p)?"+ph":""}`}function x(n){const e=String(n??"");return[...e].length===1?"printable":e}function r(n){w.push(`${Date.now()%1e6} ${n}`),w.length>b&&w.shift();try{typeof _crashDiag<"u"&&_crashDiag.log("CJK "+n)}catch{}}const $=150,K=1500,S=3e3,h={ArrowUp:"\x1B[A",ArrowDown:"\x1B[B",ArrowLeft:"\x1B[D",ArrowRight:"\x1B[C",Home:"\x1B[H",End:"\x1B[F",Tab:" "},E={c:"",d:"",l:"\f",z:"",a:"",e:""},L={ArrowUp:"A",ArrowDown:"B",ArrowRight:"C",ArrowLeft:"D",End:"F",Home:"H"};function I(n){const e=L[n.key];return!e||!n.ctrlKey&&!n.altKey?null:`\x1B[1;${1+(n.shiftKey?1:0)+(n.altKey?2:0)+(n.ctrlKey?4:0)}${e}`}function g(n){return n.replace(/​/g,"")}function c(){if(t.value===p){(t.selectionStart!==1||t.selectionEnd!==1)&&t.setSelectionRange(1,1);return}t.value=p,t.setSelectionRange(1,1)}function y(){return!g(t.value)}function k(){if(o){r("flush SKIP composing");return}const n=g(t.value);r(`flush ${n?"send len="+n.length:"empty"}`),n&&l(n),c()}function s(){f&&(clearTimeout(f),f=null)}function C(){T=!0,clearTimeout(_),_=setTimeout(()=>{T=!1,_=null},S)}function A(){s(),f=setTimeout(()=>{f=null,k()},T?K:$)}return{init({send:n}){return v&&this.destroy(),l=n,o=!1,u=null,f=null,t=document.getElementById("cjkInput"),t?(c(),r("init v2-trace"),i.mousedown=e=>{e.stopPropagation()},/Android/i.test(navigator.userAgent)&&(i.pointerdown=()=>{document.activeElement===t&&!o&&y()&&(r("ime-reset (retap)"),t.blur(),setTimeout(()=>t.focus(),0))},t.addEventListener("pointerdown",i.pointerdown)),i.focus=()=>{r(`focus ${m(t.value)}`),window.cjkActive=!0,t.value||c()},i.blur=()=>{r(`blur composing=${o} ${m(t.value)}`),u=null,t.classList.contains("cjk-input-visible")||(window.cjkActive=!1),o=!1},t.addEventListener("mousedown",i.mousedown),t.addEventListener("focus",i.focus),t.addEventListener("blur",i.blur),i.compositionstart=()=>{r(`compstart ${m(t.value)}`),o=!0,u=null,s()},i.compositionend=()=>{r(`compend ${m(t.value)}`),o=!1,s(),clearTimeout(a),a=setTimeout(()=>{a=null,k()},0)},t.addEventListener("compositionstart",i.compositionstart),t.addEventListener("compositionend",i.compositionend),i.keydown=e=>{if(r(`keydown ${x(e.key)} kc=${e.keyCode} ic=${e.isComposing} c=${o}`),u=null,e.key==="Enter"){e.preventDefault(),o=!1,s();const D=g(t.value);l(D?D+"\r":"\r"),c();return}if(e.key==="Escape"){e.preventDefault(),o=!1,s(),c();return}if(e.ctrlKey&&E[e.key]){e.preventDefault(),l(E[e.key]);return}if(o||e.isComposing||e.keyCode===229)return;if(e.key==="Backspace"&&y()){e.preventDefault(),l("\x7F"),c();return}const d=I(e);if(d){e.preventDefault(),l(d);return}if(h[e.key]&&y()){e.preventDefault(),l(h[e.key]);return}if(e.key.length===1&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&y()){u=performance.now();return}},t.addEventListener("keydown",i.keydown),i.input=e=>{r(`input ${e.inputType||"?"} ic=${e.isComposing} c=${o} ${m(t.value)}`);const d=u;if(u=null,o&&e.isComposing===!1&&e.inputType!=="insertCompositionText"&&e.inputType!=="deleteCompositionText"&&(r("UNSTICK composing"),o=!1),e.inputType==="deleteContentBackward"||e.inputType==="deleteWordBackward"){if(o)return;if(y()){s(),l("\x7F"),c();return}C(),t.value.startsWith(p)||(t.value=p+t.value,t.setSelectionRange(1,1)),A();return}if(e.inputType==="insertReplacementText"){C(),A();return}if(!o){if(e.inputType==="insertText"&&d!==null&&performance.now()-d<100){s(),k();return}A()}},t.addEventListener("input",i.input),v=!0,this):this},clear(){!v||!t||(r("clear (external)"),s(),clearTimeout(a),a=null,o=!1,u=null,c())},getTrace(){return w.slice()},destroy(){if(s(),clearTimeout(a),a=null,clearTimeout(_),T=!1,t)for(const[n,e]of Object.entries(i))e&&t.removeEventListener(n,e);window.cjkActive=!1,o=!1,u=null;for(const n of Object.keys(i))delete i[n];v=!1},get element(){return t}}})();
@@ -5,7 +5,9 @@
5
5
  *
6
6
  * - KeyboardAccessoryBar (singleton object) — Quick action buttons shown above the virtual
7
7
  * keyboard on mobile: arrow up/down, /init, Tab, paste, Esc, and dismiss (the extended
8
- * bar adds /clear, /compact, Shift+Tab and more). Tab flushes any locally-buffered
8
+ * bar adds /clear, /compact, Shift+Tab and more). Shift+Left/Right ship in both agent
9
+ * layouts but are revealed only on Codex sessions (`codex-enabled` marker class on the
10
+ * bar, synced on every session switch), since they are Codex bindings. Tab flushes any locally-buffered
9
11
  * prompt text to the PTY before sending \t, so completion applies to what was typed.
10
12
  * The paste button opens a dialog that handles both text paste and image attach
11
13
  * (native picker + best-effort image paste, routed through app._uploadAndInsertImages).
@@ -661,6 +663,8 @@ const KeyboardAccessoryBar = {
661
663
  </button>
662
664
  <button class="accessory-btn" data-action="init" title="/init">/init</button>
663
665
  <button class="accessory-btn" data-action="tab" title="Tab">Tab</button>
666
+ <button class="accessory-btn accessory-btn-codex" data-action="shift-left" title="Shift+Left (Codex: edit queued message)" aria-label="Shift+Left (Codex: edit queued message)">⇧←</button>
667
+ <button class="accessory-btn accessory-btn-codex" data-action="shift-right" title="Shift+Right (Codex: prompt stack back)" aria-label="Shift+Right (Codex: prompt stack back)">⇧→</button>
664
668
  <button class="accessory-btn" data-action="paste" title="Paste from clipboard">
665
669
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
666
670
  <path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
@@ -746,6 +750,8 @@ const KeyboardAccessoryBar = {
746
750
  <button class="accessory-btn" data-action="clear-input" title="Clear the current unsent input">&#x232B; All</button>
747
751
  <button class="accessory-btn accessory-btn-rmm" data-action="readmymind" title="Read My Mind: predict your next prompt">🧠</button>
748
752
  <button class="accessory-btn" data-action="tab" title="Tab">Tab</button>
753
+ <button class="accessory-btn accessory-btn-codex" data-action="shift-left" title="Shift+Left (Codex: edit queued message)" aria-label="Shift+Left (Codex: edit queued message)">⇧←</button>
754
+ <button class="accessory-btn accessory-btn-codex" data-action="shift-right" title="Shift+Right (Codex: prompt stack back)" aria-label="Shift+Right (Codex: prompt stack back)">⇧→</button>
749
755
  <button class="accessory-btn" data-action="shift-tab" title="Shift+Tab">⇧Tab</button>
750
756
  <button class="accessory-btn" data-action="effort-max" title="/effort max">Max</button>
751
757
  <button class="accessory-btn" data-action="ctrl-o" title="Ctrl+O">⌃O</button>
@@ -772,6 +778,9 @@ const KeyboardAccessoryBar = {
772
778
  // The 🧠 key is opt-in (`readMyMindEnabled`, synced): it ships in both
773
779
  // templates but stays display:none until the bar carries the marker class.
774
780
  this.syncReadMyMind();
781
+ // The ⇧←/⇧→ keys are Codex bindings: same shape, gated on the active
782
+ // session's mode instead of a setting.
783
+ this.syncCodexKeys();
775
784
 
776
785
  // Add click handlers — preventDefault stops event from reaching terminal
777
786
  this.element.addEventListener('click', (e) => {
@@ -784,7 +793,7 @@ const KeyboardAccessoryBar = {
784
793
  this.handleAction(action, btn);
785
794
 
786
795
  // Refocus terminal so keyboard stays open (tap blurs terminal → keyboard dismisses → toolbar shifts)
787
- const refocusActions = new Set(['scroll-up', 'scroll-down', 'arrow-left', 'arrow-right', 'tab', 'shift-tab', 'ctrl', 'ctrl-o', 'opt-enter', 'esc', 'effort-max', 'clear-input']);
796
+ const refocusActions = new Set(['scroll-up', 'scroll-down', 'arrow-left', 'arrow-right', 'tab', 'shift-tab', 'shift-left', 'shift-right', 'ctrl', 'ctrl-o', 'opt-enter', 'esc', 'effort-max', 'clear-input']);
788
797
  if (refocusActions.has(action) ||
789
798
  ((action === 'clear' || action === 'compact') && this._confirmAction)) {
790
799
  if (typeof app !== 'undefined' && app.terminal) {
@@ -815,6 +824,7 @@ const KeyboardAccessoryBar = {
815
824
  refreshForActiveSession() {
816
825
  this.clearCtrl();
817
826
  this._applyLayout(this._resolveMode());
827
+ this.syncCodexKeys();
818
828
  },
819
829
 
820
830
  /** Which layout the current state calls for. */
@@ -827,6 +837,11 @@ const KeyboardAccessoryBar = {
827
837
  return app.sessions?.get(app.activeSessionId)?.mode === 'shell';
828
838
  },
829
839
 
840
+ _isCodexSession() {
841
+ if (typeof app === 'undefined' || !app.activeSessionId) return false;
842
+ return app.sessions?.get(app.activeSessionId)?.mode === 'codex';
843
+ },
844
+
830
845
  /** Swap the button set in the DOM. */
831
846
  _applyLayout(mode) {
832
847
  if (!this.element || mode === this._mode) return;
@@ -913,6 +928,12 @@ const KeyboardAccessoryBar = {
913
928
  case 'arrow-right':
914
929
  this.sendNavKey('\x1b[C');
915
930
  break;
931
+ case 'shift-left':
932
+ this.sendNavKey('\x1b[1;2D');
933
+ break;
934
+ case 'shift-right':
935
+ this.sendNavKey('\x1b[1;2C');
936
+ break;
916
937
  case 'esc':
917
938
  this.sendKey('\x1b');
918
939
  break;
@@ -1009,6 +1030,20 @@ const KeyboardAccessoryBar = {
1009
1030
  this.element.classList.toggle('rmm-enabled', enabled === true);
1010
1031
  },
1011
1032
 
1033
+ /** Reveal the ⇧←/⇧→ keys only while the active session runs Codex. They are
1034
+ * Codex bindings (edit the last queued message / prompt stack back) and do
1035
+ * nothing in any other CLI, yet a tap still goes through sendNavKey(), which
1036
+ * hands the session to plain PTY echo for the rest of the prompt, so on a
1037
+ * phone a dead key would also switch off local echo. Same marker-class
1038
+ * shape as syncReadMyMind(): the class lives on the BAR because setMode()
1039
+ * rebuilds the buttons' innerHTML. Synced at init and on every session
1040
+ * switch (refreshForActiveSession); a session's mode is fixed at create, so
1041
+ * no other event can change the answer. */
1042
+ syncCodexKeys() {
1043
+ if (!this.element) return;
1044
+ this.element.classList.toggle('codex-enabled', this._isCodexSession());
1045
+ },
1046
+
1012
1047
  /** Send a slash command to the active session.
1013
1048
  * Sends text and Enter separately so Ink processes them as distinct events. */
1014
1049
  sendCommand(command) {
@@ -1044,7 +1079,7 @@ const KeyboardAccessoryBar = {
1044
1079
  },
1045
1080
 
1046
1081
  /**
1047
- * A composer nav key (the four arrows) from the bar, under the SAME contract
1082
+ * A composer nav key (arrows, including Shift+Left/Right) from the bar, under the SAME contract
1048
1083
  * as pressing one on a hardware keyboard (the `isComposerNavKey` branch of
1049
1084
  * terminal-ui.js's onData): flush the unsent draft so the key edits the real
1050
1085
  * composer, then hand the session to plain PTY echo until Enter or Ctrl+C,
Binary file