@adecore/agents-react 0.31.12 → 0.32.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 (402) hide show
  1. package/dist/agents/AccountDot.js +57 -6
  2. package/dist/agents/AgentIcon.js +88 -12
  3. package/dist/agents/ModelOptionControl.js +153 -18
  4. package/dist/agents/ProviderLogo.js +49 -4
  5. package/dist/agents/account-limits.js +17 -14
  6. package/dist/agents/accounts.js +99 -67
  7. package/dist/agents/agent-marks.js +5 -3
  8. package/dist/agents/model-name.js +42 -31
  9. package/dist/agents/model-options.js +8 -8
  10. package/dist/agents/model-requirement.js +17 -14
  11. package/dist/agents/option-words.d.ts +7 -0
  12. package/dist/agents/option-words.js +35 -0
  13. package/dist/agents/provider-paths.js +6 -6
  14. package/dist/agents/status-look.js +32 -12
  15. package/dist/chat/account-choice.d.ts +13 -0
  16. package/dist/chat/account-choice.js +90 -20
  17. package/dist/chat/actions.js +126 -59
  18. package/dist/chat/activity.js +5 -5
  19. package/dist/chat/attachments.js +74 -53
  20. package/dist/chat/bookmarks.js +58 -48
  21. package/dist/chat/chat-client.js +344 -263
  22. package/dist/chat/chat-references.js +3 -3
  23. package/dist/chat/composer-effort.d.ts +5 -0
  24. package/dist/chat/composer-effort.js +26 -0
  25. package/dist/chat/composer-send.js +13 -13
  26. package/dist/chat/drafts.js +115 -79
  27. package/dist/chat/forks.js +81 -24
  28. package/dist/chat/guards.js +15 -43
  29. package/dist/chat/index.d.ts +3 -1
  30. package/dist/chat/index.js +3 -2
  31. package/dist/chat/logic/ansi.js +170 -167
  32. package/dist/chat/logic/answers.js +2 -2
  33. package/dist/chat/logic/bookmarks.js +19 -19
  34. package/dist/chat/logic/command-looks.js +138 -96
  35. package/dist/chat/logic/context-usage.js +13 -9
  36. package/dist/chat/logic/continue-after-stop.js +15 -19
  37. package/dist/chat/logic/effort.d.ts +14 -0
  38. package/dist/chat/logic/effort.js +34 -0
  39. package/dist/chat/logic/embedded-code.js +387 -326
  40. package/dist/chat/logic/fork.js +134 -110
  41. package/dist/chat/logic/generated-image.js +54 -23
  42. package/dist/chat/logic/goal.js +28 -20
  43. package/dist/chat/logic/handback.js +6 -6
  44. package/dist/chat/logic/json.js +2 -2
  45. package/dist/chat/logic/limit.js +46 -30
  46. package/dist/chat/logic/picker-entries.d.ts +5 -3
  47. package/dist/chat/logic/picker-entries.js +83 -43
  48. package/dist/chat/logic/resume-compaction.d.ts +14 -1
  49. package/dist/chat/logic/resume-compaction.js +93 -24
  50. package/dist/chat/logic/scrubber.js +188 -136
  51. package/dist/chat/logic/thought.js +13 -16
  52. package/dist/chat/logic/thread-cards.js +60 -48
  53. package/dist/chat/logic/timeline-copy.js +30 -38
  54. package/dist/chat/logic/timeline-target.js +92 -63
  55. package/dist/chat/logic/timeline.js +499 -355
  56. package/dist/chat/logic/tool-catalog.js +54 -34
  57. package/dist/chat/logic/tools.js +106 -82
  58. package/dist/chat/logic/visual-height.js +18 -18
  59. package/dist/chat/logic/visual-viewport.js +6 -3
  60. package/dist/chat/logic/welcome.js +9 -9
  61. package/dist/chat/logic/workflow.js +45 -34
  62. package/dist/chat/mentions.js +149 -109
  63. package/dist/chat/persisted-json.js +51 -54
  64. package/dist/chat/preferences.d.ts +4 -0
  65. package/dist/chat/preferences.js +162 -84
  66. package/dist/chat/prompt-hold.js +9 -9
  67. package/dist/chat/quote.js +21 -30
  68. package/dist/chat/reading-width.js +12 -10
  69. package/dist/chat/recent-messages.js +34 -21
  70. package/dist/chat/resume-compaction-dismissals.js +25 -5
  71. package/dist/chat/runtime-modes.js +3 -3
  72. package/dist/chat/send-key.js +11 -7
  73. package/dist/chat/stash.js +89 -69
  74. package/dist/chat/subagent-conversation.js +181 -139
  75. package/dist/chat/subagent-list.js +65 -67
  76. package/dist/chat/subagent-support.js +12 -7
  77. package/dist/chat/subagent-view.js +132 -44
  78. package/dist/chat/thumbnails.js +88 -60
  79. package/dist/chat/timeline-flash.js +24 -12
  80. package/dist/chat/timeline-scroll.js +116 -86
  81. package/dist/chat/ui/AccountPill.js +126 -15
  82. package/dist/chat/ui/AnsiOutput.js +62 -6
  83. package/dist/chat/ui/BookmarkMarker.js +231 -41
  84. package/dist/chat/ui/BookmarkSubmenu.js +165 -18
  85. package/dist/chat/ui/ChatActivity.js +649 -70
  86. package/dist/chat/ui/ChatReferenceChip.js +104 -9
  87. package/dist/chat/ui/CodeBlock.js +132 -58
  88. package/dist/chat/ui/Composer.js +866 -132
  89. package/dist/chat/ui/ComposerInput.js +309 -120
  90. package/dist/chat/ui/DiffPool.js +75 -14
  91. package/dist/chat/ui/EditDiff.js +160 -21
  92. package/dist/chat/ui/FadingWords.js +32 -3
  93. package/dist/chat/ui/GoalDock.js +235 -42
  94. package/dist/chat/ui/ImageView.js +617 -61
  95. package/dist/chat/ui/LimitState.js +446 -72
  96. package/dist/chat/ui/Markdown.js +991 -173
  97. package/dist/chat/ui/MermaidBlock.js +238 -68
  98. package/dist/chat/ui/MessageActions.js +251 -39
  99. package/dist/chat/ui/ModelMarks.js +55 -5
  100. package/dist/chat/ui/Pickers.js +664 -113
  101. package/dist/chat/ui/PromptComposer.js +281 -51
  102. package/dist/chat/ui/QuoteButton.js +151 -57
  103. package/dist/chat/ui/ResumeCompactionDock.d.ts +6 -2
  104. package/dist/chat/ui/ResumeCompactionDock.js +141 -6
  105. package/dist/chat/ui/RowTime.js +59 -5
  106. package/dist/chat/ui/RunSettings.js +1744 -154
  107. package/dist/chat/ui/Scrubber.js +517 -88
  108. package/dist/chat/ui/ShellCommand.js +183 -107
  109. package/dist/chat/ui/SubagentControls.js +212 -24
  110. package/dist/chat/ui/SubagentInfo.js +170 -13
  111. package/dist/chat/ui/SubagentStopButton.js +115 -24
  112. package/dist/chat/ui/SubagentTimeline.js +357 -91
  113. package/dist/chat/ui/Timeline.js +988 -476
  114. package/dist/chat/ui/TimelineMenu.js +552 -37
  115. package/dist/chat/ui/UnifiedDiff.js +234 -27
  116. package/dist/chat/ui/UploadThumb.js +37 -7
  117. package/dist/chat/ui/VisualDialogs.js +251 -20
  118. package/dist/chat/ui/VisualFrame.js +321 -95
  119. package/dist/chat/ui/Welcome.js +72 -7
  120. package/dist/chat/ui/chips.js +1 -1
  121. package/dist/chat/ui/code-lines.js +36 -36
  122. package/dist/chat/ui/code-streaming.js +1 -1
  123. package/dist/chat/ui/code-theme.js +7 -7
  124. package/dist/chat/ui/composer/ComposerControls.js +329 -21
  125. package/dist/chat/ui/composer/ComposerMenu.js +358 -30
  126. package/dist/chat/ui/composer/DraftParts.js +185 -11
  127. package/dist/chat/ui/composer/QueuedMessages.js +138 -13
  128. package/dist/chat/ui/composer/chips.js +29 -19
  129. package/dist/chat/ui/composer/editor.js +79 -63
  130. package/dist/chat/ui/composer/insert.js +26 -12
  131. package/dist/chat/ui/composer/key-handler.js +180 -127
  132. package/dist/chat/ui/composer/keys.js +90 -73
  133. package/dist/chat/ui/composer/menu-aria.js +18 -9
  134. package/dist/chat/ui/composer/placeholder.js +78 -31
  135. package/dist/chat/ui/composer/surface.js +13 -37
  136. package/dist/chat/ui/composer/use-chat-controls.js +230 -90
  137. package/dist/chat/ui/composer/use-compaction-offer.js +50 -18
  138. package/dist/chat/ui/composer/use-composer-draft.js +65 -34
  139. package/dist/chat/ui/composer/use-composer-menus.js +478 -193
  140. package/dist/chat/ui/composer/use-composer-submit.js +251 -109
  141. package/dist/chat/ui/composer/use-continuable-turn.js +33 -6
  142. package/dist/chat/ui/composer/use-draft-files.js +245 -93
  143. package/dist/chat/ui/composer/use-effort-stepper.d.ts +13 -0
  144. package/dist/chat/ui/composer/use-effort-stepper.js +88 -0
  145. package/dist/chat/ui/composer/use-notice.js +61 -16
  146. package/dist/chat/ui/composer/use-pending-requests.js +38 -17
  147. package/dist/chat/ui/composer/use-prompt-history.js +117 -45
  148. package/dist/chat/ui/composer/use-prompt-hold.js +119 -35
  149. package/dist/chat/ui/composer/use-take-back.js +94 -72
  150. package/dist/chat/ui/diff/ApprovalReview.js +101 -23
  151. package/dist/chat/ui/diff/DiffFallbackBoundary.js +21 -13
  152. package/dist/chat/ui/diff/DiffOmitted.js +56 -6
  153. package/dist/chat/ui/diff/DiffStack.js +92 -8
  154. package/dist/chat/ui/diff/DiffUnavailable.js +56 -6
  155. package/dist/chat/ui/diff/EditorEditDiff.js +263 -51
  156. package/dist/chat/ui/diff/EditorPatchDiff.js +39 -14
  157. package/dist/chat/ui/diff/LegacyDiffPool.js +27 -10
  158. package/dist/chat/ui/diff/LegacyEditDiff.js +97 -20
  159. package/dist/chat/ui/diff/LegacyUnifiedDiff.js +172 -42
  160. package/dist/chat/ui/diff/RawDiff.js +65 -5
  161. package/dist/chat/ui/diff/ReviewDiff.js +77 -5
  162. package/dist/chat/ui/diff/diff-props.js +1 -1
  163. package/dist/chat/ui/diff/diff-source-budget.js +46 -35
  164. package/dist/chat/ui/diff/editor-edit-model.js +18 -14
  165. package/dist/chat/ui/diff/review-plan.js +63 -40
  166. package/dist/chat/ui/diff/review-settle.js +24 -9
  167. package/dist/chat/ui/diff/syntax-runtime.js +236 -201
  168. package/dist/chat/ui/diff/use-review-stack.js +146 -25
  169. package/dist/chat/ui/diff-syntax.js +70 -58
  170. package/dist/chat/ui/diff-theme.js +31 -12
  171. package/dist/chat/ui/file-links.js +39 -10
  172. package/dist/chat/ui/find-reveal.js +29 -8
  173. package/dist/chat/ui/full-diff.js +17 -12
  174. package/dist/chat/ui/highlighter.js +143 -113
  175. package/dist/chat/ui/icons.js +16 -7
  176. package/dist/chat/ui/index.js +1 -1
  177. package/dist/chat/ui/intelligent-ui/UiBlockFrame.js +556 -82
  178. package/dist/chat/ui/intelligent-ui/UiFallbackPart.js +73 -5
  179. package/dist/chat/ui/intelligent-ui/UiReply.js +666 -262
  180. package/dist/chat/ui/intelligent-ui/block-local.js +59 -31
  181. package/dist/chat/ui/intelligent-ui/chart-data.js +77 -67
  182. package/dist/chat/ui/intelligent-ui/node-text.js +77 -91
  183. package/dist/chat/ui/intelligent-ui/registry.js +46 -46
  184. package/dist/chat/ui/intelligent-ui/render-context.js +1 -1
  185. package/dist/chat/ui/intelligent-ui/renderers/base-land.js +1 -1
  186. package/dist/chat/ui/intelligent-ui/renderers/binding.js +3 -3
  187. package/dist/chat/ui/intelligent-ui/renderers/chart.js +1223 -123
  188. package/dist/chat/ui/intelligent-ui/renderers/choices.js +312 -34
  189. package/dist/chat/ui/intelligent-ui/renderers/content.js +1241 -86
  190. package/dist/chat/ui/intelligent-ui/renderers/data.js +619 -54
  191. package/dist/chat/ui/intelligent-ui/renderers/inputs.js +868 -67
  192. package/dist/chat/ui/intelligent-ui/renderers/links.js +366 -62
  193. package/dist/chat/ui/intelligent-ui/renderers/map-slots.js +118 -60
  194. package/dist/chat/ui/intelligent-ui/renderers/map-style.js +85 -78
  195. package/dist/chat/ui/intelligent-ui/renderers/map-view.js +282 -217
  196. package/dist/chat/ui/intelligent-ui/renderers/map.js +621 -69
  197. package/dist/chat/ui/intelligent-ui/renderers/place-point.js +15 -8
  198. package/dist/chat/ui/intelligent-ui/renderers/structure.js +262 -20
  199. package/dist/chat/ui/intelligent-ui/renderers/text.js +674 -49
  200. package/dist/chat/ui/intelligent-ui/reply-parts.js +24 -15
  201. package/dist/chat/ui/intelligent-ui/table-data.js +97 -57
  202. package/dist/chat/ui/intelligent-ui/tones.js +31 -31
  203. package/dist/chat/ui/intelligent-ui/use-in-view.js +30 -12
  204. package/dist/chat/ui/intelligent-ui/use-later.js +28 -13
  205. package/dist/chat/ui/intelligent-ui/use-truncated.js +45 -21
  206. package/dist/chat/ui/intelligent-ui/use-ui-links.js +296 -109
  207. package/dist/chat/ui/intelligent-ui/use-ui-queries.js +256 -246
  208. package/dist/chat/ui/markdown-blocks.js +296 -262
  209. package/dist/chat/ui/mermaid.js +60 -72
  210. package/dist/chat/ui/quote-selection.js +32 -29
  211. package/dist/chat/ui/rehype-chips.js +35 -23
  212. package/dist/chat/ui/rehype-fade.js +28 -17
  213. package/dist/chat/ui/remark-html-as-text.js +22 -15
  214. package/dist/chat/ui/reply-context.js +1 -1
  215. package/dist/chat/ui/reveal.js +161 -72
  216. package/dist/chat/ui/rows/ForksRow.js +226 -24
  217. package/dist/chat/ui/rows/GeneratedImageRow.js +541 -87
  218. package/dist/chat/ui/rows/MessageRows.js +1706 -159
  219. package/dist/chat/ui/rows/RowContainer.js +57 -7
  220. package/dist/chat/ui/rows/Rows.js +463 -54
  221. package/dist/chat/ui/rows/SubagentRow.js +577 -60
  222. package/dist/chat/ui/rows/TaskRow.js +359 -40
  223. package/dist/chat/ui/rows/VisualRow.js +233 -11
  224. package/dist/chat/ui/rows/WorkRows.js +1945 -164
  225. package/dist/chat/ui/rows/WorkflowRow.js +293 -34
  226. package/dist/chat/ui/rows/row-rhythm.js +27 -17
  227. package/dist/chat/ui/theme-watch.js +26 -23
  228. package/dist/chat/ui/timestamp-format.js +4 -1
  229. package/dist/chat/ui/use-diff-source-tokens.js +70 -34
  230. package/dist/chat/ui/useToggleSet.js +51 -19
  231. package/dist/chat/ui/visual-theme.js +153 -128
  232. package/dist/chat/visual-bridge.js +123 -123
  233. package/dist/chat/visual-viewport.js +94 -83
  234. package/dist/chat/visuals.js +13 -5
  235. package/dist/host-hooks.d.ts +29 -0
  236. package/dist/host-hooks.js +78 -0
  237. package/dist/host.js +120 -48
  238. package/dist/index.js +1 -1
  239. package/dist/lazy.js +38 -32
  240. package/dist/locales/en/agent-chat.d.ts +34 -0
  241. package/dist/locales/en/agent-chat.js +747 -713
  242. package/dist/locales/en/agent-prompts.js +42 -42
  243. package/dist/locales/en/agent-providers.d.ts +1 -0
  244. package/dist/locales/en/agent-providers.js +166 -165
  245. package/dist/locales/en/agent-usage.d.ts +6 -0
  246. package/dist/locales/en/agent-usage.js +129 -123
  247. package/dist/locales/nl/agent-chat.d.ts +34 -0
  248. package/dist/locales/nl/agent-chat.js +747 -713
  249. package/dist/locales/nl/agent-prompts.js +42 -42
  250. package/dist/locales/nl/agent-providers.d.ts +1 -0
  251. package/dist/locales/nl/agent-providers.js +166 -165
  252. package/dist/locales/nl/agent-usage.d.ts +6 -0
  253. package/dist/locales/nl/agent-usage.js +129 -123
  254. package/dist/locales.js +14 -14
  255. package/dist/mounted-registry.js +31 -30
  256. package/dist/port-transport.js +122 -111
  257. package/dist/prompts/index.js +1 -1
  258. package/dist/prompts/logic/focus.js +15 -14
  259. package/dist/prompts/logic/keys.js +93 -59
  260. package/dist/prompts/logic/prompts.js +27 -14
  261. package/dist/prompts/logic/subjects.js +60 -46
  262. package/dist/prompts/logic/useFocusAfterAnswer.js +60 -20
  263. package/dist/prompts/logic/usePromptSession.js +88 -77
  264. package/dist/prompts/ui/ApprovalBody.js +246 -27
  265. package/dist/prompts/ui/PromptActions.js +215 -9
  266. package/dist/prompts/ui/PromptCard.js +215 -36
  267. package/dist/prompts/ui/PromptView.js +372 -34
  268. package/dist/prompts/ui/QuestionBody.js +269 -73
  269. package/dist/providers/AccountColors.js +36 -5
  270. package/dist/providers/AccountDetail.js +683 -50
  271. package/dist/providers/AccountVariables.js +139 -32
  272. package/dist/providers/AddAccountForm.js +125 -38
  273. package/dist/providers/CliDetail.js +343 -36
  274. package/dist/providers/InstallPage.js +644 -59
  275. package/dist/providers/ProviderList.d.ts +2 -1
  276. package/dist/providers/ProviderList.js +215 -23
  277. package/dist/providers/ProvidersPane.d.ts +4 -2
  278. package/dist/providers/ProvidersPane.js +244 -64
  279. package/dist/providers/account-actions.js +54 -30
  280. package/dist/providers/index.js +1 -1
  281. package/dist/providers/install-steps.js +12 -9
  282. package/dist/providers/pane-target.d.ts +3 -0
  283. package/dist/providers/pane-target.js +34 -13
  284. package/dist/providers/parts.js +62 -12
  285. package/dist/providers/provider-abilities.js +5 -5
  286. package/dist/providers/provider-groups.js +75 -40
  287. package/dist/providers/variables.js +73 -39
  288. package/dist/scope.js +6 -6
  289. package/dist/settings/sections.js +18 -18
  290. package/dist/state/chats.js +404 -192
  291. package/dist/state/index.js +1 -1
  292. package/dist/state/provider-accounts.js +70 -47
  293. package/dist/state/providers.js +45 -16
  294. package/dist/state/usage.js +154 -77
  295. package/dist/storage.js +69 -68
  296. package/dist/testing/index.js +1 -1
  297. package/dist/testing/prompts.js +105 -67
  298. package/dist/transport.js +10 -10
  299. package/dist/ui/PlainTextarea.js +27 -3
  300. package/dist/usage/LimitsList.js +646 -40
  301. package/dist/usage/UsageBreakdown.js +879 -38
  302. package/dist/usage/UsageChart.js +311 -32
  303. package/dist/usage/UsageDialog.js +46 -4
  304. package/dist/usage/UsageLimits.js +467 -34
  305. package/dist/usage/UsageLimitsCard.js +95 -11
  306. package/dist/usage/UsagePage.js +817 -96
  307. package/dist/usage/UsagePane.js +164 -10
  308. package/dist/usage/UsageSummary.js +151 -6
  309. package/dist/usage/UsageTiles.js +164 -14
  310. package/dist/usage/format.js +32 -32
  311. package/dist/usage/index.d.ts +1 -1
  312. package/dist/usage/index.js +2 -1
  313. package/dist/usage/limit-groups.d.ts +2 -0
  314. package/dist/usage/limit-groups.js +77 -59
  315. package/dist/usage/limits.js +78 -43
  316. package/dist/usage/money.js +20 -4
  317. package/dist/usage/summary.js +85 -64
  318. package/package.json +8 -8
  319. package/src/agents/ModelOptionControl.tsx +3 -1
  320. package/src/agents/option-words.ts +27 -0
  321. package/src/chat/account-choice.ts +41 -1
  322. package/src/chat/composer-effort.ts +32 -0
  323. package/src/chat/forks.ts +4 -5
  324. package/src/chat/index.ts +3 -1
  325. package/src/chat/logic/effort.ts +32 -0
  326. package/src/chat/logic/picker-entries.ts +45 -10
  327. package/src/chat/logic/resume-compaction.ts +95 -17
  328. package/src/chat/logic/timeline.ts +11 -3
  329. package/src/chat/preferences.ts +35 -0
  330. package/src/chat/subagent-view.ts +2 -3
  331. package/src/chat/ui/AnsiOutput.tsx +1 -2
  332. package/src/chat/ui/BookmarkSubmenu.tsx +3 -3
  333. package/src/chat/ui/ChatActivity.tsx +14 -22
  334. package/src/chat/ui/ChatReferenceChip.tsx +2 -3
  335. package/src/chat/ui/Composer.tsx +15 -7
  336. package/src/chat/ui/EditDiff.tsx +2 -3
  337. package/src/chat/ui/LimitState.tsx +2 -2
  338. package/src/chat/ui/Markdown.tsx +10 -8
  339. package/src/chat/ui/MermaidBlock.tsx +2 -3
  340. package/src/chat/ui/Pickers.tsx +49 -29
  341. package/src/chat/ui/PromptComposer.tsx +7 -9
  342. package/src/chat/ui/ResumeCompactionDock.tsx +16 -4
  343. package/src/chat/ui/RunSettings.tsx +67 -28
  344. package/src/chat/ui/Scrubber.tsx +3 -3
  345. package/src/chat/ui/ShellCommand.tsx +2 -0
  346. package/src/chat/ui/SubagentInfo.tsx +2 -3
  347. package/src/chat/ui/SubagentTimeline.tsx +12 -16
  348. package/src/chat/ui/Timeline.tsx +6 -6
  349. package/src/chat/ui/UnifiedDiff.tsx +3 -4
  350. package/src/chat/ui/VisualFrame.tsx +5 -8
  351. package/src/chat/ui/code-theme.ts +4 -4
  352. package/src/chat/ui/composer/placeholder.ts +2 -2
  353. package/src/chat/ui/composer/use-compaction-offer.ts +36 -16
  354. package/src/chat/ui/composer/use-composer-menus.ts +4 -9
  355. package/src/chat/ui/composer/use-composer-submit.ts +2 -1
  356. package/src/chat/ui/composer/use-effort-stepper.ts +56 -0
  357. package/src/chat/ui/composer/use-notice.ts +2 -2
  358. package/src/chat/ui/diff/EditorEditDiff.tsx +9 -13
  359. package/src/chat/ui/diff/LegacyEditDiff.tsx +12 -17
  360. package/src/chat/ui/diff/LegacyUnifiedDiff.tsx +13 -21
  361. package/src/chat/ui/diff/use-review-stack.ts +4 -4
  362. package/src/chat/ui/diff-theme.ts +3 -3
  363. package/src/chat/ui/file-links.ts +2 -2
  364. package/src/chat/ui/intelligent-ui/UiReply.tsx +2 -0
  365. package/src/chat/ui/intelligent-ui/renderers/chart.tsx +3 -3
  366. package/src/chat/ui/intelligent-ui/renderers/content.tsx +5 -6
  367. package/src/chat/ui/intelligent-ui/renderers/map-view.tsx +2 -1
  368. package/src/chat/ui/intelligent-ui/renderers/map.tsx +2 -1
  369. package/src/chat/ui/intelligent-ui/use-truncated.ts +16 -19
  370. package/src/chat/ui/intelligent-ui/use-ui-links.ts +3 -3
  371. package/src/chat/ui/rows/ForksRow.tsx +3 -5
  372. package/src/chat/ui/rows/GeneratedImageRow.tsx +2 -1
  373. package/src/chat/ui/rows/MessageRows.tsx +12 -21
  374. package/src/chat/ui/rows/SubagentRow.tsx +3 -3
  375. package/src/chat/ui/rows/TaskRow.tsx +1 -1
  376. package/src/chat/ui/rows/WorkRows.tsx +10 -5
  377. package/src/chat/ui/useToggleSet.ts +15 -18
  378. package/src/chat/ui/visual-theme.ts +2 -3
  379. package/src/host-hooks.ts +113 -0
  380. package/src/lazy.tsx +2 -0
  381. package/src/locales/en/agent-chat.ts +134 -108
  382. package/src/locales/en/agent-prompts.ts +7 -7
  383. package/src/locales/en/agent-providers.ts +35 -34
  384. package/src/locales/en/agent-usage.ts +26 -20
  385. package/src/locales/nl/agent-chat.ts +126 -100
  386. package/src/locales/nl/agent-prompts.ts +5 -5
  387. package/src/locales/nl/agent-providers.ts +33 -32
  388. package/src/locales/nl/agent-usage.ts +25 -20
  389. package/src/providers/CliDetail.tsx +2 -1
  390. package/src/providers/InstallPage.tsx +2 -4
  391. package/src/providers/ProviderList.tsx +12 -2
  392. package/src/providers/ProvidersPane.tsx +45 -15
  393. package/src/providers/pane-target.ts +20 -4
  394. package/src/state/chats.ts +2 -2
  395. package/src/usage/LimitsList.tsx +12 -13
  396. package/src/usage/UsageBreakdown.tsx +17 -6
  397. package/src/usage/UsageLimits.tsx +2 -1
  398. package/src/usage/UsagePage.tsx +3 -3
  399. package/src/usage/index.ts +1 -1
  400. package/src/usage/limit-groups.ts +12 -0
  401. package/src/usage/limits.ts +2 -2
  402. package/src/usage/money.ts +1 -2
