cli-jaw 2.0.1 → 2.0.2

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 (607) hide show
  1. package/README.ko.md +3 -2
  2. package/README.md +41 -12
  3. package/dist/bin/_http-client.js +34 -0
  4. package/dist/bin/_http-client.js.map +1 -0
  5. package/dist/bin/cli-jaw.js +10 -5
  6. package/dist/bin/cli-jaw.js.map +1 -1
  7. package/dist/bin/commands/browser-web-ai.js +155 -38
  8. package/dist/bin/commands/browser-web-ai.js.map +1 -1
  9. package/dist/bin/commands/browser.js +265 -37
  10. package/dist/bin/commands/browser.js.map +1 -1
  11. package/dist/bin/commands/chat.js +18 -14
  12. package/dist/bin/commands/chat.js.map +1 -1
  13. package/dist/bin/commands/clone.js +3 -2
  14. package/dist/bin/commands/clone.js.map +1 -1
  15. package/dist/bin/commands/dashboard.js +22 -18
  16. package/dist/bin/commands/dashboard.js.map +1 -1
  17. package/dist/bin/commands/dispatch.js +9 -11
  18. package/dist/bin/commands/dispatch.js.map +1 -1
  19. package/dist/bin/commands/doctor.js +26 -14
  20. package/dist/bin/commands/doctor.js.map +1 -1
  21. package/dist/bin/commands/employee.js +12 -7
  22. package/dist/bin/commands/employee.js.map +1 -1
  23. package/dist/bin/commands/init.js +9 -9
  24. package/dist/bin/commands/init.js.map +1 -1
  25. package/dist/bin/commands/launchd.js +17 -7
  26. package/dist/bin/commands/launchd.js.map +1 -1
  27. package/dist/bin/commands/mcp.js +7 -4
  28. package/dist/bin/commands/mcp.js.map +1 -1
  29. package/dist/bin/commands/memory.js +7 -5
  30. package/dist/bin/commands/memory.js.map +1 -1
  31. package/dist/bin/commands/orchestrate.js +6 -3
  32. package/dist/bin/commands/orchestrate.js.map +1 -1
  33. package/dist/bin/commands/reset.js +4 -3
  34. package/dist/bin/commands/reset.js.map +1 -1
  35. package/dist/bin/commands/serve.js +3 -2
  36. package/dist/bin/commands/serve.js.map +1 -1
  37. package/dist/bin/commands/service.js +2 -2
  38. package/dist/bin/commands/service.js.map +1 -1
  39. package/dist/bin/commands/status.js +10 -9
  40. package/dist/bin/commands/status.js.map +1 -1
  41. package/dist/bin/commands/tui/api.js +26 -18
  42. package/dist/bin/commands/tui/api.js.map +1 -1
  43. package/dist/bin/commands/tui/overlays.js +3 -1
  44. package/dist/bin/commands/tui/overlays.js.map +1 -1
  45. package/dist/bin/commands/tui/simple-mode.js +1 -1
  46. package/dist/bin/commands/tui/simple-mode.js.map +1 -1
  47. package/dist/bin/commands/tui/types.js.map +1 -1
  48. package/dist/bin/postinstall.js +153 -65
  49. package/dist/bin/postinstall.js.map +1 -1
  50. package/dist/bin/star-prompt.js +4 -3
  51. package/dist/bin/star-prompt.js.map +1 -1
  52. package/dist/lib/mcp/format-converters.js +15 -10
  53. package/dist/lib/mcp/format-converters.js.map +1 -1
  54. package/dist/lib/mcp/mcp-install.js +2 -2
  55. package/dist/lib/mcp/mcp-install.js.map +1 -1
  56. package/dist/lib/mcp/skills-distribution.js +2 -2
  57. package/dist/lib/mcp/skills-distribution.js.map +1 -1
  58. package/dist/lib/mcp/skills-reset.js +5 -4
  59. package/dist/lib/mcp/skills-reset.js.map +1 -1
  60. package/dist/lib/mcp/skills-symlinks.js +9 -9
  61. package/dist/lib/mcp/skills-symlinks.js.map +1 -1
  62. package/dist/lib/mcp/skills-utils.js +5 -4
  63. package/dist/lib/mcp/skills-utils.js.map +1 -1
  64. package/dist/lib/mcp/unified-config.js +3 -2
  65. package/dist/lib/mcp/unified-config.js.map +1 -1
  66. package/dist/lib/mime-detect.js +65 -0
  67. package/dist/lib/mime-detect.js.map +1 -0
  68. package/dist/lib/quota-copilot.js +12 -10
  69. package/dist/lib/quota-copilot.js.map +1 -1
  70. package/dist/lib/stt.js +3 -3
  71. package/dist/lib/stt.js.map +1 -1
  72. package/dist/lib/upload.js +14 -5
  73. package/dist/lib/upload.js.map +1 -1
  74. package/dist/scripts/i18n-registry.js +4 -4
  75. package/dist/scripts/i18n-registry.js.map +1 -1
  76. package/dist/server.js +61 -57
  77. package/dist/server.js.map +1 -1
  78. package/dist/src/agent/alert-escalation.js +61 -0
  79. package/dist/src/agent/alert-escalation.js.map +1 -0
  80. package/dist/src/agent/args.js +71 -2
  81. package/dist/src/agent/args.js.map +1 -1
  82. package/dist/src/agent/error-classifier.js +9 -4
  83. package/dist/src/agent/error-classifier.js.map +1 -1
  84. package/dist/src/agent/events.js +130 -101
  85. package/dist/src/agent/events.js.map +1 -1
  86. package/dist/src/agent/lifecycle-handler.js +44 -19
  87. package/dist/src/agent/lifecycle-handler.js.map +1 -1
  88. package/dist/src/agent/live-run-state.js +7 -3
  89. package/dist/src/agent/live-run-state.js.map +1 -1
  90. package/dist/src/agent/memory-flush-controller.js +6 -4
  91. package/dist/src/agent/memory-flush-controller.js.map +1 -1
  92. package/dist/src/agent/opencode-diagnostics.js +7 -6
  93. package/dist/src/agent/opencode-diagnostics.js.map +1 -1
  94. package/dist/src/agent/session-persistence.js +1 -1
  95. package/dist/src/agent/session-persistence.js.map +1 -1
  96. package/dist/src/agent/spawn-env.js +33 -16
  97. package/dist/src/agent/spawn-env.js.map +1 -1
  98. package/dist/src/agent/spawn.js +176 -110
  99. package/dist/src/agent/spawn.js.map +1 -1
  100. package/dist/src/agent/watchdog.js +56 -0
  101. package/dist/src/agent/watchdog.js.map +1 -0
  102. package/dist/src/browser/actions.js +179 -70
  103. package/dist/src/browser/actions.js.map +1 -1
  104. package/dist/src/browser/connection.js +296 -19
  105. package/dist/src/browser/connection.js.map +1 -1
  106. package/dist/src/browser/index.js +4 -1
  107. package/dist/src/browser/index.js.map +1 -1
  108. package/dist/src/browser/launch-policy.js +1 -1
  109. package/dist/src/browser/launch-policy.js.map +1 -1
  110. package/dist/src/browser/primitives.js +11 -7
  111. package/dist/src/browser/primitives.js.map +1 -1
  112. package/dist/src/browser/runtime-diagnostics.js +45 -0
  113. package/dist/src/browser/runtime-diagnostics.js.map +1 -0
  114. package/dist/src/browser/runtime-orphans.js +127 -0
  115. package/dist/src/browser/runtime-orphans.js.map +1 -0
  116. package/dist/src/browser/runtime-owner-store.js +51 -0
  117. package/dist/src/browser/runtime-owner-store.js.map +1 -0
  118. package/dist/src/browser/runtime-owner.js +2 -2
  119. package/dist/src/browser/runtime-owner.js.map +1 -1
  120. package/dist/src/browser/tab-lifecycle.js +157 -0
  121. package/dist/src/browser/tab-lifecycle.js.map +1 -0
  122. package/dist/src/browser/vision.js +35 -11
  123. package/dist/src/browser/vision.js.map +1 -1
  124. package/dist/src/browser/web-ai/action-breadth.js +56 -0
  125. package/dist/src/browser/web-ai/action-breadth.js.map +1 -0
  126. package/dist/src/browser/web-ai/action-cache.js +9 -8
  127. package/dist/src/browser/web-ai/action-cache.js.map +1 -1
  128. package/dist/src/browser/web-ai/action-intent.js +64 -0
  129. package/dist/src/browser/web-ai/action-intent.js.map +1 -0
  130. package/dist/src/browser/web-ai/action-memory.js +82 -0
  131. package/dist/src/browser/web-ai/action-memory.js.map +1 -0
  132. package/dist/src/browser/web-ai/action-trace.js +11 -6
  133. package/dist/src/browser/web-ai/action-trace.js.map +1 -1
  134. package/dist/src/browser/web-ai/annotated-screenshot.js +2 -1
  135. package/dist/src/browser/web-ai/annotated-screenshot.js.map +1 -1
  136. package/dist/src/browser/web-ai/answer-artifact.js +97 -0
  137. package/dist/src/browser/web-ai/answer-artifact.js.map +1 -0
  138. package/dist/src/browser/web-ai/ax-snapshot.js +3 -2
  139. package/dist/src/browser/web-ai/ax-snapshot.js.map +1 -1
  140. package/dist/src/browser/web-ai/browser-primitives.js +10 -7
  141. package/dist/src/browser/web-ai/browser-primitives.js.map +1 -1
  142. package/dist/src/browser/web-ai/capability-registry.js +1 -1
  143. package/dist/src/browser/web-ai/capability-registry.js.map +1 -1
  144. package/dist/src/browser/web-ai/chatgpt-composer.js +12 -12
  145. package/dist/src/browser/web-ai/chatgpt-composer.js.map +1 -1
  146. package/dist/src/browser/web-ai/chatgpt-model.js +469 -50
  147. package/dist/src/browser/web-ai/chatgpt-model.js.map +1 -1
  148. package/dist/src/browser/web-ai/chatgpt-response.js +82 -10
  149. package/dist/src/browser/web-ai/chatgpt-response.js.map +1 -1
  150. package/dist/src/browser/web-ai/chatgpt.js +325 -49
  151. package/dist/src/browser/web-ai/chatgpt.js.map +1 -1
  152. package/dist/src/browser/web-ai/churn-log.js +1 -1
  153. package/dist/src/browser/web-ai/churn-log.js.map +1 -1
  154. package/dist/src/browser/web-ai/cli-sessions.js +42 -26
  155. package/dist/src/browser/web-ai/cli-sessions.js.map +1 -1
  156. package/dist/src/browser/web-ai/context-pack/builder.js +1 -1
  157. package/dist/src/browser/web-ai/context-pack/builder.js.map +1 -1
  158. package/dist/src/browser/web-ai/context-pack/file-selector.js +2 -2
  159. package/dist/src/browser/web-ai/context-pack/file-selector.js.map +1 -1
  160. package/dist/src/browser/web-ai/context-pack/report.js +1 -1
  161. package/dist/src/browser/web-ai/context-pack/report.js.map +1 -1
  162. package/dist/src/browser/web-ai/copy-markdown.js +25 -5
  163. package/dist/src/browser/web-ai/copy-markdown.js.map +1 -1
  164. package/dist/src/browser/web-ai/diagnostics.js +17 -14
  165. package/dist/src/browser/web-ai/diagnostics.js.map +1 -1
  166. package/dist/src/browser/web-ai/doctor.js +10 -6
  167. package/dist/src/browser/web-ai/doctor.js.map +1 -1
  168. package/dist/src/browser/web-ai/dom-hash.js.map +1 -1
  169. package/dist/src/browser/web-ai/errors.js +5 -22
  170. package/dist/src/browser/web-ai/errors.js.map +1 -1
  171. package/dist/src/browser/web-ai/gemini-live.js +7 -6
  172. package/dist/src/browser/web-ai/gemini-live.js.map +1 -1
  173. package/dist/src/browser/web-ai/grok-live.js +9 -5
  174. package/dist/src/browser/web-ai/grok-live.js.map +1 -1
  175. package/dist/src/browser/web-ai/index.js +5 -0
  176. package/dist/src/browser/web-ai/index.js.map +1 -1
  177. package/dist/src/browser/web-ai/observation-bundle.js +90 -0
  178. package/dist/src/browser/web-ai/observation-bundle.js.map +1 -0
  179. package/dist/src/browser/web-ai/observe-actions.js +186 -0
  180. package/dist/src/browser/web-ai/observe-actions.js.map +1 -0
  181. package/dist/src/browser/web-ai/observe-targets.js +6 -1
  182. package/dist/src/browser/web-ai/observe-targets.js.map +1 -1
  183. package/dist/src/browser/web-ai/planner-contract.js +18 -0
  184. package/dist/src/browser/web-ai/planner-contract.js.map +1 -0
  185. package/dist/src/browser/web-ai/post-action-assert.js +8 -7
  186. package/dist/src/browser/web-ai/post-action-assert.js.map +1 -1
  187. package/dist/src/browser/web-ai/product-surfaces.js +2 -1
  188. package/dist/src/browser/web-ai/product-surfaces.js.map +1 -1
  189. package/dist/src/browser/web-ai/provider-adapter.js.map +1 -1
  190. package/dist/src/browser/web-ai/question.js +14 -7
  191. package/dist/src/browser/web-ai/question.js.map +1 -1
  192. package/dist/src/browser/web-ai/ref-registry.js.map +1 -1
  193. package/dist/src/browser/web-ai/self-heal.js +20 -14
  194. package/dist/src/browser/web-ai/self-heal.js.map +1 -1
  195. package/dist/src/browser/web-ai/session-store.js +61 -1
  196. package/dist/src/browser/web-ai/session-store.js.map +1 -1
  197. package/dist/src/browser/web-ai/session.js +43 -2
  198. package/dist/src/browser/web-ai/session.js.map +1 -1
  199. package/dist/src/browser/web-ai/source-audit.js +116 -0
  200. package/dist/src/browser/web-ai/source-audit.js.map +1 -0
  201. package/dist/src/browser/web-ai/tab-finalizer.js +18 -0
  202. package/dist/src/browser/web-ai/tab-finalizer.js.map +1 -0
  203. package/dist/src/browser/web-ai/tab-lease-store.js +390 -0
  204. package/dist/src/browser/web-ai/tab-lease-store.js.map +1 -0
  205. package/dist/src/browser/web-ai/tab-pool.js +44 -0
  206. package/dist/src/browser/web-ai/tab-pool.js.map +1 -0
  207. package/dist/src/browser/web-ai/target-resolver.js +31 -0
  208. package/dist/src/browser/web-ai/target-resolver.js.map +1 -0
  209. package/dist/src/browser/web-ai/trace-persistence.js +4 -2
  210. package/dist/src/browser/web-ai/trace-persistence.js.map +1 -1
  211. package/dist/src/browser/web-ai/vendor-editor-contract.js.map +1 -1
  212. package/dist/src/browser/web-ai/watcher.js +8 -7
  213. package/dist/src/browser/web-ai/watcher.js.map +1 -1
  214. package/dist/src/cli/acp-client.js +40 -26
  215. package/dist/src/cli/acp-client.js.map +1 -1
  216. package/dist/src/cli/command-context.js +3 -3
  217. package/dist/src/cli/command-context.js.map +1 -1
  218. package/dist/src/cli/commands.js +25 -16
  219. package/dist/src/cli/commands.js.map +1 -1
  220. package/dist/src/cli/compact.js.map +1 -1
  221. package/dist/src/cli/handlers-completions.js +6 -4
  222. package/dist/src/cli/handlers-completions.js.map +1 -1
  223. package/dist/src/cli/handlers-runtime.js +45 -38
  224. package/dist/src/cli/handlers-runtime.js.map +1 -1
  225. package/dist/src/cli/handlers.js +44 -36
  226. package/dist/src/cli/handlers.js.map +1 -1
  227. package/dist/src/cli/readiness.js +3 -1
  228. package/dist/src/cli/readiness.js.map +1 -1
  229. package/dist/src/cli/registry.js +1 -1
  230. package/dist/src/cli/registry.js.map +1 -1
  231. package/dist/src/cli/tui/overlay.js +4 -1
  232. package/dist/src/cli/tui/overlay.js.map +1 -1
  233. package/dist/src/cli/types.js +4 -0
  234. package/dist/src/cli/types.js.map +1 -0
  235. package/dist/src/command-contract/catalog.js +1 -1
  236. package/dist/src/command-contract/catalog.js.map +1 -1
  237. package/dist/src/command-contract/help-renderer.js +1 -1
  238. package/dist/src/command-contract/help-renderer.js.map +1 -1
  239. package/dist/src/core/browser-open-default.js +13 -0
  240. package/dist/src/core/browser-open-default.js.map +1 -0
  241. package/dist/src/core/browser-open.js +41 -0
  242. package/dist/src/core/browser-open.js.map +1 -0
  243. package/dist/src/core/bus.js +13 -2
  244. package/dist/src/core/bus.js.map +1 -1
  245. package/dist/src/core/compact.js +5 -4
  246. package/dist/src/core/compact.js.map +1 -1
  247. package/dist/src/core/config.js +51 -52
  248. package/dist/src/core/config.js.map +1 -1
  249. package/dist/src/core/db.js +48 -6
  250. package/dist/src/core/db.js.map +1 -1
  251. package/dist/src/core/employees.js +9 -8
  252. package/dist/src/core/employees.js.map +1 -1
  253. package/dist/src/core/instance.js +7 -6
  254. package/dist/src/core/instance.js.map +1 -1
  255. package/dist/src/core/logger.js +1 -1
  256. package/dist/src/core/logger.js.map +1 -1
  257. package/dist/src/core/main-session.js +7 -7
  258. package/dist/src/core/main-session.js.map +1 -1
  259. package/dist/src/core/path-expand.js +10 -0
  260. package/dist/src/core/path-expand.js.map +1 -0
  261. package/dist/src/core/runtime-path.js +1 -1
  262. package/dist/src/core/runtime-path.js.map +1 -1
  263. package/dist/src/core/runtime-settings.js +13 -13
  264. package/dist/src/core/runtime-settings.js.map +1 -1
  265. package/dist/src/core/settings-merge.js +14 -14
  266. package/dist/src/core/settings-merge.js.map +1 -1
  267. package/dist/src/core/strip-undefined.js +13 -0
  268. package/dist/src/core/strip-undefined.js.map +1 -0
  269. package/dist/src/core/tcc.js +1 -1
  270. package/dist/src/core/tcc.js.map +1 -1
  271. package/dist/src/discord/bot.js +19 -18
  272. package/dist/src/discord/bot.js.map +1 -1
  273. package/dist/src/discord/channel-types.js +14 -0
  274. package/dist/src/discord/channel-types.js.map +1 -0
  275. package/dist/src/discord/commands.js +7 -6
  276. package/dist/src/discord/commands.js.map +1 -1
  277. package/dist/src/discord/discord-file.js.map +1 -1
  278. package/dist/src/discord/forwarder.js +3 -3
  279. package/dist/src/discord/forwarder.js.map +1 -1
  280. package/dist/src/http/error-middleware.js +3 -3
  281. package/dist/src/http/error-middleware.js.map +1 -1
  282. package/dist/src/http/response.js +2 -2
  283. package/dist/src/http/response.js.map +1 -1
  284. package/dist/src/ide/diff.js +7 -7
  285. package/dist/src/ide/diff.js.map +1 -1
  286. package/dist/src/manager/board/routes.js +28 -27
  287. package/dist/src/manager/board/routes.js.map +1 -1
  288. package/dist/src/manager/dashboard-home.js +3 -5
  289. package/dist/src/manager/dashboard-home.js.map +1 -1
  290. package/dist/src/manager/dashboard-service.js +2 -2
  291. package/dist/src/manager/dashboard-service.js.map +1 -1
  292. package/dist/src/manager/health-history.js +10 -9
  293. package/dist/src/manager/health-history.js.map +1 -1
  294. package/dist/src/manager/launchd-service.js +2 -2
  295. package/dist/src/manager/launchd-service.js.map +1 -1
  296. package/dist/src/manager/lifecycle-helpers.js +7 -6
  297. package/dist/src/manager/lifecycle-helpers.js.map +1 -1
  298. package/dist/src/manager/lifecycle.js +7 -6
  299. package/dist/src/manager/lifecycle.js.map +1 -1
  300. package/dist/src/manager/logs.js +18 -18
  301. package/dist/src/manager/logs.js.map +1 -1
  302. package/dist/src/manager/metadata.js +10 -2
  303. package/dist/src/manager/metadata.js.map +1 -1
  304. package/dist/src/manager/notes/assets.js +216 -0
  305. package/dist/src/manager/notes/assets.js.map +1 -0
  306. package/dist/src/manager/notes/capabilities.js +56 -0
  307. package/dist/src/manager/notes/capabilities.js.map +1 -0
  308. package/dist/src/manager/notes/constants.js +11 -0
  309. package/dist/src/manager/notes/constants.js.map +1 -0
  310. package/dist/src/manager/notes/frontmatter.js +120 -0
  311. package/dist/src/manager/notes/frontmatter.js.map +1 -0
  312. package/dist/src/manager/notes/link-resolver.js +96 -0
  313. package/dist/src/manager/notes/link-resolver.js.map +1 -0
  314. package/dist/src/manager/notes/path-guards.js +4 -0
  315. package/dist/src/manager/notes/path-guards.js.map +1 -1
  316. package/dist/src/manager/notes/remote-assets.js +128 -0
  317. package/dist/src/manager/notes/remote-assets.js.map +1 -0
  318. package/dist/src/manager/notes/routes.js +63 -13
  319. package/dist/src/manager/notes/routes.js.map +1 -1
  320. package/dist/src/manager/notes/store.js +3 -2
  321. package/dist/src/manager/notes/store.js.map +1 -1
  322. package/dist/src/manager/notes/system-trash.js +3 -3
  323. package/dist/src/manager/notes/system-trash.js.map +1 -1
  324. package/dist/src/manager/notes/vault-index.js +220 -0
  325. package/dist/src/manager/notes/vault-index.js.map +1 -0
  326. package/dist/src/manager/notes/watcher.js +27 -0
  327. package/dist/src/manager/notes/watcher.js.map +1 -0
  328. package/dist/src/manager/notes/wiki-links.js +109 -0
  329. package/dist/src/manager/notes/wiki-links.js.map +1 -0
  330. package/dist/src/manager/process-verify.js +29 -0
  331. package/dist/src/manager/process-verify.js.map +1 -1
  332. package/dist/src/manager/profiles.js +3 -2
  333. package/dist/src/manager/profiles.js.map +1 -1
  334. package/dist/src/manager/registry.js +60 -58
  335. package/dist/src/manager/registry.js.map +1 -1
  336. package/dist/src/manager/routes/electron-metrics.js +22 -22
  337. package/dist/src/manager/routes/electron-metrics.js.map +1 -1
  338. package/dist/src/manager/scan.js +2 -2
  339. package/dist/src/manager/scan.js.map +1 -1
  340. package/dist/src/manager/schedule/routes.js +24 -23
  341. package/dist/src/manager/schedule/routes.js.map +1 -1
  342. package/dist/src/manager/server.js +28 -28
  343. package/dist/src/manager/server.js.map +1 -1
  344. package/dist/src/manager/systemd-service.js +1 -1
  345. package/dist/src/manager/systemd-service.js.map +1 -1
  346. package/dist/src/memory/bootstrap.js +5 -4
  347. package/dist/src/memory/bootstrap.js.map +1 -1
  348. package/dist/src/memory/heartbeat-schedule.js +10 -10
  349. package/dist/src/memory/heartbeat-schedule.js.map +1 -1
  350. package/dist/src/memory/heartbeat.js +23 -22
  351. package/dist/src/memory/heartbeat.js.map +1 -1
  352. package/dist/src/memory/indexing.js.map +1 -1
  353. package/dist/src/memory/keyword-expand.js +1 -1
  354. package/dist/src/memory/keyword-expand.js.map +1 -1
  355. package/dist/src/memory/memory.js +2 -2
  356. package/dist/src/memory/memory.js.map +1 -1
  357. package/dist/src/memory/runtime.js +6 -5
  358. package/dist/src/memory/runtime.js.map +1 -1
  359. package/dist/src/memory/shared.js +2 -1
  360. package/dist/src/memory/shared.js.map +1 -1
  361. package/dist/src/memory/worklog.js +1 -1
  362. package/dist/src/memory/worklog.js.map +1 -1
  363. package/dist/src/messaging/runtime.js +13 -10
  364. package/dist/src/messaging/runtime.js.map +1 -1
  365. package/dist/src/messaging/send.js +16 -15
  366. package/dist/src/messaging/send.js.map +1 -1
  367. package/dist/src/orchestrator/collect.js +6 -6
  368. package/dist/src/orchestrator/collect.js.map +1 -1
  369. package/dist/src/orchestrator/distribute.js +112 -77
  370. package/dist/src/orchestrator/distribute.js.map +1 -1
  371. package/dist/src/orchestrator/gateway.js +6 -5
  372. package/dist/src/orchestrator/gateway.js.map +1 -1
  373. package/dist/src/orchestrator/pipeline.js +42 -42
  374. package/dist/src/orchestrator/pipeline.js.map +1 -1
  375. package/dist/src/orchestrator/state-machine.js +3 -3
  376. package/dist/src/orchestrator/state-machine.js.map +1 -1
  377. package/dist/src/orchestrator/worker-registry.js +4 -3
  378. package/dist/src/orchestrator/worker-registry.js.map +1 -1
  379. package/dist/src/prompt/builder.js +24 -19
  380. package/dist/src/prompt/builder.js.map +1 -1
  381. package/dist/src/prompt/templates/a1-system.md +15 -10
  382. package/dist/src/prompt/templates/control-system.md +9 -7
  383. package/dist/src/prompt/templates/employee.md +5 -4
  384. package/dist/src/prompt/templates/vision-click.md +1 -1
  385. package/dist/src/routes/_http-error.js +15 -0
  386. package/dist/src/routes/_http-error.js.map +1 -0
  387. package/dist/src/routes/avatar.js +6 -5
  388. package/dist/src/routes/avatar.js.map +1 -1
  389. package/dist/src/routes/browser.js +132 -45
  390. package/dist/src/routes/browser.js.map +1 -1
  391. package/dist/src/routes/employees.js +28 -21
  392. package/dist/src/routes/employees.js.map +1 -1
  393. package/dist/src/routes/heartbeat.js +12 -9
  394. package/dist/src/routes/heartbeat.js.map +1 -1
  395. package/dist/src/routes/i18n.js +13 -7
  396. package/dist/src/routes/i18n.js.map +1 -1
  397. package/dist/src/routes/jaw-memory.js +15 -11
  398. package/dist/src/routes/jaw-memory.js.map +1 -1
  399. package/dist/src/routes/memory.js +25 -20
  400. package/dist/src/routes/memory.js.map +1 -1
  401. package/dist/src/routes/messaging.js +50 -29
  402. package/dist/src/routes/messaging.js.map +1 -1
  403. package/dist/src/routes/orchestrate.js +38 -24
  404. package/dist/src/routes/orchestrate.js.map +1 -1
  405. package/dist/src/routes/quota.js +81 -17
  406. package/dist/src/routes/quota.js.map +1 -1
  407. package/dist/src/routes/settings.js +28 -18
  408. package/dist/src/routes/settings.js.map +1 -1
  409. package/dist/src/routes/skills.js +22 -13
  410. package/dist/src/routes/skills.js.map +1 -1
  411. package/dist/src/routes/traces.js +77 -0
  412. package/dist/src/routes/traces.js.map +1 -0
  413. package/dist/src/security/path-guards.js +2 -1
  414. package/dist/src/security/path-guards.js.map +1 -1
  415. package/dist/src/shared/tool-log-sanitize.js +191 -0
  416. package/dist/src/shared/tool-log-sanitize.js.map +1 -0
  417. package/dist/src/telegram/bot.js +65 -55
  418. package/dist/src/telegram/bot.js.map +1 -1
  419. package/dist/src/telegram/forwarder.js +5 -9
  420. package/dist/src/telegram/forwarder.js.map +1 -1
  421. package/dist/src/telegram/telegram-file.js +28 -24
  422. package/dist/src/telegram/telegram-file.js.map +1 -1
  423. package/dist/src/telegram/voice.js +4 -3
  424. package/dist/src/telegram/voice.js.map +1 -1
  425. package/dist/src/trace/redact.js +50 -0
  426. package/dist/src/trace/redact.js.map +1 -0
  427. package/dist/src/trace/store.js +162 -0
  428. package/dist/src/trace/store.js.map +1 -0
  429. package/dist/src/trace/types.js +2 -0
  430. package/dist/src/trace/types.js.map +1 -0
  431. package/dist/src/types/cli-engine.js +34 -0
  432. package/dist/src/types/cli-engine.js.map +1 -0
  433. package/dist/src/types/cli-events.js +31 -0
  434. package/dist/src/types/cli-events.js.map +1 -0
  435. package/package.json +22 -2
  436. package/public/css/tool-ui.css +3 -1
  437. package/public/css/trace-drawer.css +48 -0
  438. package/public/dist/assets/{AdvancedExport-3WAYIabE.js → AdvancedExport-DJZ2VmBR.js} +1 -1
  439. package/public/dist/assets/Agent-CgpLT8IY.js +1 -0
  440. package/public/dist/assets/Browser-CrkiQoB8.js +1 -0
  441. package/public/dist/assets/{ChannelsDiscord-UzFPlWT4.js → ChannelsDiscord-CVUC22D4.js} +1 -1
  442. package/public/dist/assets/{ChannelsTelegram-DNWtPX0w.js → ChannelsTelegram-DEatIQNM.js} +1 -1
  443. package/public/dist/assets/{DashboardMeta-Y_6nVeJO.js → DashboardMeta-BKoxRc7i.js} +1 -1
  444. package/public/dist/assets/{Display-D8vGOl4s.js → Display-DnNGV9Km.js} +1 -1
  445. package/public/dist/assets/{Employees-YR_sIRK4.js → Employees-DZ2iJYKy.js} +1 -1
  446. package/public/dist/assets/{HealthBadge-CPePajyU.js → HealthBadge-Cq2c7G9s.js} +1 -1
  447. package/public/dist/assets/{Heartbeat-DTpAULQR.js → Heartbeat-BML6eTXZ.js} +1 -1
  448. package/public/dist/assets/{Mcp-DM-PgG6z.js → Mcp-BlEviQ3h.js} +1 -1
  449. package/public/dist/assets/{Memory-C_LvJnkn.js → Memory-BRyH80He.js} +1 -1
  450. package/public/dist/assets/MilkdownWysiwygEditor-Cm3uXfWf.js +52 -0
  451. package/public/dist/assets/ModelProvider-DxyR7EL9.js +1 -0
  452. package/public/dist/assets/Network-DDOOESh1.js +1 -0
  453. package/public/dist/assets/{Permissions-B1naJjjw.js → Permissions-Br0eSbKb.js} +1 -1
  454. package/public/dist/assets/{Permissions-BKffrMJD.js → Permissions-QHkzStqQ.js} +1 -1
  455. package/public/dist/assets/{Profile-DIqjSe2C.js → Profile-C79NKumk.js} +1 -1
  456. package/public/dist/assets/{Prompts-BMfbV6Y4.js → Prompts-BmiIDiXW.js} +1 -1
  457. package/public/dist/assets/{SpeechKeys-DjiQTzSL.js → SpeechKeys-B8304XJK.js} +1 -1
  458. package/public/dist/assets/app-Be58Cs3Y.js +32 -0
  459. package/public/dist/assets/{app-BzvwJJiv.css → app-CphocJzo.css} +1 -1
  460. package/public/dist/assets/{dist-DTvxN3ux.js → dist-BD0UXfgF2.js} +1 -1
  461. package/public/dist/assets/{dist-CASeq-Tl.js → dist-BNfXO3Yr.js} +1 -1
  462. package/public/dist/assets/{dist-BMPiaUzF.js → dist-BUnPYbK3.js} +1 -1
  463. package/public/dist/assets/{dist-CT_X3hVT.js → dist-BZosRD2u.js} +1 -1
  464. package/public/dist/assets/{dist-4J6YbNXv.js → dist-Bd9PlnQm.js} +1 -1
  465. package/public/dist/assets/{dist-BcZjyn5g.js → dist-BsT5UdNP.js} +1 -1
  466. package/public/dist/assets/{dist-BfBhOPR-.js → dist-CIuXW-sc.js} +1 -1
  467. package/public/dist/assets/{dist-BMiCig3A2.js → dist-CL4PTYWf.js} +1 -1
  468. package/public/dist/assets/{dist-VyP6-HLb.js → dist-Ch5VAlV9.js} +1 -1
  469. package/public/dist/assets/dist-ClqO40BE.js +1 -0
  470. package/public/dist/assets/{dist-c98Tp7bP.js → dist-Cp42cMcI.js} +1 -1
  471. package/public/dist/assets/{dist-CIlYL1qe.js → dist-CpUK8ypo.js} +1 -1
  472. package/public/dist/assets/dist-CxeLAw2Y.js +1 -0
  473. package/public/dist/assets/dist-D2SH8nxa.js +1 -0
  474. package/public/dist/assets/{dist-84fwQ7bO.js → dist-D6cUXP7K.js} +1 -1
  475. package/public/dist/assets/{dist-BOCcQAyF.js → dist-D7bCuS3f.js} +1 -1
  476. package/public/dist/assets/{dist-DMmpfLVP.js → dist-DFYRUAjN.js} +1 -1
  477. package/public/dist/assets/{dist-DdY6pTJr.js → dist-DZsFVYF4.js} +1 -1
  478. package/public/dist/assets/{dist-B0p3Eyme.js → dist-Db16ogVk.js} +1 -1
  479. package/public/dist/assets/{dist-DlnNtr6L.js → dist-DfodGES_.js} +1 -1
  480. package/public/dist/assets/{dist-DO9so2a2.js → dist-SU-YTAIg.js} +1 -1
  481. package/public/dist/assets/{dist-DUjXiMLP.js → dist-UYn7T-GH.js} +1 -1
  482. package/public/dist/assets/{dist-BW1409rz.js → dist-W51oDoeA.js} +1 -1
  483. package/public/dist/assets/{dist-BimBQZx1.js → dist-eU7TyC86.js} +1 -1
  484. package/public/dist/assets/dist-l9HH00ip.js +1 -0
  485. package/public/dist/assets/{dist-BrOPNxdH.js → dist-urPTQzXL.js} +1 -1
  486. package/public/dist/assets/{dist-AloEV3J52.js → dist-yHP6L0Ty.js} +1 -1
  487. package/public/dist/assets/{employees-Bbabvbyx.js → employees-CxdghzoD.js} +7 -7
  488. package/public/dist/assets/{error-normalize-DdvKGLt_.js → error-normalize-5n-zlEQ3.js} +1 -1
  489. package/public/dist/assets/insert-image-markdown-DIEa-zjk.js +22 -0
  490. package/public/dist/assets/{manager-DyB2ZUr9.css → manager-DEiyrWDP.css} +1 -1
  491. package/public/dist/assets/manager-UEXd1_9T.js +25 -0
  492. package/public/dist/assets/{memory-B_plvcuQ.js → memory-CsMNkYtv.js} +9 -9
  493. package/public/dist/assets/memory-DXad_DPO.js +1 -0
  494. package/public/dist/assets/{page-shell-DML_HneX.js → page-shell-D5tbivHH.js} +1 -1
  495. package/public/dist/assets/{render-DEhbfUAW.js → render-DGQX46ei.js} +2 -2
  496. package/public/dist/assets/{settings-D7F-_kYG.js → settings-BH213Yv3.js} +14 -14
  497. package/public/dist/assets/settings-DXT87G2U.js +1 -0
  498. package/public/dist/assets/settings-client-ajlwI-oK.js +1 -0
  499. package/public/dist/assets/skills-5o_1v0nz.js +1 -0
  500. package/public/dist/assets/{skills-DoGJOc0D.js → skills-CQtCtHPA.js} +6 -6
  501. package/public/dist/assets/slash-commands-D4-hrrmh.js +1 -0
  502. package/public/dist/assets/{slash-commands-khNFPOyF.js → slash-commands-Dzk1xHWS.js} +1 -1
  503. package/public/dist/assets/trace-drawer-SRKcfm2S.js +15 -0
  504. package/public/dist/assets/ui-CdRKN2S6.js +141 -0
  505. package/public/dist/assets/ui-n43jmg_f.js +1 -0
  506. package/public/dist/assets/{ws-B2aJ-nD2.js → ws-CTHQFzM1.js} +8 -8
  507. package/public/dist/index.html +2 -2
  508. package/public/dist/manager/index.html +2 -2
  509. package/public/index.html +1 -0
  510. package/public/js/constants.ts +5 -5
  511. package/public/js/diagram/iframe-renderer.ts +11 -11
  512. package/public/js/features/chat.ts +1 -1
  513. package/public/js/features/memory.ts +10 -10
  514. package/public/js/features/pending-queue.ts +2 -2
  515. package/public/js/features/process-block.ts +257 -29
  516. package/public/js/features/process-step-match.ts +18 -0
  517. package/public/js/features/settings-cli-status.ts +1 -1
  518. package/public/js/features/settings-stt.ts +37 -11
  519. package/public/js/features/settings-templates.ts +2 -2
  520. package/public/js/features/slash-commands.ts +1 -1
  521. package/public/js/features/tool-ui.ts +13 -7
  522. package/public/js/features/trace-drawer.ts +122 -0
  523. package/public/js/icons.ts +1 -1
  524. package/public/js/main.ts +28 -28
  525. package/public/js/provider-icons.ts +1 -1
  526. package/public/js/render.ts +29 -27
  527. package/public/js/sanitizer.ts +4 -0
  528. package/public/js/ui.ts +234 -68
  529. package/public/js/virtual-scroll.ts +19 -33
  530. package/public/js/ws.ts +22 -10
  531. package/public/manager/src/App.tsx +34 -6
  532. package/public/manager/src/api.ts +55 -1
  533. package/public/manager/src/components/ActivityTimeline.tsx +1 -1
  534. package/public/manager/src/components/InstanceDetailPanel.tsx +2 -2
  535. package/public/manager/src/components/InstanceGroups.tsx +5 -5
  536. package/public/manager/src/components/InstanceListContent.tsx +1 -1
  537. package/public/manager/src/dashboard-features.ts +1 -1
  538. package/public/manager/src/manager-notes.css +49 -2
  539. package/public/manager/src/notes/MarkdownEditor.tsx +7 -3
  540. package/public/manager/src/notes/NotesFileTree.tsx +45 -6
  541. package/public/manager/src/notes/NotesSidebar.tsx +24 -55
  542. package/public/manager/src/notes/NotesWorkspace.tsx +50 -3
  543. package/public/manager/src/notes/image-assets/clipboard-images.ts +100 -0
  544. package/public/manager/src/notes/image-assets/insert-image-markdown.ts +85 -0
  545. package/public/manager/src/notes/notes-api.ts +2 -0
  546. package/public/manager/src/notes/notes-types.ts +8 -1
  547. package/public/manager/src/notes/rendering/MarkdownRenderer.tsx +6 -0
  548. package/public/manager/src/notes/rendering/markdown-render-security.ts +19 -1
  549. package/public/manager/src/notes/rich-markdown/paste-policy.ts +6 -2
  550. package/public/manager/src/notes/rich-markdown/rich-markdown-extension.ts +5 -5
  551. package/public/manager/src/notes/rich-markdown/rich-widget.ts +8 -8
  552. package/public/manager/src/notes/useNotesExternalSync.ts +37 -0
  553. package/public/manager/src/notes/useNotesModel.ts +91 -0
  554. package/public/manager/src/notes/wysiwyg/MilkdownWysiwygEditor.tsx +157 -17
  555. package/public/manager/src/notes/wysiwyg/milkdown-block-keymap.ts +14 -2
  556. package/public/manager/src/notes/wysiwyg/milkdown-code-block-view.ts +20 -20
  557. package/public/manager/src/notes/wysiwyg/milkdown-heading-source-view.ts +8 -8
  558. package/public/manager/src/notes/wysiwyg/milkdown-math.ts +25 -25
  559. package/public/manager/src/settings/pages/Browser.tsx +38 -20
  560. package/public/manager/src/settings/pages/ModelProvider.tsx +11 -9
  561. package/public/manager/src/settings/pages/Network.tsx +10 -10
  562. package/public/manager/src/settings/pages/components/HealthBadge.tsx +12 -12
  563. package/public/manager/src/settings/pages/components/agent/runtime-employees-helpers.ts +12 -10
  564. package/public/manager/src/settings/pages/components/employees-helpers.ts +9 -9
  565. package/public/manager/src/settings/pages/components/heartbeat-helpers.ts +13 -13
  566. package/public/manager/src/settings/pages/components/memory-helpers.ts +4 -4
  567. package/public/manager/src/settings/pages/mcp-helpers.ts +7 -7
  568. package/public/manager/src/settings/settings-client.ts +4 -3
  569. package/public/manager/src/sync/IframeBridge.tsx +29 -0
  570. package/public/manager/src/sync/VisibilityBridge.tsx +24 -0
  571. package/public/manager/src/sync/invalidation-bus.ts +30 -0
  572. package/public/manager/src/sync/useInvalidationSubscription.ts +19 -0
  573. package/public/manager/src/types.ts +101 -0
  574. package/scripts/check-strict-baseline.mjs +255 -0
  575. package/scripts/claim-audit.mjs +159 -0
  576. package/scripts/i18n-registry.ts +4 -4
  577. package/scripts/install-officecli.sh +2 -2
  578. package/scripts/install-wsl.sh +2 -1
  579. package/scripts/release-gates.mjs +347 -0
  580. package/scripts/release-preview.sh +3 -0
  581. package/scripts/release.sh +4 -0
  582. package/scripts/smoke/opencode-external-dir-smoke.ts +14 -5
  583. package/public/dist/assets/Agent-BYdzZwD0.js +0 -1
  584. package/public/dist/assets/Browser-CkGeczuN.js +0 -1
  585. package/public/dist/assets/MilkdownWysiwygEditor-B7k9bAey.js +0 -52
  586. package/public/dist/assets/ModelProvider-CX3Qhowu.js +0 -1
  587. package/public/dist/assets/Network-DfPLFAvw.js +0 -1
  588. package/public/dist/assets/app-DLYoRkU9.js +0 -32
  589. package/public/dist/assets/dist-8zNAQAIa.js +0 -1
  590. package/public/dist/assets/dist-BgeY6nvK.js +0 -1
  591. package/public/dist/assets/dist-BzDGGxHQ.js +0 -1
  592. package/public/dist/assets/dist-D3YKbVi-.js +0 -1
  593. package/public/dist/assets/manager-CUSgFbMO.js +0 -25
  594. package/public/dist/assets/markdown-render-security-DJfJPWO-.js +0 -22
  595. package/public/dist/assets/memory-DQ6dU0qs.js +0 -1
  596. package/public/dist/assets/settings-DxLPUbpj.js +0 -1
  597. package/public/dist/assets/settings-client-CGf3uPPf.js +0 -1
  598. package/public/dist/assets/skills-yMfNYJ8m.js +0 -1
  599. package/public/dist/assets/slash-commands-CZcwr1W6.js +0 -1
  600. package/public/dist/assets/ui-04YlOMgn.js +0 -136
  601. package/public/dist/assets/ui-D6hlMjRq.js +0 -1
  602. /package/public/dist/assets/{InlineWarn-CqgWEC41.js → InlineWarn-BooBRm7o.js} +0 -0
  603. /package/public/dist/assets/{agent-meta-puNn13DV.js → agent-meta-DHddpWHQ.js} +0 -0
  604. /package/public/dist/assets/{fields-DH9JS3mb.js → fields-BtncIZYA.js} +0 -0
  605. /package/public/dist/assets/{mermaid-loader-6XC0y10y.js → mermaid-loader-BEFIOoJn.js} +0 -0
  606. /package/public/dist/assets/{path-utils-CtsDDGZg.js → path-utils-BuEEtj9w.js} +0 -0
  607. /package/public/dist/assets/{w3c-keyname-VSld09PZ.js → w3c-keyname-IiiZScED.js} +0 -0
