aicodeman 1.46.0 → 1.48.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 (291) hide show
  1. package/README.md +3 -0
  2. package/dist/cli-notify.d.ts +34 -0
  3. package/dist/cli-notify.d.ts.map +1 -0
  4. package/dist/cli-notify.js +100 -0
  5. package/dist/cli-notify.js.map +1 -0
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +16 -0
  8. package/dist/cli.js.map +1 -1
  9. package/dist/config/cli-registry/patterns.d.ts +1 -1
  10. package/dist/config/cli-registry/patterns.d.ts.map +1 -1
  11. package/dist/config/cli-registry/patterns.js +4 -0
  12. package/dist/config/cli-registry/patterns.js.map +1 -1
  13. package/dist/config/cli-registry/schema.d.ts +6 -0
  14. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  15. package/dist/config/cli-registry/schema.js +62 -2
  16. package/dist/config/cli-registry/schema.js.map +1 -1
  17. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  18. package/dist/config/cli-registry/stock.js +43 -26
  19. package/dist/config/cli-registry/stock.js.map +1 -1
  20. package/dist/config/cli-registry/types.d.ts +47 -17
  21. package/dist/config/cli-registry/types.d.ts.map +1 -1
  22. package/dist/config/path-probe.d.ts +6 -0
  23. package/dist/config/path-probe.d.ts.map +1 -1
  24. package/dist/config/path-probe.js +6 -0
  25. package/dist/config/path-probe.js.map +1 -1
  26. package/dist/config-backup.d.ts +1 -1
  27. package/dist/config-backup.d.ts.map +1 -1
  28. package/dist/config-backup.js +2 -0
  29. package/dist/config-backup.js.map +1 -1
  30. package/dist/custom-model-hosts.d.ts +32 -8
  31. package/dist/custom-model-hosts.d.ts.map +1 -1
  32. package/dist/custom-model-hosts.js +10 -0
  33. package/dist/custom-model-hosts.js.map +1 -1
  34. package/dist/custom-model-injection-apply.d.ts +19 -5
  35. package/dist/custom-model-injection-apply.d.ts.map +1 -1
  36. package/dist/custom-model-injection-apply.js +88 -8
  37. package/dist/custom-model-injection-apply.js.map +1 -1
  38. package/dist/custom-model-injection.d.ts +6 -0
  39. package/dist/custom-model-injection.d.ts.map +1 -1
  40. package/dist/custom-model-injection.js +92 -10
  41. package/dist/custom-model-injection.js.map +1 -1
  42. package/dist/discord-bridge.d.ts +338 -0
  43. package/dist/discord-bridge.d.ts.map +1 -0
  44. package/dist/discord-bridge.js +1256 -0
  45. package/dist/discord-bridge.js.map +1 -0
  46. package/dist/edit-history-local-source.d.ts +83 -0
  47. package/dist/edit-history-local-source.d.ts.map +1 -0
  48. package/dist/edit-history-local-source.js +198 -0
  49. package/dist/edit-history-local-source.js.map +1 -0
  50. package/dist/edit-history-parse.d.ts +114 -0
  51. package/dist/edit-history-parse.d.ts.map +1 -0
  52. package/dist/edit-history-parse.js +312 -0
  53. package/dist/edit-history-parse.js.map +1 -0
  54. package/dist/edit-history-store.d.ts +209 -0
  55. package/dist/edit-history-store.d.ts.map +1 -0
  56. package/dist/edit-history-store.js +599 -0
  57. package/dist/edit-history-store.js.map +1 -0
  58. package/dist/git-clone.d.ts +6 -1
  59. package/dist/git-clone.d.ts.map +1 -1
  60. package/dist/git-clone.js +79 -14
  61. package/dist/git-clone.js.map +1 -1
  62. package/dist/image-watcher.js +4 -4
  63. package/dist/image-watcher.js.map +1 -1
  64. package/dist/mux-interface.d.ts +10 -1
  65. package/dist/mux-interface.d.ts.map +1 -1
  66. package/dist/ralph-fix-plan-watcher.d.ts +13 -1
  67. package/dist/ralph-fix-plan-watcher.d.ts.map +1 -1
  68. package/dist/ralph-fix-plan-watcher.js +21 -3
  69. package/dist/ralph-fix-plan-watcher.js.map +1 -1
  70. package/dist/ralph-tracker.d.ts +6 -0
  71. package/dist/ralph-tracker.d.ts.map +1 -1
  72. package/dist/ralph-tracker.js +8 -0
  73. package/dist/ralph-tracker.js.map +1 -1
  74. package/dist/session-cli-registry-bridge.d.ts.map +1 -1
  75. package/dist/session-cli-registry-bridge.js +4 -0
  76. package/dist/session-cli-registry-bridge.js.map +1 -1
  77. package/dist/session.d.ts +70 -3
  78. package/dist/session.d.ts.map +1 -1
  79. package/dist/session.js +147 -4
  80. package/dist/session.js.map +1 -1
  81. package/dist/tmux-manager.d.ts +40 -0
  82. package/dist/tmux-manager.d.ts.map +1 -1
  83. package/dist/tmux-manager.js +62 -0
  84. package/dist/tmux-manager.js.map +1 -1
  85. package/dist/types/discord.d.ts +55 -0
  86. package/dist/types/discord.d.ts.map +1 -0
  87. package/dist/types/discord.js +18 -0
  88. package/dist/types/discord.js.map +1 -0
  89. package/dist/types/index.d.ts +2 -0
  90. package/dist/types/index.d.ts.map +1 -1
  91. package/dist/types/index.js +2 -0
  92. package/dist/types/index.js.map +1 -1
  93. package/dist/types/session.d.ts +13 -0
  94. package/dist/types/session.d.ts.map +1 -1
  95. package/dist/types/session.js.map +1 -1
  96. package/dist/web/case-path.d.ts +2 -0
  97. package/dist/web/case-path.d.ts.map +1 -1
  98. package/dist/web/case-path.js +3 -3
  99. package/dist/web/case-path.js.map +1 -1
  100. package/dist/web/edit-history-sync.d.ts +158 -0
  101. package/dist/web/edit-history-sync.d.ts.map +1 -0
  102. package/dist/web/edit-history-sync.js +445 -0
  103. package/dist/web/edit-history-sync.js.map +1 -0
  104. package/dist/web/paste-image-gc.d.ts +6 -0
  105. package/dist/web/paste-image-gc.d.ts.map +1 -1
  106. package/dist/web/paste-image-gc.js +6 -0
  107. package/dist/web/paste-image-gc.js.map +1 -1
  108. package/dist/web/ports/session-port.d.ts +13 -0
  109. package/dist/web/ports/session-port.d.ts.map +1 -1
  110. package/dist/web/public/admin-ui.js.gz +0 -0
  111. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  112. package/dist/web/public/{app.3093527f.js → app.963b5ba8.js} +18 -18
  113. package/dist/web/public/app.963b5ba8.js.br +0 -0
  114. package/dist/web/public/app.963b5ba8.js.gz +0 -0
  115. package/dist/web/public/approvals-ui.js.gz +0 -0
  116. package/dist/web/public/{constants.affcdde6.js → constants.782170e1.js} +114 -25
  117. package/dist/web/public/constants.782170e1.js.br +0 -0
  118. package/dist/web/public/constants.782170e1.js.gz +0 -0
  119. package/dist/web/public/cron-ui.js.gz +0 -0
  120. package/dist/web/public/edit-history-ui.js +630 -0
  121. package/dist/web/public/edit-history-ui.js.br +0 -0
  122. package/dist/web/public/edit-history-ui.js.gz +0 -0
  123. package/dist/web/public/entrance-animations.js.gz +0 -0
  124. package/dist/web/public/git-status-ui.js.gz +0 -0
  125. package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
  126. package/dist/web/public/home-sessions.js.gz +0 -0
  127. package/dist/web/public/host-wake-ui.js.gz +0 -0
  128. package/dist/web/public/i18n.33f930d7.js +2 -0
  129. package/dist/web/public/i18n.33f930d7.js.br +0 -0
  130. package/dist/web/public/i18n.33f930d7.js.gz +0 -0
  131. package/dist/web/public/{image-input.941386e7.js → image-input.a5d0f8f3.js} +18 -9
  132. package/dist/web/public/image-input.a5d0f8f3.js.br +0 -0
  133. package/dist/web/public/image-input.a5d0f8f3.js.gz +0 -0
  134. package/dist/web/public/index.html +162 -16
  135. package/dist/web/public/index.html.br +0 -0
  136. package/dist/web/public/index.html.gz +0 -0
  137. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  138. package/dist/web/public/{keyboard-accessory.4e8b20ac.js → keyboard-accessory.d4ec5957.js} +77 -2
  139. package/dist/web/public/keyboard-accessory.d4ec5957.js.br +0 -0
  140. package/dist/web/public/keyboard-accessory.d4ec5957.js.gz +0 -0
  141. package/dist/web/public/mobile-handlers.f7c3f692.js.gz +0 -0
  142. package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
  143. package/dist/web/public/mobile-overview.js.gz +0 -0
  144. package/dist/web/public/mobile.5ef2ce85.css +1 -0
  145. package/dist/web/public/mobile.5ef2ce85.css.br +0 -0
  146. package/dist/web/public/mobile.5ef2ce85.css.gz +0 -0
  147. package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
  148. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  149. package/dist/web/public/{panels-ui.4a56ee63.js → panels-ui.b100727d.js} +2 -2
  150. package/dist/web/public/panels-ui.b100727d.js.br +0 -0
  151. package/dist/web/public/{panels-ui.4a56ee63.js.gz → panels-ui.b100727d.js.gz} +0 -0
  152. package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
  153. package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
  154. package/dist/web/public/readmymind-ui.js.gz +0 -0
  155. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  156. package/dist/web/public/{respawn-ui.d7adcf6a.js → respawn-ui.304ba0d4.js} +1 -1
  157. package/dist/web/public/respawn-ui.304ba0d4.js.br +0 -0
  158. package/dist/web/public/respawn-ui.304ba0d4.js.gz +0 -0
  159. package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
  160. package/dist/web/public/security-notices.json +1 -21
  161. package/dist/web/public/session-lineage.js.gz +0 -0
  162. package/dist/web/public/{session-ui.186f9419.js → session-ui.5ac82f2c.js} +30 -30
  163. package/dist/web/public/session-ui.5ac82f2c.js.br +0 -0
  164. package/dist/web/public/session-ui.5ac82f2c.js.gz +0 -0
  165. package/dist/web/public/settings-ui.d1d4fb99.js +106 -0
  166. package/dist/web/public/settings-ui.d1d4fb99.js.br +0 -0
  167. package/dist/web/public/settings-ui.d1d4fb99.js.gz +0 -0
  168. package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
  169. package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
  170. package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
  171. package/dist/web/public/styles.77dc538f.css +1 -0
  172. package/dist/web/public/styles.77dc538f.css.br +0 -0
  173. package/dist/web/public/styles.77dc538f.css.gz +0 -0
  174. package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
  175. package/dist/web/public/sw.js +2 -2
  176. package/dist/web/public/sw.js.br +0 -0
  177. package/dist/web/public/sw.js.gz +0 -0
  178. package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
  179. package/dist/web/public/tab-rail-resize.b5cdceaf.js.gz +0 -0
  180. package/dist/web/public/terminal-keycode229-recovery.98843069.js +1 -0
  181. package/dist/web/public/terminal-keycode229-recovery.98843069.js.br +0 -0
  182. package/dist/web/public/terminal-keycode229-recovery.98843069.js.gz +0 -0
  183. package/dist/web/public/terminal-split.js.gz +0 -0
  184. package/dist/web/public/terminal-tile.js +8 -6
  185. package/dist/web/public/terminal-tile.js.br +0 -0
  186. package/dist/web/public/terminal-tile.js.gz +0 -0
  187. package/dist/web/public/{terminal-ui.7e787829.js → terminal-ui.d7c75ce8.js} +3 -3
  188. package/dist/web/public/terminal-ui.d7c75ce8.js.br +0 -0
  189. package/dist/web/public/terminal-ui.d7c75ce8.js.gz +0 -0
  190. package/dist/web/public/tile-grid.js.gz +0 -0
  191. package/dist/web/public/ultracode-panel.js.gz +0 -0
  192. package/dist/web/public/ultracode-windows.js.gz +0 -0
  193. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  194. package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
  195. package/dist/web/public/vendor/fflate.min.js.gz +0 -0
  196. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  197. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  198. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  199. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  200. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  201. package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.gz +0 -0
  202. package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.gz +0 -0
  203. package/dist/web/public/vendor/xterm.css.gz +0 -0
  204. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  205. package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
  206. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  207. package/dist/web/public/webview-tabs.js.gz +0 -0
  208. package/dist/web/public/whats-new.json +9 -9
  209. package/dist/web/request-body-parser.d.ts +23 -0
  210. package/dist/web/request-body-parser.d.ts.map +1 -0
  211. package/dist/web/request-body-parser.js +57 -0
  212. package/dist/web/request-body-parser.js.map +1 -0
  213. package/dist/web/routes/case-routes.d.ts.map +1 -1
  214. package/dist/web/routes/case-routes.js +104 -8
  215. package/dist/web/routes/case-routes.js.map +1 -1
  216. package/dist/web/routes/config-backup-routes.d.ts +5 -1
  217. package/dist/web/routes/config-backup-routes.d.ts.map +1 -1
  218. package/dist/web/routes/config-backup-routes.js +4 -1
  219. package/dist/web/routes/config-backup-routes.js.map +1 -1
  220. package/dist/web/routes/custom-model-routes.d.ts +7 -2
  221. package/dist/web/routes/custom-model-routes.d.ts.map +1 -1
  222. package/dist/web/routes/custom-model-routes.js +51 -6
  223. package/dist/web/routes/custom-model-routes.js.map +1 -1
  224. package/dist/web/routes/discord-routes.d.ts +25 -0
  225. package/dist/web/routes/discord-routes.d.ts.map +1 -0
  226. package/dist/web/routes/discord-routes.js +206 -0
  227. package/dist/web/routes/discord-routes.js.map +1 -0
  228. package/dist/web/routes/edit-history-routes.d.ts +43 -0
  229. package/dist/web/routes/edit-history-routes.d.ts.map +1 -0
  230. package/dist/web/routes/edit-history-routes.js +106 -0
  231. package/dist/web/routes/edit-history-routes.js.map +1 -0
  232. package/dist/web/routes/file-routes.d.ts +5 -0
  233. package/dist/web/routes/file-routes.d.ts.map +1 -1
  234. package/dist/web/routes/file-routes.js +67 -3
  235. package/dist/web/routes/file-routes.js.map +1 -1
  236. package/dist/web/routes/index.d.ts +2 -0
  237. package/dist/web/routes/index.d.ts.map +1 -1
  238. package/dist/web/routes/index.js +2 -0
  239. package/dist/web/routes/index.js.map +1 -1
  240. package/dist/web/routes/ralph-routes.d.ts.map +1 -1
  241. package/dist/web/routes/ralph-routes.js +45 -2
  242. package/dist/web/routes/ralph-routes.js.map +1 -1
  243. package/dist/web/routes/session-routes.d.ts +17 -0
  244. package/dist/web/routes/session-routes.d.ts.map +1 -1
  245. package/dist/web/routes/session-routes.js +92 -37
  246. package/dist/web/routes/session-routes.js.map +1 -1
  247. package/dist/web/routes/system-routes.d.ts.map +1 -1
  248. package/dist/web/routes/system-routes.js +4 -2
  249. package/dist/web/routes/system-routes.js.map +1 -1
  250. package/dist/web/schemas.d.ts +68 -1
  251. package/dist/web/schemas.d.ts.map +1 -1
  252. package/dist/web/schemas.js +77 -1
  253. package/dist/web/schemas.js.map +1 -1
  254. package/dist/web/sensitive-path.d.ts.map +1 -1
  255. package/dist/web/sensitive-path.js +15 -0
  256. package/dist/web/sensitive-path.js.map +1 -1
  257. package/dist/web/server.d.ts +43 -0
  258. package/dist/web/server.d.ts.map +1 -1
  259. package/dist/web/server.js +237 -15
  260. package/dist/web/server.js.map +1 -1
  261. package/package.json +1 -1
  262. package/dist/web/public/app.3093527f.js.br +0 -0
  263. package/dist/web/public/app.3093527f.js.gz +0 -0
  264. package/dist/web/public/constants.affcdde6.js.br +0 -0
  265. package/dist/web/public/constants.affcdde6.js.gz +0 -0
  266. package/dist/web/public/i18n.70265257.js +0 -2
  267. package/dist/web/public/i18n.70265257.js.br +0 -0
  268. package/dist/web/public/i18n.70265257.js.gz +0 -0
  269. package/dist/web/public/image-input.941386e7.js.br +0 -0
  270. package/dist/web/public/image-input.941386e7.js.gz +0 -0
  271. package/dist/web/public/keyboard-accessory.4e8b20ac.js.br +0 -0
  272. package/dist/web/public/keyboard-accessory.4e8b20ac.js.gz +0 -0
  273. package/dist/web/public/mobile.1bbd2d67.css +0 -1
  274. package/dist/web/public/mobile.1bbd2d67.css.br +0 -0
  275. package/dist/web/public/mobile.1bbd2d67.css.gz +0 -0
  276. package/dist/web/public/panels-ui.4a56ee63.js.br +0 -0
  277. package/dist/web/public/respawn-ui.d7adcf6a.js.br +0 -0
  278. package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
  279. package/dist/web/public/session-ui.186f9419.js.br +0 -0
  280. package/dist/web/public/session-ui.186f9419.js.gz +0 -0
  281. package/dist/web/public/settings-ui.a191154e.js +0 -106
  282. package/dist/web/public/settings-ui.a191154e.js.br +0 -0
  283. package/dist/web/public/settings-ui.a191154e.js.gz +0 -0
  284. package/dist/web/public/styles.7238eae8.css +0 -1
  285. package/dist/web/public/styles.7238eae8.css.br +0 -0
  286. package/dist/web/public/styles.7238eae8.css.gz +0 -0
  287. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js +0 -1
  288. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.br +0 -0
  289. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
  290. package/dist/web/public/terminal-ui.7e787829.js.br +0 -0
  291. package/dist/web/public/terminal-ui.7e787829.js.gz +0 -0