@@ -3,41 +3,55 @@ export const SHELL_LANGUAGE = 'shellscript';
3
3
  export const EMBEDDED_CODE_LIMIT = 20_000;
4
4
  const MAX_DEPTH = 3;
5
5
  const SHELL = {
6
- language: SHELL_LANGUAGE,
7
- script: (flag) => /^-[a-zA-Z]*c[a-zA-Z]*$/.test(flag),
8
- takesValue: new Set(['-o', '-O', '--rcfile', '--init-file'])
6
+ language: SHELL_LANGUAGE,
7
+ script: flag => /^-[a-zA-Z]*c[a-zA-Z]*$/.test(flag),
8
+ takesValue: new Set(['-o', '-O', '--rcfile', '--init-file'])
9
+ };
10
+ const PYTHON = {
11
+ language: 'python',
12
+ script: flag => flag === '-c',
13
+ takesValue: new Set(['-W', '-X'])
9
14
  };
10
- const PYTHON = { language: 'python', script: (flag) => flag === '-c', takesValue: new Set(['-W', '-X']) };
11
15
  const NODE = {
12
- language: 'javascript',
13
- script: (flag) => ['-e', '--eval', '-p', '--print'].includes(flag),
14
- takesValue: new Set(['-r', '--require', '--import', '--input-type', '--conditions', '-C'])
16
+ language: 'javascript',
17
+ script: flag => ['-e', '--eval', '-p', '--print'].includes(flag),
18
+ takesValue: new Set(['-r', '--require', '--import', '--input-type', '--conditions', '-C'])
19
+ };
20
+ const BUN = {
21
+ language: 'typescript',
22
+ script: flag => ['-e', '--eval', '-p', '--print'].includes(flag),
23
+ takesValue: NODE.takesValue
15
24
  };