@@ -6,21 +6,42 @@ export const CHATGPT_MODEL_SELECTOR_BUTTONS = [
6
6
  const CHATGPT_COMPOSER_MODEL_PILL_SELECTORS = [
7
7
  'button.__composer-pill[aria-haspopup="menu"]',
8
8
  '[role="button"].__composer-pill[aria-haspopup="menu"]',
9
+ 'button.__composer-pill',
10
+ '[role="button"].__composer-pill',
11
+ ];
12
+ const CHATGPT_MODEL_MENU_ITEM_SELECTOR = '[data-testid^="model-switcher-gpt-"]';
13
+ const CHATGPT_MODEL_TEXT_BUTTON_PATTERN = /^(ChatGPT|GPT[-\s]?\d|((Light|Standard|Extended|Heavy)\s+)?(Instant|Fast|Thinking|Pro|Heavy)\b)/i;
14
+ const CHATGPT_OBSERVED_PRO_PILL_LABELS = ['Standard Pro', 'Extended Pro'];
15
+ const CHATGPT_EFFORT_TRIGGER_SELECTORS = [
16
+ '[data-testid*="thinking-effort"]',
17
+ '[data-testid*="reasoning-effort"]',
18
+ '[data-testid*="effort"]',
19
+ '[aria-label*="Effort" i]',
20
+ '[aria-label*="Reasoning" i]',
21
+ '[role="menuitem"][aria-label*="Effort" i]',
22
+ '[role="menuitem"][aria-label*="Reasoning" i]',
9
23
  ];
10
- const CHATGPT_MODEL_MENU_ITEM_SELECTOR = '[data-testid^="model-switcher-"]';
11
- const CHATGPT_MODEL_TEXT_BUTTON_PATTERN = /^(Instant|Fast|Thinking|Pro|Heavy)\b/i;
12
24
  export const CHATGPT_MODEL_OPTIONS = {
13
- instant: {
14
- testIds: ['model-switcher-gpt-5-3'],
15
- labels: ['Instant'],
16
- },
25
+ instant: { testIds: ['model-switcher-gpt-5-3'], labels: ['Instant'] },
26
+ thinking: { testIds: ['model-switcher-gpt-5-5-thinking', 'model-switcher-gpt-5-5-thinking-thinking-effort'], labels: ['Thinking'] },
27
+ pro: { testIds: ['model-switcher-gpt-5-5-pro', 'model-switcher-gpt-5-5-pro-thinking-effort'], labels: ['Pro', 'Heavy'] },
28
+ };
29
+ export const CHATGPT_MODEL_EFFORT_OPTIONS = {
17
30
  thinking: {
18
- testIds: ['model-switcher-gpt-5-5-thinking', 'model-switcher-gpt-5-5-thinking-thinking-effort'],
19
- labels: ['Thinking'],
31
+ triggerTestIds: ['model-switcher-gpt-5-5-thinking-thinking-effort'],
32
+ efforts: {
33
+ light: 'Light',
34
+ standard: 'Standard',
35
+ extended: 'Extended',
36
+ heavy: 'Heavy',
37
+ },
20
38
  },
21
39
  pro: {
22
- testIds: ['model-switcher-gpt-5-5-pro', 'model-switcher-gpt-5-5-pro-thinking-effort'],
23
- labels: ['Pro', 'Heavy'],
40
+ triggerTestIds: ['model-switcher-gpt-5-5-pro-thinking-effort'],
41
+ efforts: {
42
+ standard: 'Standard',
43
+ extended: 'Extended',
44
+ },
24
45
  },
25
46
  };
26
47
  const MODEL_ALIASES = {
@@ -36,39 +57,84 @@ const MODEL_ALIASES = {
36
57
  'gpt-5-5-pro': 'pro',
37
58
  'gpt-5.5-pro': 'pro',
38
59
  };
60
+ const EFFORT_ALIASES = {
61
+ light: 'light',
62
+ low: 'light',
63
+ standard: 'standard',
64
+ normal: 'standard',
65
+ regular: 'standard',
66
+ default: 'standard',
67
+ extended: 'extended',
68
+ high: 'extended',
69
+ heavy: 'heavy',
70
+ };
39
71
  export function normalizeChatGptModelChoice(model) {
40
72
  const key = String(model || '').trim().toLowerCase();
41
73
  if (!key)
42
74
  return null;
43
75
  return MODEL_ALIASES[key] || null;
44
76
  }
45
- export async function selectChatGptModel(page, model) {
77
+ export function normalizeChatGptEffortChoice(effort) {
78
+ const key = String(effort || '').trim().toLowerCase();
79
+ if (!key)
80
+ return null;
81
+ return EFFORT_ALIASES[key] || null;
82
+ }
83
+ export function isChatGptEffortSupported(model, effort) {
84
+ const requestedModel = normalizeChatGptModelChoice(model);
85
+ const requestedEffort = normalizeChatGptEffortChoice(effort);
86
+ if ((requestedModel !== 'thinking' && requestedModel !== 'pro') || !requestedEffort)
87
+ return false;
88
+ return Boolean(CHATGPT_MODEL_EFFORT_OPTIONS[requestedModel].efforts[requestedEffort]);
89
+ }
90
+ export async function selectChatGptModel(page, model, options = {}) {
46
91
  const requested = normalizeChatGptModelChoice(model);
92
+ const requestedEffort = normalizeChatGptEffortChoice(options.effort || options.reasoningEffort);
47
93
  if (!requested) {
48
94
  if (model)
49
95
  throw new Error(`unsupported ChatGPT model selection: ${model}`);
50
- return null;
96
+ if (!requestedEffort)
97
+ return null;
98
+ }
99
+ if ((options.effort || options.reasoningEffort) && !requestedEffort) {
100
+ throw new Error(`unsupported ChatGPT reasoning effort: ${options.effort || options.reasoningEffort}`);
51
101
  }
52
102
  const usedFallbacks = [];
53
103
  await openModelMenu(page, usedFallbacks);
54
- const before = await readCheckedModel(page);
55
- if (before === requested) {
104
+ let currentModel = await readCheckedModel(page, requested || null);
105
+ const targetModel = requested || currentModel;
106
+ let modelChanged = false;
107
+ if (!targetModel) {
56
108
  await closeModelMenu(page);
57
- return { requested, selected: before, alreadySelected: true, usedFallbacks };
109
+ throw new Error('ChatGPT model must be selected before setting reasoning effort');
58
110
  }
59
- const option = await findModelOption(page, requested);
60
- if (!option) {
61
- throw new Error(`ChatGPT model option not found: ${requested}`);
111
+ if (requested && currentModel !== requested) {
112
+ const option = await findModelOption(page, requested);
113
+ if (!option)
114
+ throw new Error(`ChatGPT model option not found: ${requested}`);
115
+ await option.click({ timeout: 5_000 });
116
+ await page.waitForTimeout(750).catch(() => undefined);
117
+ await openModelMenu(page, usedFallbacks);
118
+ currentModel = await readCheckedModel(page, requested);
119
+ modelChanged = true;
62
120
  }
63
- await option.click({ timeout: 5_000 });
64
- await page.waitForTimeout(750).catch(() => undefined);
65
- await openModelMenu(page, usedFallbacks);
66
- const after = await readCheckedModel(page);
67
- await closeModelMenu(page);
68
- if (after !== requested) {
69
- throw new Error(`ChatGPT model verification failed: expected ${requested}, got ${after || 'none'}`);
121
+ let selectedEffort = null;
122
+ if (requestedEffort) {
123
+ selectedEffort = await selectChatGptEffort(page, targetModel, requestedEffort, usedFallbacks);
124
+ await openModelMenu(page, usedFallbacks);
70
125
  }
71
- return { requested, selected: after, alreadySelected: false, usedFallbacks };
126
+ const after = await readCheckedModel(page, targetModel);
127
+ await closeModelMenu(page);
128
+ if (after !== targetModel)
129
+ throw new Error(`ChatGPT model verification failed: expected ${targetModel}, got ${after || 'none'}`);
130
+ return {
131
+ requested: requested || targetModel,
132
+ selected: after,
133
+ alreadySelected: !modelChanged && !selectedEffort?.changed,
134
+ effort: selectedEffort?.selected || null,
135
+ requestedEffort: requestedEffort || null,
136
+ usedFallbacks,
137
+ };
72
138
  }
73
139
  async function closeModelMenu(page) {
74
140
  for (let i = 0; i < 3; i += 1) {
@@ -103,8 +169,8 @@ async function openModelMenu(page, usedFallbacks) {
103
169
  await page.waitForTimeout(250).catch(() => undefined);
104
170
  }
105
171
  usedFallbacks.push('model-menu-text-button');
106
- const textButton = page.locator('button').filter({ hasText: /^ChatGPT$|^GPT-|^Instant$|^Fast$|^Thinking$|^Pro$|^Heavy$/i }).first();
107
- if (await textButton.isVisible().catch(() => false)) {
172
+ const textButton = await findModelTextButton(page);
173
+ if (textButton && await textButton.isVisible().catch(() => false)) {
108
174
  await textButton.click({ timeout: 5_000 });
109
175
  await page.waitForTimeout(400).catch(() => undefined);
110
176
  if (await isModelMenuOpen(page))
@@ -113,6 +179,7 @@ async function openModelMenu(page, usedFallbacks) {
113
179
  throw new Error(`ChatGPT model selector not found. Tried: ${[...CHATGPT_MODEL_SELECTOR_BUTTONS, ...CHATGPT_COMPOSER_MODEL_PILL_SELECTORS].join(', ')}`);
114
180
  }
115
181
  async function findComposerModelPill(page) {
182
+ let standaloneHeavy = null;
116
183
  for (const selector of CHATGPT_COMPOSER_MODEL_PILL_SELECTORS) {
117
184
  const candidates = await page.locator(selector).count().catch(() => 0);
118
185
  for (let index = candidates - 1; index >= 0; index -= 1) {
@@ -120,30 +187,289 @@ async function findComposerModelPill(page) {
120
187
  if (!(await loc.isVisible().catch(() => false)))
121
188
  continue;
122
189
  const text = await loc.innerText({ timeout: 1_000 }).catch(() => '');
123
- if (CHATGPT_MODEL_TEXT_BUTTON_PATTERN.test(text.trim()))
124
- return loc;
190
+ const trimmed = text.trim();
191
+ if (!isModelPillText(trimmed))
192
+ continue;
193
+ if (isStandaloneEffortLabel(trimmed)) {
194
+ if (/^Heavy$/i.test(trimmed) && !standaloneHeavy)
195
+ standaloneHeavy = loc;
196
+ continue;
197
+ }
198
+ return loc;
125
199
  }
126
200
  }
127
- const textButton = page.locator('button').filter({ hasText: CHATGPT_MODEL_TEXT_BUTTON_PATTERN }).last();
128
- if (await textButton.isVisible().catch(() => false))
129
- return textButton;
130
- return null;
201
+ return standaloneHeavy || findModelTextButton(page);
202
+ }
203
+ async function findModelTextButton(page) {
204
+ let standaloneHeavy = null;
205
+ const candidates = await page.locator('button').count().catch(() => 0);
206
+ for (let index = candidates - 1; index >= 0; index -= 1) {
207
+ const loc = page.locator('button').nth(index);
208
+ if (!(await loc.isVisible().catch(() => false)))
209
+ continue;
210
+ const text = (await loc.innerText({ timeout: 500 }).catch(() => '')).trim();
211
+ if (!isModelPillText(text))
212
+ continue;
213
+ if (isStandaloneEffortLabel(text)) {
214
+ if (/^Heavy$/i.test(text) && !standaloneHeavy)
215
+ standaloneHeavy = loc;
216
+ continue;
217
+ }
218
+ return loc;
219
+ }
220
+ return standaloneHeavy;
131
221
  }
132
222
  async function findModelOption(page, choice) {
133
223
  const option = CHATGPT_MODEL_OPTIONS[choice];
134
224
  for (const testId of option.testIds) {
135
225
  const loc = page.locator(`[role="menuitemradio"][data-testid="${testId}"], [data-testid="${testId}"]`).first();
136
- if (await loc.isVisible().catch(() => false))
137
- return loc;
226
+ if (!(await loc.isVisible().catch(() => false)))
227
+ continue;
228
+ if (!(await isModelOptionCandidate(loc, choice)))
229
+ continue;
230
+ return loc;
138
231
  }
139
232
  for (const label of option.labels) {
140
- const loc = page.locator('[role="menuitemradio"], [role="menuitem"]').filter({ hasText: new RegExp(`^${label}\\b`, 'i') }).first();
141
- if (await loc.isVisible().catch(() => false))
233
+ const candidates = page.locator('[role="menuitemradio"], [role="menuitem"]').filter({ hasText: modelLabelPattern(choice, label) });
234
+ const count = await candidates.count().catch(() => 0);
235
+ for (let index = 0; index < count; index += 1) {
236
+ const loc = candidates.nth(index);
237
+ if (!(await loc.isVisible().catch(() => false)))
238
+ continue;
239
+ if (!(await isModelOptionCandidate(loc, choice)))
240
+ continue;
142
241
  return loc;
242
+ }
243
+ }
244
+ return null;
245
+ }
246
+ async function isModelOptionCandidate(loc, choice) {
247
+ const text = (await loc.innerText({ timeout: 500 }).catch(() => '')).trim();
248
+ if (!text)
249
+ return false;
250
+ if (isStandaloneEffortLabel(text) || CHATGPT_OBSERVED_PRO_PILL_LABELS.includes(text))
251
+ return false;
252
+ return modelChoiceFromText(text) === choice;
253
+ }
254
+ async function selectChatGptEffort(page, model, effort, usedFallbacks) {
255
+ const config = CHATGPT_MODEL_EFFORT_OPTIONS[model];
256
+ if (!config?.efforts?.[effort])
257
+ throw new Error(`ChatGPT reasoning effort ${effort} is not available for ${model}`);
258
+ await openEffortMenu(page, model, effort, usedFallbacks);
259
+ const before = await readCheckedEffort(page, model);
260
+ if (before === effort)
261
+ return { selected: before, changed: false };
262
+ const option = await findEffortOption(page, model, effort);
263
+ if (!option)
264
+ throw new Error(`ChatGPT reasoning effort option not found: ${model}/${effort}`);
265
+ await option.click({ timeout: 5_000 });
266
+ await page.waitForTimeout(500).catch(() => undefined);
267
+ await openEffortMenu(page, model, effort, usedFallbacks);
268
+ const after = await readCheckedEffort(page, model);
269
+ if (after !== effort)
270
+ throw new Error(`ChatGPT reasoning effort verification failed: expected ${effort}, got ${after || 'none'}`);
271
+ return { selected: after, changed: true };
272
+ }
273
+ async function findEffortOption(page, model, effort) {
274
+ const label = CHATGPT_MODEL_EFFORT_OPTIONS[model]?.efforts?.[effort];
275
+ if (!label)
276
+ return null;
277
+ const candidates = page.locator('[role="menuitemradio"], [role="menuitem"]').filter({ hasText: effortLabelPattern(label) });
278
+ const modelSpecific = candidates.filter({ hasText: modelLabelPattern(model, CHATGPT_MODEL_OPTIONS[model]?.labels?.[0] || '') }).last();
279
+ if (await modelSpecific.isVisible().catch(() => false))
280
+ return modelSpecific;
281
+ const option = candidates.last();
282
+ return (await option.isVisible().catch(() => false)) ? option : null;
283
+ }
284
+ async function openEffortMenu(page, model, effort, usedFallbacks) {
285
+ if (await isEffortMenuOpen(page, model, { effort }))
286
+ return;
287
+ if (!(await isModelMenuOpen(page)))
288
+ await openModelMenu(page, usedFallbacks);
289
+ const config = CHATGPT_MODEL_EFFORT_OPTIONS[model];
290
+ if (!config)
291
+ throw new Error(`ChatGPT reasoning effort is not available for ${model}`);
292
+ const row = await findModelOption(page, model);
293
+ const rowBox = row ? await row.boundingBox().catch(() => null) : null;
294
+ if (rowBox) {
295
+ await page.mouse.move(rowBox.x + rowBox.width / 2, rowBox.y + rowBox.height / 2).catch(() => undefined);
296
+ await page.waitForTimeout(150).catch(() => undefined);
297
+ }
298
+ else if (row) {
299
+ await row.hover({ timeout: 2_000 }).catch(() => undefined);
300
+ }
301
+ for (const testId of config.triggerTestIds) {
302
+ const trigger = page.locator(`[data-testid="${testId}"]`).first();
303
+ if (!(await trigger.count().then(count => count > 0).catch(() => false)))
304
+ continue;
305
+ if (await trigger.isVisible().catch(() => false)) {
306
+ await trigger.click({ timeout: 2_000 }).catch(() => undefined);
307
+ await page.waitForTimeout(300).catch(() => undefined);
308
+ if (await isEffortMenuOpen(page, model, { effort }))
309
+ return;
310
+ await dismissEffortMenuAndReopenModel(page, usedFallbacks);
311
+ }
312
+ }
313
+ for (const selector of CHATGPT_EFFORT_TRIGGER_SELECTORS) {
314
+ const trigger = page.locator(selector).last();
315
+ if (!(await trigger.isVisible().catch(() => false)))
316
+ continue;
317
+ await trigger.click({ timeout: 2_000 }).catch(() => undefined);
318
+ await page.waitForTimeout(300).catch(() => undefined);
319
+ if (await isEffortMenuOpen(page, model, { effort, allowUnlabeled: false })) {
320
+ usedFallbacks.push(`${model}-effort-generic-trigger`);
321
+ return;
322
+ }
323
+ await dismissEffortMenuAndReopenModel(page, usedFallbacks);
324
+ }
325
+ const textTrigger = page.locator('button, [role="button"], [role="menuitem"]').filter({ hasText: /^(Effort|Reasoning effort)$/i }).last();
326
+ if (await textTrigger.isVisible().catch(() => false)) {
327
+ await textTrigger.click({ timeout: 2_000 }).catch(() => undefined);
328
+ await page.waitForTimeout(300).catch(() => undefined);
329
+ if (await isEffortMenuOpen(page, model, { effort, allowUnlabeled: false })) {
330
+ usedFallbacks.push(`${model}-effort-text-trigger`);
331
+ return;
332
+ }
333
+ await dismissEffortMenuAndReopenModel(page, usedFallbacks);
334
+ }
335
+ if (row) {
336
+ await row.focus({ timeout: 1_000 }).catch(() => undefined);
337
+ await page.keyboard.press('ArrowRight').catch(() => undefined);
338
+ await page.waitForTimeout(300).catch(() => undefined);
339
+ if (await isEffortMenuOpen(page, model, { effort })) {
340
+ usedFallbacks.push(`${model}-effort-keyboard-open`);
341
+ return;
342
+ }
343
+ }
344
+ const fallbackBox = await findEffortTriggerBoxNearModelRow(page, model);
345
+ if (fallbackBox) {
346
+ await page.mouse.move(fallbackBox.x + fallbackBox.width / 2, fallbackBox.y + fallbackBox.height / 2).catch(() => undefined);
347
+ await page.waitForTimeout(100).catch(() => undefined);
348
+ await page.mouse.click(fallbackBox.x + fallbackBox.width / 2, fallbackBox.y + fallbackBox.height / 2).catch(() => undefined);
349
+ await page.waitForTimeout(300).catch(() => undefined);
350
+ if (await isEffortMenuOpen(page, model, { effort })) {
351
+ usedFallbacks.push(`${model}-effort-row-button`);
352
+ return;
353
+ }
354
+ }
355
+ usedFallbacks.push(`${model}-effort-trigger`);
356
+ throw new Error(`ChatGPT reasoning effort selector not found for ${model}`);
357
+ }
358
+ async function dismissEffortMenuAndReopenModel(page, usedFallbacks) {
359
+ await page.keyboard.press('Escape').catch(() => undefined);
360
+ await page.waitForTimeout(200).catch(() => undefined);
361
+ await openModelMenu(page, usedFallbacks);
362
+ }
363
+ async function findEffortTriggerBoxNearModelRow(page, model) {
364
+ const labels = CHATGPT_MODEL_OPTIONS[model]?.labels || [];
365
+ return page.evaluate(({ expectedLabels, modelChoice, triggerSelectors }) => {
366
+ const rows = Array.from(document.querySelectorAll('[role="menuitemradio"][data-testid^="model-switcher-"], [role="menuitemradio"]'));
367
+ const row = rows.find((candidate) => {
368
+ const text = (candidate.innerText || candidate.textContent || '').trim();
369
+ return matchesModelText(text, modelChoice, expectedLabels);
370
+ });
371
+ if (!row)
372
+ return null;
373
+ const rowRect = row.getBoundingClientRect();
374
+ const selectorButtons = Array.from(document.querySelectorAll(triggerSelectors.join(',')));
375
+ const textButtons = Array.from(document.querySelectorAll('button, [role="button"], [role="menuitem"]'))
376
+ .filter((candidate) => /^(Effort|Reasoning effort)$/i.test((candidate.innerText || candidate.textContent || '').trim()));
377
+ const effortButtons = [...selectorButtons, ...textButtons];
378
+ const button = effortButtons.find((candidate) => {
379
+ const rect = candidate.getBoundingClientRect();
380
+ const rowCenterY = rowRect.y + rowRect.height / 2;
381
+ return rect.width > 0 && rect.height > 0 && rowCenterY >= rect.y && rowCenterY <= rect.y + rect.height;
382
+ });
383
+ if (!button)
384
+ return null;
385
+ const rect = button.getBoundingClientRect();
386
+ return { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
387
+ function matchesModelText(text, choice, labelsForChoice) {
388
+ if (choice === 'instant')
389
+ return /\b(Instant|Fast)\b/i.test(text);
390
+ if (choice === 'thinking')
391
+ return /\b(Thinking|Think)\b/i.test(text);
392
+ if (choice === 'pro')
393
+ return /\b(Pro|Heavy)\b/i.test(text);
394
+ return labelsForChoice.some(label => new RegExp(`(^|\\s)${label}\\b`, 'i').test(text));
395
+ }
396
+ }, { expectedLabels: labels, modelChoice: model, triggerSelectors: CHATGPT_EFFORT_TRIGGER_SELECTORS }).catch(() => null);
397
+ }
398
+ async function readCheckedEffort(page, model) {
399
+ const config = CHATGPT_MODEL_EFFORT_OPTIONS[model];
400
+ for (const [effort, label] of Object.entries(config?.efforts || {})) {
401
+ const checked = await page.locator('[role="menuitemradio"][aria-checked="true"], [role="menuitemradio"][data-state="checked"]')
402
+ .filter({ hasText: effortLabelPattern(label) })
403
+ .last()
404
+ .isVisible()
405
+ .catch(() => false);
406
+ if (checked)
407
+ return effort;
408
+ }
409
+ const active = await readActiveEffortPill(page);
410
+ for (const [effort, label] of Object.entries(config?.efforts || {})) {
411
+ if (effortLabelPattern(label).test(active))
412
+ return effort;
143
413
  }
144
414
  return null;
145
415
  }
146
- async function readCheckedModel(page) {
416
+ async function isEffortMenuOpen(page, model, options = {}) {
417
+ const allowUnlabeled = options.allowUnlabeled !== false;
418
+ const requestedEffort = options.effort || null;
419
+ const config = CHATGPT_MODEL_EFFORT_OPTIONS[model];
420
+ if (!config)
421
+ return false;
422
+ const labels = Object.values(config.efforts).filter(Boolean);
423
+ const requiredLabels = requiredEffortMenuLabels(model, requestedEffort);
424
+ const unexpectedLabels = Object.entries(CHATGPT_MODEL_EFFORT_OPTIONS)
425
+ .filter(([choice]) => choice !== model)
426
+ .flatMap(([, option]) => Object.values(option.efforts))
427
+ .filter((label) => Boolean(label) && !labels.includes(label));
428
+ return page.locator('[role="menu"]').evaluateAll((menus, { expectedLabels, requiredLabels, unexpectedLabels, modelChoice, allowUnlabeled }) => {
429
+ return menus.some(menu => {
430
+ const text = menu.innerText || menu.textContent || '';
431
+ if (!menuTextMatchesModel(text, modelChoice, allowUnlabeled))
432
+ return false;
433
+ const unexpectedMatches = unexpectedLabels.filter(label => new RegExp(`(^|\\s)${label}(\\s|$)`, 'i').test(text));
434
+ if (unexpectedMatches.length > 0)
435
+ return false;
436
+ const requiredMatches = requiredLabels.filter(label => new RegExp(`(^|\\s)${label}(\\s|$)`, 'i').test(text));
437
+ if (requiredMatches.length < requiredLabels.length)
438
+ return false;
439
+ const matches = expectedLabels.filter(label => new RegExp(`(^|\\s)${label}(\\s|$)`, 'i').test(text));
440
+ const minimumMatches = requiredLabels.length || (expectedLabels.length <= 2 ? expectedLabels.length : Math.min(3, expectedLabels.length));
441
+ return matches.length >= minimumMatches;
442
+ });
443
+ function menuTextMatchesModel(text, choice, permitUnlabeled) {
444
+ const hasThinking = /\b(Thinking|Think)\b/i.test(text);
445
+ const hasPro = /\bPro\b/i.test(text);
446
+ if (!hasThinking && !hasPro)
447
+ return permitUnlabeled;
448
+ if (choice === 'thinking')
449
+ return hasThinking && !hasPro;
450
+ if (choice === 'pro')
451
+ return hasPro && !hasThinking;
452
+ return true;
453
+ }
454
+ }, { expectedLabels: labels, requiredLabels, unexpectedLabels, modelChoice: model, allowUnlabeled }).catch(() => false);
455
+ }
456
+ function requiredEffortMenuLabels(model, effort) {
457
+ const efforts = CHATGPT_MODEL_EFFORT_OPTIONS[model]?.efforts || {};
458
+ if (model === 'thinking') {
459
+ const base = [efforts.standard, efforts.extended].filter(Boolean);
460
+ if (effort === 'light' || effort === 'heavy') {
461
+ return Array.from(new Set([...base, efforts[effort]].filter(Boolean)));
462
+ }
463
+ if (effort === 'standard' || effort === 'extended')
464
+ return base;
465
+ }
466
+ if (model === 'pro')
467
+ return Object.values(efforts).filter(Boolean);
468
+ if (effort && efforts[effort])
469
+ return [efforts[effort]];
470
+ return Object.values(efforts).filter(Boolean);
471
+ }
472
+ async function readCheckedModel(page, expectedModel = null) {
147
473
  for (const [choice, option] of Object.entries(CHATGPT_MODEL_OPTIONS)) {
148
474
  for (const testId of option.testIds) {
149
475
  const checked = await page.locator(`[role="menuitemradio"][data-testid="${testId}"][aria-checked="true"], [data-testid="${testId}"][aria-checked="true"]`).first().isVisible().catch(() => false);
@@ -151,28 +477,121 @@ async function readCheckedModel(page) {
151
477
  return choice;
152
478
  }
153
479
  }
154
- const active = await readActiveModelPill(page);
155
- if (/^(Instant|Fast)\b/i.test(active))
156
- return 'instant';
157
- if (/^Thinking\b/i.test(active))
158
- return 'thinking';
159
- if (/^(Pro|Heavy)\b/i.test(active))
160
- return 'pro';
161
- return null;
480
+ const checkedRows = await page.locator('[role="menuitemradio"][aria-checked="true"], [role="menuitemradio"][data-state="checked"]').all().catch(() => []);
481
+ for (const row of checkedRows) {
482
+ const text = (await row.innerText({ timeout: 500 }).catch(() => '')).trim();
483
+ if (isStandaloneEffortLabel(text))
484
+ continue;
485
+ const choice = modelChoiceFromText(text);
486
+ if (choice)
487
+ return choice;
488
+ }
489
+ const active = await readActiveModelPill(page, { allowStandaloneHeavy: expectedModel === 'pro' });
490
+ return modelChoiceFromText(active);
162
491
  }
163
- async function readActiveModelPill(page) {
492
+ async function readActiveModelPill(page, options = {}) {
493
+ const allowStandaloneHeavy = options.allowStandaloneHeavy === true;
494
+ let standaloneHeavy = '';
495
+ for (const selector of CHATGPT_COMPOSER_MODEL_PILL_SELECTORS) {
496
+ const candidates = await page.locator(selector).count().catch(() => 0);
497
+ for (let index = candidates - 1; index >= 0; index -= 1) {
498
+ const loc = page.locator(selector).nth(index);
499
+ if (!(await loc.isVisible().catch(() => false)))
500
+ continue;
501
+ const text = (await loc.innerText({ timeout: 500 }).catch(() => '')).trim();
502
+ if (!isModelPillText(text))
503
+ continue;
504
+ if (isStandaloneEffortLabel(text)) {
505
+ if (allowStandaloneHeavy && /^Heavy$/i.test(text) && !standaloneHeavy)
506
+ standaloneHeavy = text;
507
+ continue;
508
+ }
509
+ return text;
510
+ }
511
+ }
512
+ const candidates = await page.locator('button').count().catch(() => 0);
513
+ for (let index = candidates - 1; index >= 0; index -= 1) {
514
+ const loc = page.locator('button').nth(index);
515
+ if (!(await loc.isVisible().catch(() => false)))
516
+ continue;
517
+ const text = (await loc.innerText({ timeout: 500 }).catch(() => '')).trim();
518
+ if (!isModelPillText(text))
519
+ continue;
520
+ if (isStandaloneEffortLabel(text)) {
521
+ if (allowStandaloneHeavy && /^Heavy$/i.test(text) && !standaloneHeavy)
522
+ standaloneHeavy = text;
523
+ continue;
524
+ }
525
+ return text;
526
+ }
527
+ return standaloneHeavy;
528
+ }
529
+ async function readActiveEffortPill(page) {
530
+ const labels = [...new Set(Object.values(CHATGPT_MODEL_EFFORT_OPTIONS).flatMap(option => Object.values(option.efforts)).filter(Boolean))];
531
+ for (const selector of CHATGPT_COMPOSER_MODEL_PILL_SELECTORS) {
532
+ const candidates = await page.locator(selector).count().catch(() => 0);
533
+ for (let index = candidates - 1; index >= 0; index -= 1) {
534
+ const loc = page.locator(selector).nth(index);
535
+ if (!(await loc.isVisible().catch(() => false)))
536
+ continue;
537
+ const text = (await loc.innerText({ timeout: 500 }).catch(() => '')).trim();
538
+ if (labels.some(label => effortLabelPattern(label).test(text)))
539
+ return text;
540
+ }
541
+ }
164
542
  const candidates = await page.locator('button').count().catch(() => 0);
165
543
  for (let index = candidates - 1; index >= 0; index -= 1) {
166
544
  const loc = page.locator('button').nth(index);
167
545
  if (!(await loc.isVisible().catch(() => false)))
168
546
  continue;
169
547
  const text = (await loc.innerText({ timeout: 500 }).catch(() => '')).trim();
170
- if (CHATGPT_MODEL_TEXT_BUTTON_PATTERN.test(text))
548
+ if (labels.some(label => effortLabelPattern(label).test(text)))
171
549
  return text;
172
550
  }
173
551
  return '';
174
552
  }
175
553
  async function isModelMenuOpen(page) {
176
- return page.locator(CHATGPT_MODEL_MENU_ITEM_SELECTOR).first().isVisible().catch(() => false);
554
+ return page.locator(CHATGPT_MODEL_MENU_ITEM_SELECTOR)
555
+ .filter({ hasText: CHATGPT_MODEL_TEXT_BUTTON_PATTERN })
556
+ .evaluateAll((items) => items.some((item) => {
557
+ const text = (item.innerText || item.textContent || '').trim();
558
+ const testId = item.getAttribute?.('data-testid') || '';
559
+ if (!text)
560
+ return false;
561
+ if (testId.includes('effort') && /^(Light|Standard|Extended|Heavy|Standard Pro|Extended Pro)$/i.test(text))
562
+ return false;
563
+ return /^(ChatGPT|GPT[-\s]?\d|((Light|Standard|Extended|Heavy)\s+)?(Instant|Fast|Thinking|Pro|Heavy)\b)/i.test(text);
564
+ }))
565
+ .catch(() => false);
566
+ }
567
+ function modelLabelPattern(choice, label) {
568
+ if (choice === 'instant')
569
+ return /\b(Instant|Fast)\b/i;
570
+ if (choice === 'thinking')
571
+ return /\b(Thinking|Think)\b/i;
572
+ if (choice === 'pro')
573
+ return /\b(Pro|Heavy)\b/i;
574
+ return new RegExp(`(^|\\s)${escapeRegExp(label)}\\b`, 'i');
575
+ }
576
+ function effortLabelPattern(label) {
577
+ return new RegExp(`(^|\\s)${escapeRegExp(label)}\\b`, 'i');
578
+ }
579
+ function modelChoiceFromText(text) {
580
+ if (/\b(Instant|Fast)\b/i.test(text))
581
+ return 'instant';
582
+ if (/\b(Thinking|Think)\b/i.test(text))
583
+ return 'thinking';
584
+ if (/\b(Pro|Heavy)\b/i.test(text))
585
+ return 'pro';
586
+ return null;
587
+ }
588
+ function isModelPillText(text) {
589
+ return CHATGPT_MODEL_TEXT_BUTTON_PATTERN.test(text) || CHATGPT_OBSERVED_PRO_PILL_LABELS.includes(text);
590
+ }
591
+ function isStandaloneEffortLabel(text) {
592
+ return /^(Light|Standard|Extended|Heavy)$/i.test(String(text || '').trim());
593
+ }
594
+ function escapeRegExp(value) {
595
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
177
596
  }
178
597
  //# sourceMappingURL=chatgpt-model.js.map