Binary file
@@ -281,6 +281,11 @@ function resolveTabRailKeyboardWidth(input = {}) {
281
281
  // the gap is what tells the user there is more strip to swipe to.
282
282
  const TAB_SCROLL_REVEAL_PX = 16;
283
283
 
284
+ // Narrowest room beside the toolbar the L-shaped header strip trims its first
285
+ // tab into (`_syncTabStripCorner()`, app.js). Less than this keeps the plain
286
+ // wrap: a tab squeezed further shows its number and buttons but no name.
287
+ const TAB_CORNER_MIN_FIRST_TAB = 120;
288
+
284
289
  // Phone/tablet tab-strip scroll policy (issue #257). Those breakpoints scroll
285
290
  // the strip horizontally (desktop wraps to a second row instead and never
286
291
  // scrolls), so the active tab can sit entirely outside the visible slice with
@@ -2106,7 +2111,7 @@ function computeRewriteScrollLine(input) {
2106
2111
  * a `/g` regex, so {@link absoluteFilePathPattern} mints a fresh one per call.
2107
2112
  */
2108
2113
  const FILE_PATH_LINK_PATTERN =
2109
- /(\/(?:home|Users|tmp|var|private|opt|mnt|srv|media|data|workspace)\/[^\s"'<>|;&\n\x00-\x1f]*\.(?:log|txt|json|markdown|md|ya?ml|csv|tsv|xml|sh|py|tsx|ts|jsx|js|mjs|cjs|css|html?|toml|ini|sql|diff|patch|png|jpe?g|gif|webp|avif|bmp|ico|svg|pdf|docx|pptx|xlsx|zip|mp4|webm|mov|m4v|ogv|mp3|wav))\b/g;
2114
+ /(\/(?:home|Users|tmp|var|private|opt|mnt|srv|media|data|workspace)\/[^\s"'<>|;&\n\x00-\x1f]*\.(?:log|txt|json|markdown|md|ya?ml|csv|tsv|xml|sh|py|tsx|ts|jsx|js|mjs|cjs|css|html?|toml|ini|conf|sql|diff|patch|png|jpe?g|gif|webp|avif|bmp|ico|svg|pdf|docx|pptx|xlsx|zip|mp4|webm|mov|m4v|ogv|mp3|wav))\b/g;
2110
2115
 
2111
2116
  /** A fresh, zero-state instance of {@link FILE_PATH_LINK_PATTERN}. */
2112
2117
  function absoluteFilePathPattern() {
@@ -2159,14 +2164,14 @@ function previewsInFileViewer(filePath) {
2159
2164
  * {@link findFilePathLinks}.
2160
2165
  */
2161
2166
  const RELATIVE_FILE_PATH_LINK_PATTERN =
2162
- /(^|[\s"'`(\[{<>=,])((?![^\s"'`<>|;&()[\]{}=,\n\x00-\x1f]*:\/\/)(?:~\/|[^\s"'`<>|;&()[\]{}=,\/~\n\x00-\x1f])[^\s"'`<>|;&()[\]{}=,\n\x00-\x1f]*\.(?:log|txt|json|markdown|md|ya?ml|csv|tsv|xml|sh|py|tsx|ts|jsx|js|mjs|cjs|css|html?|toml|ini|sql|diff|patch|png|jpe?g|gif|webp|avif|bmp|ico|svg|pdf|docx|pptx|xlsx|zip|mp4|webm|mov|m4v|ogv|mp3|wav))\b/g;
2167
+ /(^|[\s"'`(\[{<>=,])((?![^\s"'`<>|;&()[\]{}=,\n\x00-\x1f]*:\/\/)(?:~\/|[^\s"'`<>|;&()[\]{}=,\/~\n\x00-\x1f])[^\s"'`<>|;&()[\]{}=,\n\x00-\x1f]*\.(?:log|txt|json|markdown|md|ya?ml|csv|tsv|xml|sh|py|tsx|ts|jsx|js|mjs|cjs|css|html?|toml|ini|conf|sql|diff|patch|png|jpe?g|gif|webp|avif|bmp|ico|svg|pdf|docx|pptx|xlsx|zip|mp4|webm|mov|m4v|ogv|mp3|wav))\b/g;
2163
2168
 
2164
2169
  /** The `(?:log|txt|…)` extension group, read off the rooted pattern so it cannot drift. */
2165
2170
  const FILE_LINK_EXTENSION_GROUP = /\\\.(\(\?:[^()]*\))\)\\b$/.exec(FILE_PATH_LINK_PATTERN.source)[1];
2166
2171
 
2167
2172
  /**
2168
2173
  * Every linkable file path in `text`, sorted by position. Spaced candidates
2169
- * reserve their whole span first, even when unlinkable; rooted, `~/`, relative
2174
+ * reserve their whole span first, including paths bounded by parentheses, even when unlinkable; rooted, `~/`, relative
2170
2175
  * and folder detectors then skip reserved spans, earlier matches and URLs.
2171
2176
  *
2172
2177
  * The one entry point for both consumers (terminal link provider, response
@@ -2195,19 +2200,26 @@ function findFilePathLinks(text) {
2195
2200
  // A path with spaces is taken whole, or the span it covers links nothing
2196
2201
  // (spacedFilePathOnLine). Either way no detector below may cut a fragment out of it.
2197
2202
  const reserved = [];
2203
+ const isReserved = (index, length) =>
2204
+ reserved.some((r) => index < r.index + r.path.length && r.index < index + length);
2205
+ const reserve = (spaced, index) => {
2206
+ if (!spaced) return;
2207
+ const start = index + spaced.index;
2208
+ if (inUrl(start, spaced.path.length) || isReserved(start, spaced.path.length)) return;
2209
+ reserved.push({ index: start, path: spaced.path });
2210
+ if (spaced.link) found.push({ path: spaced.path, index: start });
2211
+ };
2198
2212
  let lineStart = 0;
2199
2213
  for (const line of value.split('\n')) {
2200
- const spaced = spacedFilePathOnLine(line);
2201
- if (spaced && !inUrl(lineStart + spaced.index, spaced.path.length)) {
2202
- const index = lineStart + spaced.index;
2203
- reserved.push({ index, path: spaced.path });
2204
- if (spaced.link) found.push({ path: spaced.path, index });
2214
+ reserve(spacedFilePathOnLine(line), lineStart);
2215
+ // Parentheses bound an inline path just as a whole line bounds a standalone path.
2216
+ const parenthesised = /\(([^()\r\n]{1,1000})\)/g;
2217
+ while ((match = parenthesised.exec(line)) !== null) {
2218
+ if (opensBashCall(line, match.index)) continue;
2219
+ reserve(spacedFilePathOnLine(match[1], { parenthesised: true }), lineStart + match.index + 1);
2205
2220
  }
2206
2221
  lineStart += line.length + 1;
2207
2222
  }
2208
- const isReserved = (index, length) =>
2209
- reserved.some((r) => index < r.index + r.path.length && r.index < index + length);
2210
-
2211
2223
  const absolute = absoluteFilePathPattern();
2212
2224
  while ((match = absolute.exec(value)) !== null) {
2213
2225
  if (!inUrl(match.index, match[1].length) && !isReserved(match.index, match[1].length)) {
@@ -2235,14 +2247,29 @@ function findFilePathLinks(text) {
2235
2247
  const SPACED_FILE_PATH_LABEL_PATTERN =
2236
2248
  /^(?:path|files?|saved (?:to|as)|wrote|written to|output|created|location|attachment):[ \t]*$/i;
2237
2249
 
2250
+ /**
2251
+ * True when the `(` at `open` starts a `Bash(` tool row, which holds a command rather than
2252
+ * a path: `Bash(/tmp/a.out input.txt)` is a program and its argument, so the parentheses do
2253
+ * not bound one spaced path and the ordinary detectors keep the row. Only `Bash(`: the path
2254
+ * tools (`Read(`, `Update(`, `Write(`) do hold a path, spaces included.
2255
+ *
2256
+ * @param {string} text
2257
+ * @param {number} open Index of the `(`.
2258
+ * @returns {boolean}
2259
+ */
2260
+ function opensBashCall(text, open) {
2261
+ return /(?:^|\W)Bash\($/.test(text.slice(Math.max(0, open - 5), open + 1));
2262
+ }
2263
+
2238
2264
  /**
2239
2265
  * A file path WITH SPACES on one line, or null.
2240
2266
  *
2241
2267
  * Every path pattern ends a path at whitespace, so `/mnt/c/OneDrive - Contoso/a.docx`
2242
2268
  * linked `/mnt/c/OneDrive` plus a relative `Contoso/a.docx`, two links to the
2243
2269
  * wrong targets. A space is only safe inside a path where the line itself bounds
2244
- * the path, so a spaced path is recognised in exactly these shapes:
2270
+ * the path or a parenthesised group bounds it, so a spaced path is recognised in these shapes:
2245
2271
  *
2272
+ * Updated (/mnt/c/My Docs/report.docx) inside parentheses in prose
2246
2273
  * /mnt/c/My Docs/report.docx the whole line is the path
2247
2274
  * - /mnt/c/My Docs/report.docx after a list marker (`-`, `*`, `•`, `1.`, `2)`)
2248
2275
  * Saved to: 03 Attachments/Build SIPOC Design/plan.pptx after a path label (SPACED_FILE_PATH_LABEL_PATTERN)
@@ -2256,7 +2283,7 @@ const SPACED_FILE_PATH_LABEL_PATTERN =
2256
2283
  * it ends on a known extension, a rooted one has a directory before its first
2257
2284
  * space, no earlier word holds an extension (`a.md,`, `a.ts#L12`) or ends in `/`,
2258
2285
  * and none holds a `:` and a digit (`a.ts:42`, a line suffix ends the path). Later words cannot start a new
2259
- * `/`, `~/`, `./` or `../` path, no earlier word ends in `:`, is an arrow or has
2286
+ * `/`, `~/`, `./` or `../` path, no earlier word ends in `:` (or `,` inside parentheses), is an arrow or has
2260
2287
  * no letter or digit (a prompt glyph such as `❯` or `$`; a bare `-` is kept), and
2261
2288
  * a run of spaces (a column gap) is refused, so two paths on a line are never
2262
2289
  * merged. A relative candidate whose only `/` word is its last is prose after the
@@ -2278,9 +2305,10 @@ const SPACED_FILE_PATH_LABEL_PATTERN =
2278
2305
  * Linear: one bounded prefix match, then string scans.
2279
2306
  *
2280
2307
  * @param {string} line One line, no newline.
2308
+ * @param {{parenthesised?: boolean}} [options] Refuse comma-separated lists inside parentheses only.
2281
2309
  * @returns {{path: string, index: number, link: boolean} | null}
2282
2310
  */
2283
- function spacedFilePathOnLine(line) {
2311
+ function spacedFilePathOnLine(line, options = {}) {
2284
2312
  const text = String(line || '');
2285
2313
  const prefix = /^[ \t]*((?:\d{1,3}[.)]|[-*•])[ \t]+)?((?:[A-Za-z][\w-]{0,30}(?: [\w-]{1,30}){0,3}):[ \t]+)?/.exec(text);
2286
2314
  const index = prefix[0].length;
@@ -2304,6 +2332,7 @@ function spacedFilePathOnLine(line) {
2304
2332
  }
2305
2333
  for (const word of words.slice(0, -1)) {
2306
2334
  if (word.endsWith('/') || word.endsWith(':') || /^(?:—|–|→|=>|->|<-|=)$/.test(word)) return null;
2335
+ if (options.parenthesised && word.endsWith(',')) return null;
2307
2336
  // A shell prompt that prints its working directory in full (`/home/me/proj$ cat
2308
2337
  // notes.md`; WSL's `/mnt/c/...` is outside `$HOME`) is a command line too, and so is
2309
2338
  // one whose directory has a space in it (`/mnt/c/My Docs$ ls notes.md`): the `$`
@@ -2397,6 +2426,31 @@ function resolveLinkedFilePath(filePath, workingDir) {
2397
2426
  return `/${parts.join('/')}`;
2398
2427
  }
2399
2428
 
2429
+ /**
2430
+ * The directory a RELATIVE path printed for a session is relative TO.
2431
+ *
2432
+ * `workingDir` is recorded once at create time and never follows a `cd`, so it
2433
+ * stops describing where a shell (or an agent that changed directory) really
2434
+ * is. `session.paneCwd` is the pane's live `#{pane_current_path}`, published by the
2435
+ * server from its pane read. It only changes which BASE a relative path joins;
2436
+ * the result is then routed like any other path, so a target outside the
2437
+ * workspace still goes through the attachment routes.
2438
+ *
2439
+ * Remote and Docker sessions are excluded (the server never sends them a paneCwd,
2440
+ * and this checks again): their local pane runs the ssh / docker-exec CLIENT,
2441
+ * so its directory says nothing about the agent. An unknown paneCwd falls back to
2442
+ * `workingDir`.
2443
+ *
2444
+ * @param {{workingDir?: string, paneCwd?: string, remote?: unknown, docker?: unknown}} [session]
2445
+ * @returns {string|undefined}
2446
+ */
2447
+ function relativeResolutionBase(session) {
2448
+ if (!session) return undefined;
2449
+ const paneCwd = session.paneCwd;
2450
+ if (!session.remote && !session.docker && typeof paneCwd === 'string' && paneCwd.startsWith('/')) return paneCwd;
2451
+ return session.workingDir;
2452
+ }
2453
+
2400
2454
  /**
2401
2455
  * Extensions the file preview renders as a PAGE, from the sandboxed
2402
2456
  * `/html-view/<cap>/` route (src/web/routes/html-view-routes.ts, whose
@@ -2557,9 +2611,10 @@ const pathFirstSegment = (path) => path.replace(/^(?:\.?\/)+/, '').split('/')[0]
2557
2611
  * top directory the broken token did (the next entry of a listing).
2558
2612
  */
2559
2613
  function pathContinuation(prevText, nextText) {
2560
- const tail = /[^\s"'<>|;&]+$/.exec(String(prevText || '').replace(/\s+$/, ''))?.[0] || '';
2561
- if (!tail.includes('/') || !/[\w\-.~+@%/]$/.test(tail) || PATH_TOKEN_ENDS_WITH_EXTENSION.test(tail)) return null;
2614
+ const previous = String(prevText || '').trimEnd();
2562
2615
  const next = String(nextText || '').replace(/^\s+/, '');
2616
+ const tail = /[^\s"'<>|;&]+$/.exec(previous)?.[0] || '';
2617
+ if (!tail.includes('/') || !/[\w\-.~+@%/]$/.test(tail) || PATH_TOKEN_ENDS_WITH_EXTENSION.test(tail)) return null;
2563
2618
  const head = /^[^\s"'<>|;&]+/.exec(next)?.[0] || '';
2564
2619
  if (!head || PATH_TOKEN_STARTS_NEW_PATH.test(head) || PATH_TOKEN_STARTS_EXPLICIT_RELATIVE.test(head)) return null;
2565
2620
  // A listing (`git ls-files`, `find`, `ls -R`) puts one path per row, so `src/components`
@@ -2586,7 +2641,9 @@ function pathContinuation(prevText, nextText) {
2586
2641
  * A following logical line is glued on (its indent dropped, cell mapping kept
2587
2642
  * exact) when {@link pathContinuation} says it carries the path on and the row it
2588
2643
  * broke off is at least as long as the row it continues on. Bounded by the same
2589
- * `maxRows` as the logical line.
2644
+ * `maxRows` as the logical line. Hard breaks concatenate without inserting spaces.
2645
+ * An ambiguous parenthesised filename also carries `pathAlternatives` for a
2646
+ * guarded lookup on activation; its text and cell mapping remain unchanged.
2590
2647
  *
2591
2648
  * @returns Same shape as {@link terminalLogicalLine}; null when the row does not exist.
2592
2649
  */
@@ -2607,6 +2664,7 @@ function terminalPathLine(buffer, row, cols, maxRows) {
2607
2664
  /** `first` and the lines a path carries on into, stopping at the last confirmed join. */
2608
2665
  const extend = (first) => {
2609
2666
  const parts = [first];
2667
+ const alternatives = [];
2610
2668
  let text = first.text;
2611
2669
  let rows = rowsOf(first);
2612
2670
  let confirmed = 1;
@@ -2616,25 +2674,41 @@ function terminalPathLine(buffer, row, cols, maxRows) {
2616
2674
  const kind = continues(parts[parts.length - 1], next, text);
2617
2675
  if (!kind) break;
2618
2676
  parts.push(next);
2677
+ if (kind === 'join') {
2678
+ const opening = text.lastIndexOf('(');
2679
+ const closing = next.text.indexOf(')');
2680
+ if (opening >= 0 && closing > 0 && !opensBashCall(text, opening)) {
2681
+ const before = text.slice(opening + 1);
2682
+ const after = next.text.slice(0, closing).trimStart();
2683
+ const spaced = spacedFilePathOnLine(`${before} ${after}`, { parenthesised: true });
2684
+ if (!before.includes(')') && !/[/-]$/.test(before) && !after.includes('/') && spaced?.link) {
2685
+ alternatives.push({ path: before.slice(spaced.index) + after, spacedPath: spaced.path });
2686
+ }
2687
+ }
2688
+ }
2619
2689
  text += next.text.replace(/^\s+/, '');
2620
2690
  rows += rowsOf(next);
2621
2691
  if (kind === 'join') confirmed = parts.length;
2622
2692
  }
2623
- return parts.slice(0, confirmed);
2693
+ return { parts: parts.slice(0, confirmed), alternatives };
2624
2694
  };
2625
2695
 
2626
- // The hovered row may be the second or third line of a broken path: walk back
2627
- // to where it could start, then let the forward pass decide what really joins.
2696
+ // A middle fragment may have no slash, so only a forward pass from its
2697
+ // rooted start can confirm a path spanning three or more rows.
2698
+ let extended = extend(base);
2628
2699
  let first = base;
2629
2700
  let rows = rowsOf(base);
2630
2701
  while (first.startRow > 0) {
2631
2702
  const prev = lineAt(first.startRow - 1);
2632
- if (!prev || rows + rowsOf(prev) > bound || !continues(prev, first, prev.text)) break;
2703
+ if (!prev || rows + rowsOf(prev) > bound) break;
2633
2704
  first = prev;
2634
2705
  rows += rowsOf(prev);
2706
+ const tail = /[^\s"'<>|;&]+$/.exec(first.text.trimEnd())?.[0] || '';
2707
+ if (!tail.includes('/')) continue;
2708
+ const candidate = extend(first);
2709
+ if (candidate.parts[candidate.parts.length - 1].endRow >= base.startRow) extended = candidate;
2635
2710
  }
2636
- let parts = extend(first);
2637
- if (parts[parts.length - 1].endRow < base.startRow) parts = extend(base);
2711
+ const { parts, alternatives } = extended;
2638
2712
  if (parts.length === 1) return parts[0];
2639
2713
 
2640
2714
  const segments = [];
@@ -2659,7 +2733,14 @@ function terminalPathLine(buffer, row, cols, maxRows) {
2659
2733
  }
2660
2734
  return -1;
2661
2735
  };
2662
- return { startRow: parts[0].startRow, endRow: parts[parts.length - 1].endRow, text, offsetToCell, cellToOffset };
2736
+ return {
2737
+ startRow: parts[0].startRow,
2738
+ endRow: parts[parts.length - 1].endRow,
2739
+ text,
2740
+ offsetToCell,
2741
+ cellToOffset,
2742
+ ...(alternatives.length ? { pathAlternatives: alternatives } : {}),
2743
+ };
2663
2744
  }
2664
2745
 
2665
2746
  /**
@@ -2915,7 +2996,14 @@ function terminalLinkLine(buffer, row, cols, maxRows) {
2915
2996
  for (const s of segments) if (s.row === targetRow && (!seg || s.colStart <= targetCol)) seg = s;
2916
2997
  return seg ? seg.textStart + Math.max(0, targetCol - seg.colStart) : -1;
2917
2998
  };
2918
- return { startRow, endRow: lastRow, text, offsetToCell, cellToOffset };
2999
+ return {
3000
+ startRow,
3001
+ endRow: lastRow,
3002
+ text,
3003
+ offsetToCell,
3004
+ cellToOffset,
3005
+ ...(base.pathAlternatives ? { pathAlternatives: base.pathAlternatives } : {}),
3006
+ };
2919
3007
  }
2920
3008
 
2921
3009
  /**
@@ -4025,6 +4113,7 @@ if (typeof window !== 'undefined') {
4025
4113
  absoluteFilePathPattern,
4026
4114
  findFilePathLinks,
4027
4115
  resolveLinkedFilePath,
4116
+ relativeResolutionBase,
4028
4117
  previewsInFileViewer,
4029
4118
  FILE_PREVIEW_EXTENSIONS,
4030
4119
  rendersAsPage,
Binary file