16
- const BUN = { language: 'typescript', script: (flag) => ['-e', '--eval', '-p', '--print'].includes(flag), takesValue: NODE.takesValue };
17
25
  const MYSQL = {
18
- language: 'sql',
19
- client: true,
20
- script: (flag) => flag === '-e' || flag === '--execute',
21
- takesValue: new Set(['-u', '-h', '-P', '-D', '-S', '--user', '--host', '--port', '--database'])
26
+ language: 'sql',
27
+ client: true,
28
+ script: flag => flag === '-e' || flag === '--execute',
29
+ takesValue: new Set(['-u', '-h', '-P', '-D', '-S', '--user', '--host', '--port', '--database'])
22
30
  };
23
31
  const INTERPRETERS = {
24
- bash: SHELL,
25
- sh: SHELL,
26
- zsh: SHELL,
27
- dash: SHELL,
28
- ksh: SHELL,
29
- python: PYTHON,
30
- node: NODE,
31
- bun: BUN,
32
- psql: {
33
- language: 'sql',
34
- client: true,
35
- script: (flag) => flag === '-c' || flag === '--command',
36
- takesValue: new Set(['-d', '-h', '-p', '-U', '-f', '-v', '-o', '--dbname', '--host', '--port', '--username', '--file', '--set'])
37
- },
38
- mysql: MYSQL,
39
- mariadb: MYSQL,
40
- sqlite3: { language: 'sql', client: true, script: () => false, takesValue: new Set(['-cmd', '-separator', '-newline', '-nullvalue']), positional: 1 }
32
+ bash: SHELL,
33
+ sh: SHELL,
34
+ zsh: SHELL,
35
+ dash: SHELL,
36
+ ksh: SHELL,
37
+ python: PYTHON,
38
+ node: NODE,
39
+ bun: BUN,
40
+ psql: {
41
+ language: 'sql',
42
+ client: true,
43
+ script: flag => flag === '-c' || flag === '--command',
44
+ takesValue: new Set(['-d', '-h', '-p', '-U', '-f', '-v', '-o', '--dbname', '--host', '--port', '--username', '--file', '--set'])
45
+ },
46
+ mysql: MYSQL,
47
+ mariadb: MYSQL,
48
+ sqlite3: {
49
+ language: 'sql',
50
+ client: true,
51
+ script: () => false,
52
+ takesValue: new Set(['-cmd', '-separator', '-newline', '-nullvalue']),
53
+ positional: 1
54
+ }
41
55
  };
42
56
  // Programs that run the next word as the command; their own options are skipped along with them.
43
57
  const WRAPPERS = new Set(['sudo', 'env', 'exec', 'nohup', 'time', 'command', 'nice']);
@@ -45,336 +59,383 @@ const WRAPPERS = new Set(['sudo', 'env', 'exec', 'nohup', 'time', 'command', 'ni
45
59
  const RUNNERS = new Set(['uv', 'poetry', 'pipenv']);
46
60
  // Where a heredoc written to a file goes, by the file's extension.
47
61
  const EXTENSIONS = {
48
- py: 'python',
49
- js: 'javascript',
50
- mjs: 'javascript',
51
- cjs: 'javascript',
52
- jsx: 'jsx',
53
- ts: 'typescript',
54
- mts: 'typescript',
55
- tsx: 'tsx',
56
- json: 'json',
57
- sql: 'sql',
58
- sh: SHELL_LANGUAGE,
59
- bash: SHELL_LANGUAGE,
60
- zsh: SHELL_LANGUAGE,
61
- yml: 'yaml',
62
- yaml: 'yaml',
63
- md: 'markdown',
64
- css: 'css',
65
- html: 'html',
66
- php: 'php',
67
- xml: 'xml'
62
+ py: 'python',
63
+ js: 'javascript',
64
+ mjs: 'javascript',
65
+ cjs: 'javascript',
66
+ jsx: 'jsx',
67
+ ts: 'typescript',
68
+ mts: 'typescript',
69
+ tsx: 'tsx',
70
+ json: 'json',
71
+ sql: 'sql',
72
+ sh: SHELL_LANGUAGE,
73
+ bash: SHELL_LANGUAGE,
74
+ zsh: SHELL_LANGUAGE,
75
+ yml: 'yaml',
76
+ yaml: 'yaml',
77
+ md: 'markdown',
78
+ css: 'css',
79
+ html: 'html',
80
+ php: 'php',
81
+ xml: 'xml'
68
82
  };
69
83
  const SEPARATORS = ';&|()';
70
84
  const BLANKS = ' \t\r';
71
85
  /* The program a command name runs, as the table above knows it: `/usr/bin/python3.12` is `python`. */
72
86
  function programOf(word) {
73
- const name = word.slice(word.lastIndexOf('/') + 1);
74
- return /^python\d*(\.\d+)?$/.test(name) ? 'python' : name;
87
+ const name = word.slice(word.lastIndexOf('/') + 1);
88
+ return /^python\d*(\.\d+)?$/.test(name) ? 'python' : name;
75
89
  }
76
90
  /* Splits `source[from, to)` into simple commands the way a shell would, enough to find the code in them. */
77
91
  function parseCommands(source, from, to) {
78
- const commands = [];
79
- let current = { words: [], redirects: [], heredocs: [] };
80
- const pending = [];
81
- // The start of the `2` of a `2>&1` just read, which the redirect after it begins at.
82
- let descriptorStart = null;
83
- const finish = () => {
84
- if (current.words.length > 0 || current.redirects.length > 0) {
85
- commands.push(current);
86
- }
87
- current = { words: [], redirects: [], heredocs: [] };
88
- descriptorStart = null;
89
- };
90
- const skipBlanks = (index) => {
91
- while (index < to && BLANKS.includes(source[index])) {
92
- index++;
93
- }
94
- return index;
95
- };
96
- const readWord = (start) => {
97
- let index = start;
98
- let text = '';
99
- let quoted = null;
100
- let parts = 0;
101
- let bare = true;
102
- while (index < to) {
103
- const char = source[index];
104
- if (BLANKS.includes(char) || char === '\n' || SEPARATORS.includes(char) || char === '<' || char === '>') {
105
- break;
106
- }
107
- parts++;
108
- if (char === "'") {
109
- const close = source.indexOf("'", index + 1);
110
- const end = close === -1 || close >= to ? to : close;
111
- text += source.slice(index + 1, end);
112
- quoted = { start: index + 1, end };
113
- bare = false;
114
- index = Math.min(end + 1, to);
115
- }
116
- else if (char === '"') {
117
- let end = index + 1;
118
- while (end < to && source[end] !== '"') {
119
- if (source[end] === '\\' && end + 1 < to && '$`"\\\n'.includes(source[end + 1])) {
120
- text += source[end + 1];
121
- end += 2;
122
- }
123
- else {
124
- text += source[end];
125
- end++;
126
- }
127
- }
128
- quoted = { start: index + 1, end };
129
- bare = false;
130
- index = Math.min(end + 1, to);
131
- }
132
- else if (char === '\\') {
133
- text += source[index + 1] ?? '';
134
- bare = false;
135
- index += 2;
136
- }
137
- else if (char === '$' && source[index + 1] === '(') {
138
- const end = closingParen(source, index + 1, to);
139
- text += source.slice(index, end);
140
- index = end;
141
- }
142
- else {
143
- text += char;
144
- index++;
145
- }
146
- }
147
- const end = Math.min(index, to);
148
- const body = bare ? { start, end } : parts === 1 && quoted !== null ? quoted : null;
149
- return { start, end, text, body };
92
+ const commands = [];
93
+ let current = {
94
+ words: [],
95
+ redirects: [],
96
+ heredocs: []
97
+ };
98
+ const pending = [];
99
+ // The start of the `2` of a `2>&1` just read, which the redirect after it begins at.
100
+ let descriptorStart = null;
101
+ const finish = () => {
102
+ if (current.words.length > 0 || current.redirects.length > 0) {
103
+ commands.push(current);
104
+ }
105
+ current = {
106
+ words: [],
107
+ redirects: [],
108
+ heredocs: []
150
109
  };
151
- const readHeredoc = (start, delimiter, strip) => {
152
- let index = start;
153
- while (index < to) {
154
- const newline = source.indexOf('\n', index);
155
- const lineEnd = newline === -1 || newline >= to ? to : newline;
156
- let line = source.slice(index, lineEnd).replace(/\r$/, '');
157
- if (strip) {
158
- line = line.replace(/^\t+/, '');
159
- }
160
- if (line === delimiter) {
161
- return { body: { start, end: index }, next: Math.min(lineEnd + 1, to) };
162
- }
163
- index = lineEnd + 1;
110
+ descriptorStart = null;
111
+ };
112
+ const skipBlanks = index => {
113
+ while (index < to && BLANKS.includes(source[index])) {
114
+ index++;
115
+ }
116
+ return index;
117
+ };
118
+ const readWord = start => {
119
+ let index = start;
120
+ let text = '';
121
+ let quoted = null;
122
+ let parts = 0;
123
+ let bare = true;
124
+ while (index < to) {
125
+ const char = source[index];
126
+ if (BLANKS.includes(char) || char === '\n' || SEPARATORS.includes(char) || char === '<' || char === '>') {
127
+ break;
128
+ }
129
+ parts++;
130
+ if (char === "'") {
131
+ const close = source.indexOf("'", index + 1);
132
+ const end = close === -1 || close >= to ? to : close;
133
+ text += source.slice(index + 1, end);
134
+ quoted = {
135
+ start: index + 1,
136
+ end
137
+ };
138
+ bare = false;
139
+ index = Math.min(end + 1, to);
140
+ } else if (char === '"') {
141
+ let end = index + 1;
142
+ while (end < to && source[end] !== '"') {
143
+ if (source[end] === '\\' && end + 1 < to && '$`"\\\n'.includes(source[end + 1])) {
144
+ text += source[end + 1];
145
+ end += 2;
146
+ } else {
147
+ text += source[end];
148
+ end++;
149
+ }
164
150
  }
165
- return { body: { start, end: to }, next: to };
151
+ quoted = {
152
+ start: index + 1,
153
+ end
154
+ };
155
+ bare = false;
156
+ index = Math.min(end + 1, to);
157
+ } else if (char === '\\') {
158
+ text += source[index + 1] ?? '';
159
+ bare = false;
160
+ index += 2;
161
+ } else if (char === '$' && source[index + 1] === '(') {
162
+ const end = closingParen(source, index + 1, to);
163
+ text += source.slice(index, end);
164
+ index = end;
165
+ } else {
166
+ text += char;
167
+ index++;
168
+ }
169
+ }
170
+ const end = Math.min(index, to);
171
+ const body = bare ? {
172
+ start,
173
+ end
174
+ } : parts === 1 && quoted !== null ? quoted : null;
175
+ return {
176
+ start,
177
+ end,
178
+ text,
179
+ body
166
180
  };
167
- let index = from;
181
+ };
182
+ const readHeredoc = (start, delimiter, strip) => {
183
+ let index = start;
168
184
  while (index < to) {
169
- const char = source[index];
170
- if (char === '\n') {
171
- index++;
172
- for (const heredoc of pending) {
173
- const { body, next } = readHeredoc(index, heredoc.delimiter, heredoc.strip);
174
- heredoc.command.heredocs.push({ ...heredoc.operator, body });
175
- index = next;
176
- }
177
- pending.length = 0;
178
- finish();
179
- }
180
- else if (BLANKS.includes(char)) {
181
- index++;
182
- }
183
- else if (char === '\\' && source[index + 1] === '\n') {
184
- index += 2;
185
- }
186
- else if (char === '#') {
187
- const newline = source.indexOf('\n', index);
188
- index = newline === -1 || newline >= to ? to : newline;
189
- }
190
- else if (source.startsWith('<<<', index)) {
191
- index = readWord(skipBlanks(index + 3)).end;
192
- }
193
- else if (source.startsWith('<<', index)) {
194
- const start = index;
195
- index += 2;
196
- const strip = source[index] === '-';
197
- const word = readWord(skipBlanks(strip ? index + 1 : index));
198
- if (word.text !== '') {
199
- pending.push({ command: current, delimiter: word.text, strip, operator: { start, end: word.end } });
200
- }
201
- index = word.end;
202
- }
203
- else if (char === '<' || char === '>' || (char === '&' && source[index + 1] === '>')) {
204
- let end = index + 1;
205
- while (end < to && '<>&|'.includes(source[end])) {
206
- end++;
207
- }
208
- const op = source.slice(index, end);
209
- const target = readWord(skipBlanks(end));
210
- current.redirects.push({ start: descriptorStart ?? index, end: Math.max(target.end, end), op, target });
211
- descriptorStart = null;
212
- index = Math.max(target.end, end);
213
- }
214
- else if (SEPARATORS.includes(char)) {
215
- index++;
216
- finish();
217
- }
218
- else {
219
- const word = readWord(index);
220
- // The `2` of `2>&1` is a file descriptor, not an argument.
221
- const descriptor = /^\d+$/.test(word.text) && (source[word.end] === '>' || source[word.end] === '<');
222
- if (descriptor) {
223
- descriptorStart = word.start;
224
- }
225
- else {
226
- current.words.push(word);
227
- }
228
- index = Math.max(word.end, index + 1);
229
- }
185
+ const newline = source.indexOf('\n', index);
186
+ const lineEnd = newline === -1 || newline >= to ? to : newline;
187
+ let line = source.slice(index, lineEnd).replace(/\r$/, '');
188
+ if (strip) {
189
+ line = line.replace(/^\t+/, '');
190
+ }
191
+ if (line === delimiter) {
192
+ return {
193
+ body: {
194
+ start,
195
+ end: index
196
+ },
197
+ next: Math.min(lineEnd + 1, to)
198
+ };
199
+ }
200
+ index = lineEnd + 1;
201
+ }
202
+ return {
203
+ body: {
204
+ start,
205
+ end: to
206
+ },
207
+ next: to
208
+ };
209
+ };
210
+ let index = from;
211
+ while (index < to) {
212
+ const char = source[index];
213
+ if (char === '\n') {
214
+ index++;
215
+ for (const heredoc of pending) {
216
+ const {
217
+ body,
218
+ next
219
+ } = readHeredoc(index, heredoc.delimiter, heredoc.strip);
220
+ heredoc.command.heredocs.push({
221
+ ...heredoc.operator,
222
+ body
223
+ });
224
+ index = next;
225
+ }
226
+ pending.length = 0;
227
+ finish();
228
+ } else if (BLANKS.includes(char)) {
229
+ index++;
230
+ } else if (char === '\\' && source[index + 1] === '\n') {
231
+ index += 2;
232
+ } else if (char === '#') {
233
+ const newline = source.indexOf('\n', index);
234
+ index = newline === -1 || newline >= to ? to : newline;
235
+ } else if (source.startsWith('<<<', index)) {
236
+ index = readWord(skipBlanks(index + 3)).end;
237
+ } else if (source.startsWith('<<', index)) {
238
+ const start = index;
239
+ index += 2;
240
+ const strip = source[index] === '-';
241
+ const word = readWord(skipBlanks(strip ? index + 1 : index));
242
+ if (word.text !== '') {
243
+ pending.push({
244
+ command: current,
245
+ delimiter: word.text,
246
+ strip,
247
+ operator: {
248
+ start,
249
+ end: word.end
250
+ }
251
+ });
252
+ }
253
+ index = word.end;
254
+ } else if (char === '<' || char === '>' || char === '&' && source[index + 1] === '>') {
255
+ let end = index + 1;
256
+ while (end < to && '<>&|'.includes(source[end])) {
257
+ end++;
258
+ }
259
+ const op = source.slice(index, end);
260
+ const target = readWord(skipBlanks(end));
261
+ current.redirects.push({
262
+ start: descriptorStart ?? index,
263
+ end: Math.max(target.end, end),
264
+ op,
265
+ target
266
+ });
267
+ descriptorStart = null;
268
+ index = Math.max(target.end, end);
269
+ } else if (SEPARATORS.includes(char)) {
270
+ index++;
271
+ finish();
272
+ } else {
273
+ const word = readWord(index);
274
+ // The `2` of `2>&1` is a file descriptor, not an argument.
275
+ const descriptor = /^\d+$/.test(word.text) && (source[word.end] === '>' || source[word.end] === '<');
276
+ if (descriptor) {
277
+ descriptorStart = word.start;
278
+ } else {
279
+ current.words.push(word);
280
+ }
281
+ index = Math.max(word.end, index + 1);
230
282
  }
231
- finish();
232
- return commands;
283
+ }
284
+ finish();
285
+ return commands;
233
286
  }
234
287
  /* Where the `)` that closes the `(` at `open` is, past it; quotes inside do not count. */
235
288
  function closingParen(source, open, to) {
236
- let depth = 0;
237
- let quote = null;
238
- for (let index = open; index < to; index++) {
239
- const char = source[index];
240
- if (quote !== null) {
241
- if (char === quote) {
242
- quote = null;
243
- }
244
- else if (char === '\\' && quote === '"') {
245
- index++;
246
- }
247
- }
248
- else if (char === "'" || char === '"') {
249
- quote = char;
250
- }
251
- else if (char === '(') {
252
- depth++;
253
- }
254
- else if (char === ')') {
255
- depth--;
256
- if (depth === 0) {
257
- return index + 1;
258
- }
259
- }
289
+ let depth = 0;
290
+ let quote = null;
291
+ for (let index = open; index < to; index++) {
292
+ const char = source[index];
293
+ if (quote !== null) {
294
+ if (char === quote) {
295
+ quote = null;
296
+ } else if (char === '\\' && quote === '"') {
297
+ index++;
298
+ }
299
+ } else if (char === "'" || char === '"') {
300
+ quote = char;
301
+ } else if (char === '(') {
302
+ depth++;
303
+ } else if (char === ')') {
304
+ depth--;
305
+ if (depth === 0) {
306
+ return index + 1;
307
+ }
260
308
  }
261
- return to;
309
+ }
310
+ return to;
262
311
  }
263
312
  /* The index of the word a command runs, past variable assignments, wrappers and runners; -1 for none. */
264
313
  function programIndex(words) {
265
- let index = 0;
266
- while (index < words.length) {
267
- const text = words[index].text;
268
- if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(text)) {
269
- index++;
270
- }
271
- else if (WRAPPERS.has(programOf(text))) {
272
- index++;
273
- while (index < words.length && words[index].text.startsWith('-')) {
274
- index++;
275
- }
276
- }
277
- else if (RUNNERS.has(programOf(text)) && words[index + 1]?.text === 'run') {
278
- index += 2;
279
- }
280
- else {
281
- return index;
282
- }
314
+ let index = 0;
315
+ while (index < words.length) {
316
+ const text = words[index].text;
317
+ if (/^[A-Za-z_][A-Za-z0-9_]*=/.test(text)) {
318
+ index++;
319
+ } else if (WRAPPERS.has(programOf(text))) {
320
+ index++;
321
+ while (index < words.length && words[index].text.startsWith('-')) {
322
+ index++;
323
+ }
324
+ } else if (RUNNERS.has(programOf(text)) && words[index + 1]?.text === 'run') {
325
+ index += 2;
326
+ } else {
327
+ return index;
283
328
  }
284
- return -1;
329
+ }
330
+ return -1;
285
331
  }
286
332
  /* The code of one simple command: an inline script, or a heredoc fed to an interpreter or written to a file. */
287
333
  function codeOf(command) {
288
- const found = [];
289
- const at = programIndex(command.words);
290
- const program = at === -1 ? '' : programOf(command.words[at].text);
291
- const interpreter = INTERPRETERS[program];
292
- let readsFile = false;
293
- if (interpreter !== undefined) {
294
- let positional = 0;
295
- for (let index = at + 1; index < command.words.length; index++) {
296
- const word = command.words[index];
297
- if (word.text.startsWith('-') && word.text !== '-') {
298
- if (interpreter.script(word.text)) {
299
- const script = command.words[index + 1];
300
- if (script?.body) {
301
- found.push({ ...script.body, language: interpreter.language });
302
- }
303
- readsFile = true;
304
- index++;
305
- }
306
- else if (interpreter.takesValue?.has(word.text)) {
307
- index++;
308
- }
309
- else if (interpreter === PYTHON && word.text === '-m') {
310
- readsFile = true;
311
- break;
312
- }
313
- continue;
314
- }
315
- if (interpreter.client !== true) {
316
- // A script file; whatever follows is its own arguments.
317
- readsFile = word.text !== '-';
318
- break;
319
- }
320
- if (positional === interpreter.positional && word.body !== null) {
321
- found.push({ ...word.body, language: interpreter.language });
322
- }
323
- positional++;
334
+ const found = [];
335
+ const at = programIndex(command.words);
336
+ const program = at === -1 ? '' : programOf(command.words[at].text);
337
+ const interpreter = INTERPRETERS[program];
338
+ let readsFile = false;
339
+ if (interpreter !== undefined) {
340
+ let positional = 0;
341
+ for (let index = at + 1; index < command.words.length; index++) {
342
+ const word = command.words[index];
343
+ if (word.text.startsWith('-') && word.text !== '-') {
344
+ if (interpreter.script(word.text)) {
345
+ const script = command.words[index + 1];
346
+ if (script?.body) {
347
+ found.push({
348
+ ...script.body,
349
+ language: interpreter.language
350
+ });
351
+ }
352
+ readsFile = true;
353
+ index++;
354
+ } else if (interpreter.takesValue?.has(word.text)) {
355
+ index++;
356
+ } else if (interpreter === PYTHON && word.text === '-m') {
357
+ readsFile = true;
358
+ break;
324
359
  }
360
+ continue;
361
+ }
362
+ if (interpreter.client !== true) {
363
+ // A script file; whatever follows is its own arguments.
364
+ readsFile = word.text !== '-';
365
+ break;
366
+ }
367
+ if (positional === interpreter.positional && word.body !== null) {
368
+ found.push({
369
+ ...word.body,
370
+ language: interpreter.language
371
+ });
372
+ }
373
+ positional++;
325
374
  }
326
- const heredocLanguage = interpreter !== undefined && (!readsFile || interpreter.client === true) ? interpreter.language : writtenLanguage(command, program);
327
- if (heredocLanguage !== null) {
328
- for (const { body } of command.heredocs) {
329
- found.push({ ...body, language: heredocLanguage });
330
- }
375
+ }
376
+ const heredocLanguage = interpreter !== undefined && (!readsFile || interpreter.client === true) ? interpreter.language : writtenLanguage(command, program);
377
+ if (heredocLanguage !== null) {
378
+ for (const {
379
+ body
380
+ } of command.heredocs) {
381
+ found.push({
382
+ ...body,
383
+ language: heredocLanguage
384
+ });
331
385
  }
332
- return found;
386
+ }
387
+ return found;
333
388
  }
334
389
  /* The language of the file a `cat > file` or `tee file` writes, by its extension; null when nothing says. */
335
390
  function writtenLanguage(command, program) {
336
- const targets = command.redirects.filter(({ op }) => op === '>' || op === '>>' || op === '>|').map(({ target }) => target.text);
337
- if (program === 'tee') {
338
- targets.push(...command.words
339
- .slice(programIndex(command.words) + 1)
340
- .map(({ text }) => text)
341
- .filter((text) => !text.startsWith('-')));
342
- }
343
- for (const target of targets) {
344
- const dot = target.lastIndexOf('.');
345
- const language = dot === -1 ? undefined : EXTENSIONS[target.slice(dot + 1).toLowerCase()];
346
- if (language !== undefined) {
347
- return language;
348
- }
391
+ const targets = command.redirects.filter(({
392
+ op
393
+ }) => op === '>' || op === '>>' || op === '>|').map(({
394
+ target
395
+ }) => target.text);
396
+ if (program === 'tee') {
397
+ targets.push(...command.words.slice(programIndex(command.words) + 1).map(({
398
+ text
399
+ }) => text).filter(text => !text.startsWith('-')));
400
+ }
401
+ for (const target of targets) {
402
+ const dot = target.lastIndexOf('.');
403
+ const language = dot === -1 ? undefined : EXTENSIONS[target.slice(dot + 1).toLowerCase()];
404
+ if (language !== undefined) {
405
+ return language;
349
406
  }
350
- return null;
407
+ }
408
+ return null;
351
409
  }
352
410
  function collect(source, from, to, depth, into) {
353
- for (const command of parseCommands(source, from, to)) {
354
- for (const code of codeOf(command)) {
355
- if (code.end <= code.start) {
356
- continue;
357
- }
358
- into.push(code);
359
- if (code.language === SHELL_LANGUAGE && depth < MAX_DEPTH) {
360
- collect(source, code.start, code.end, depth + 1, into);
361
- }
362
- }
411
+ for (const command of parseCommands(source, from, to)) {
412
+ for (const code of codeOf(command)) {
413
+ if (code.end <= code.start) {
414
+ continue;
415
+ }
416
+ into.push(code);
417
+ if (code.language === SHELL_LANGUAGE && depth < MAX_DEPTH) {
418
+ collect(source, code.start, code.end, depth + 1, into);
419
+ }
363
420
  }
421
+ }
364
422
  }
365
423
  /*
366
424
  * The simple commands of a shell line, in the order they come: a pipeline, a list and a line each split
367
425
  * apart, a heredoc with the command it feeds. Only the line itself: the script of a `bash -lc '…'` stays a word.
368
426
  */
369
427
  export function shellCommands(source) {
370
- return parseCommands(source, 0, source.length).map((command) => {
371
- const index = programIndex(command.words);
372
- const word = command.words[index];
373
- return {
374
- ...command,
375
- program: word === undefined ? null : { index, name: word.text.slice(word.text.lastIndexOf('/') + 1) }
376
- };
377
- });
428
+ return parseCommands(source, 0, source.length).map(command => {
429
+ const index = programIndex(command.words);
430
+ const word = command.words[index];
431
+ return {
432
+ ...command,
433
+ program: word === undefined ? null : {
434
+ index,
435
+ name: word.text.slice(word.text.lastIndexOf('/') + 1)
436
+ }
437
+ };
438
+ });
378
439
  }
379
440
  /*
380
441
  * The code inside a shell command that is in another language, or a shell script of its own: the
@@ -384,10 +445,10 @@ export function shellCommands(source) {
384
445
  * grammar, not a parser: what it does not recognize stays plain shell.
385
446
  */
386
447
  export function embeddedCode(command) {
387
- if (command.length > EMBEDDED_CODE_LIMIT) {
388
- return [];
389
- }
390
- const found = [];
391
- collect(command, 0, command.length, 0, found);
392
- return found.sort((left, right) => left.start - right.start || right.end - left.end);
393
- }
448
+ if (command.length > EMBEDDED_CODE_LIMIT) {
449
+ return [];
450
+ }
451
+ const found = [];
452
+ collect(command, 0, command.length, 0, found);
453
+ return found.sort((left, right) => left.start - right.start || right.end - left.end);
454
+ }