cuelo 0.6.2 → 0.6.4

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 (301) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +10 -8
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.js +1 -1
  6. package/.next/required-server-files.json +1 -1
  7. package/.next/routes-manifest.json +12 -0
  8. package/.next/server/app/_global-error/page.js +3 -3
  9. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/_global-error.html +1 -1
  11. package/.next/server/app/_global-error.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  17. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/.next/server/app/_not-found/page.js +2 -2
  19. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/server/app/_not-found.html +1 -1
  21. package/.next/server/app/_not-found.rsc +3 -3
  22. package/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  24. package/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  25. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  26. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  27. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  28. package/.next/server/app/api/agent/[id]/account/route.js +1 -1
  29. package/.next/server/app/api/agent/[id]/bash-output/route.js +1 -1
  30. package/.next/server/app/api/agent/[id]/events/route.js +1 -1
  31. package/.next/server/app/api/agent/[id]/route.js +1 -1
  32. package/.next/server/app/api/agent/new/route.js +1 -1
  33. package/.next/server/app/api/agent/running/route.js +1 -1
  34. package/.next/server/app/api/attachments/route.js +3 -3
  35. package/.next/server/app/api/auth/all-providers/route.js +1 -1
  36. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
  37. package/.next/server/app/api/auth/login/[provider]/route.js +2 -2
  38. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
  39. package/.next/server/app/api/auth/providers/route.js +1 -1
  40. package/.next/server/app/api/cwd/browse/route.js +1 -1
  41. package/.next/server/app/api/cwd/validate/route.js +1 -1
  42. package/.next/server/app/api/default-cwd/route.js +1 -1
  43. package/.next/server/app/api/display-settings/route.js +1 -1
  44. package/.next/server/app/api/document-text/route.js +2 -2
  45. package/.next/server/app/api/experiments/route.js +1 -1
  46. package/.next/server/app/api/file-index/route.js +1 -1
  47. package/.next/server/app/api/files/[...path]/route.js +1 -1
  48. package/.next/server/app/api/git/diff/route.js +2 -2
  49. package/.next/server/app/api/git/status/route.js +2 -2
  50. package/.next/server/app/api/gpt6/handles/route.js +1 -1
  51. package/.next/server/app/api/gpt6/reply/route.js +1 -1
  52. package/.next/server/app/api/gpt6/token/route.js +1 -1
  53. package/.next/server/app/api/gpt6/web6-session/route.js +1 -1
  54. package/.next/server/app/api/home/route.js +1 -1
  55. package/.next/server/app/api/live/call/[callId]/route.js +1 -1
  56. package/.next/server/app/api/live/events/route.js +2 -2
  57. package/.next/server/app/api/live/offer/route.js +1 -1
  58. package/.next/server/app/api/live/voices/route.js +1 -1
  59. package/.next/server/app/api/lounge/events/route.js +4 -0
  60. package/.next/server/app/api/lounge/events/route.js.nft.json +1 -0
  61. package/.next/server/app/api/lounge/events/route_client-reference-manifest.js +1 -0
  62. package/.next/server/app/api/lounge/route.js +1 -0
  63. package/.next/server/app/api/lounge/route.js.nft.json +1 -0
  64. package/.next/server/app/api/lounge/route_client-reference-manifest.js +1 -0
  65. package/.next/server/app/api/mcp/route.js +2 -2
  66. package/.next/server/app/api/model-roles/route.js +1 -1
  67. package/.next/server/app/api/models/route.js +1 -1
  68. package/.next/server/app/api/models-config/catalog/route.js +1 -1
  69. package/.next/server/app/api/models-config/discover/route.js +1 -1
  70. package/.next/server/app/api/models-config/route.js +3 -3
  71. package/.next/server/app/api/models-config/test/route.js +1 -1
  72. package/.next/server/app/api/plugins/route.js +1 -1
  73. package/.next/server/app/api/project-trust/route.js +1 -1
  74. package/.next/server/app/api/projects/route.js +1 -1
  75. package/.next/server/app/api/runs/[runId]/route.js +1 -1
  76. package/.next/server/app/api/runs/route.js +1 -1
  77. package/.next/server/app/api/sessions/[id]/auto-name/route.js +1 -1
  78. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  79. package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +1 -1
  80. package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
  81. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  82. package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
  83. package/.next/server/app/api/sessions/route.js +1 -1
  84. package/.next/server/app/api/settings/route.js +1 -1
  85. package/.next/server/app/api/sidecars/[service]/[...path]/route.js +1 -1
  86. package/.next/server/app/api/skills/check/route.js +1 -1
  87. package/.next/server/app/api/skills/install/route.js +2 -2
  88. package/.next/server/app/api/skills/route.js +2 -2
  89. package/.next/server/app/api/skills/search/route.js +1 -1
  90. package/.next/server/app/api/skills/update/route.js +1 -1
  91. package/.next/server/app/api/theme/route.js +1 -1
  92. package/.next/server/app/api/tool-image/route.js +1 -1
  93. package/.next/server/app/api/update-maintenance/route.js +2 -2
  94. package/.next/server/app/api/updates/route.js +1 -1
  95. package/.next/server/app/api/web-access/recovery/route.js +1 -1
  96. package/.next/server/app/api/web-access/route.js +1 -1
  97. package/.next/server/app/api/web6/consults/route.js +1 -1
  98. package/.next/server/app/api/worktrees/route.js +1 -1
  99. package/.next/server/app/favicon.ico/route.js +1 -1
  100. package/.next/server/app/index.html +1 -1
  101. package/.next/server/app/index.rsc +6 -6
  102. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  103. package/.next/server/app/index.segments/_full.segment.rsc +6 -6
  104. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  105. package/.next/server/app/index.segments/_index.segment.rsc +3 -3
  106. package/.next/server/app/index.segments/_tree.segment.rsc +3 -3
  107. package/.next/server/app/manifest.webmanifest/route.js +2 -2
  108. package/.next/server/app/page.js +17 -17
  109. package/.next/server/app/page_client-reference-manifest.js +1 -1
  110. package/.next/server/app/recover/page.js +2 -2
  111. package/.next/server/app/recover/page_client-reference-manifest.js +1 -1
  112. package/.next/server/app/recover.html +1 -1
  113. package/.next/server/app/recover.rsc +3 -3
  114. package/.next/server/app/recover.segments/_full.segment.rsc +3 -3
  115. package/.next/server/app/recover.segments/_head.segment.rsc +1 -1
  116. package/.next/server/app/recover.segments/_index.segment.rsc +3 -3
  117. package/.next/server/app/recover.segments/_tree.segment.rsc +2 -2
  118. package/.next/server/app/recover.segments/recover/__PAGE__.segment.rsc +1 -1
  119. package/.next/server/app/recover.segments/recover.segment.rsc +1 -1
  120. package/.next/server/app-paths-manifest.json +10 -8
  121. package/.next/server/chunks/2651.js +2 -2
  122. package/.next/server/chunks/3379.js +1 -1
  123. package/.next/server/chunks/3707.js +5 -0
  124. package/.next/server/chunks/5582.js +1 -1
  125. package/.next/server/chunks/6429.js +5 -5
  126. package/.next/server/functions-config-manifest.json +2 -0
  127. package/.next/server/middleware-build-manifest.js +1 -1
  128. package/.next/server/pages/404.html +1 -1
  129. package/.next/server/pages/500.html +1 -1
  130. package/.next/server/server-reference-manifest.json +1 -1
  131. package/.next/static/chunks/8579-73b103d96227d1b8.js +7 -0
  132. package/.next/static/chunks/app/_global-error/page-d1e510cc33aec52f.js +1 -0
  133. package/.next/static/chunks/app/api/agent/[id]/account/route-d1e510cc33aec52f.js +1 -0
  134. package/.next/static/chunks/app/api/agent/[id]/bash-output/route-d1e510cc33aec52f.js +1 -0
  135. package/.next/static/chunks/app/api/agent/[id]/events/route-d1e510cc33aec52f.js +1 -0
  136. package/.next/static/chunks/app/api/agent/[id]/route-d1e510cc33aec52f.js +1 -0
  137. package/.next/static/chunks/app/api/agent/new/route-d1e510cc33aec52f.js +1 -0
  138. package/.next/static/chunks/app/api/agent/running/route-d1e510cc33aec52f.js +1 -0
  139. package/.next/static/chunks/app/api/attachments/route-d1e510cc33aec52f.js +1 -0
  140. package/.next/static/chunks/app/api/auth/all-providers/route-d1e510cc33aec52f.js +1 -0
  141. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-d1e510cc33aec52f.js +1 -0
  142. package/.next/static/chunks/app/api/auth/login/[provider]/route-d1e510cc33aec52f.js +1 -0
  143. package/.next/static/chunks/app/api/auth/logout/[provider]/route-d1e510cc33aec52f.js +1 -0
  144. package/.next/static/chunks/app/api/auth/providers/route-d1e510cc33aec52f.js +1 -0
  145. package/.next/static/chunks/app/api/cwd/browse/route-d1e510cc33aec52f.js +1 -0
  146. package/.next/static/chunks/app/api/cwd/validate/route-d1e510cc33aec52f.js +1 -0
  147. package/.next/static/chunks/app/api/default-cwd/route-d1e510cc33aec52f.js +1 -0
  148. package/.next/static/chunks/app/api/display-settings/route-d1e510cc33aec52f.js +1 -0
  149. package/.next/static/chunks/app/api/document-text/route-d1e510cc33aec52f.js +1 -0
  150. package/.next/static/chunks/app/api/experiments/route-d1e510cc33aec52f.js +1 -0
  151. package/.next/static/chunks/app/api/file-index/route-d1e510cc33aec52f.js +1 -0
  152. package/.next/static/chunks/app/api/files/[...path]/route-d1e510cc33aec52f.js +1 -0
  153. package/.next/static/chunks/app/api/git/diff/route-d1e510cc33aec52f.js +1 -0
  154. package/.next/static/chunks/app/api/git/status/route-d1e510cc33aec52f.js +1 -0
  155. package/.next/static/chunks/app/api/gpt6/handles/route-d1e510cc33aec52f.js +1 -0
  156. package/.next/static/chunks/app/api/gpt6/reply/route-d1e510cc33aec52f.js +1 -0
  157. package/.next/static/chunks/app/api/gpt6/token/route-d1e510cc33aec52f.js +1 -0
  158. package/.next/static/chunks/app/api/gpt6/web6-session/route-d1e510cc33aec52f.js +1 -0
  159. package/.next/static/chunks/app/api/home/route-d1e510cc33aec52f.js +1 -0
  160. package/.next/static/chunks/app/api/live/call/[callId]/route-d1e510cc33aec52f.js +1 -0
  161. package/.next/static/chunks/app/api/live/events/route-d1e510cc33aec52f.js +1 -0
  162. package/.next/static/chunks/app/api/live/offer/route-d1e510cc33aec52f.js +1 -0
  163. package/.next/static/chunks/app/api/live/voices/route-d1e510cc33aec52f.js +1 -0
  164. package/.next/static/chunks/app/api/lounge/events/route-d1e510cc33aec52f.js +1 -0
  165. package/.next/static/chunks/app/api/lounge/route-d1e510cc33aec52f.js +1 -0
  166. package/.next/static/chunks/app/api/mcp/route-d1e510cc33aec52f.js +1 -0
  167. package/.next/static/chunks/app/api/model-roles/route-d1e510cc33aec52f.js +1 -0
  168. package/.next/static/chunks/app/api/models/route-d1e510cc33aec52f.js +1 -0
  169. package/.next/static/chunks/app/api/models-config/catalog/route-d1e510cc33aec52f.js +1 -0
  170. package/.next/static/chunks/app/api/models-config/discover/route-d1e510cc33aec52f.js +1 -0
  171. package/.next/static/chunks/app/api/models-config/route-d1e510cc33aec52f.js +1 -0
  172. package/.next/static/chunks/app/api/models-config/test/route-d1e510cc33aec52f.js +1 -0
  173. package/.next/static/chunks/app/api/plugins/route-d1e510cc33aec52f.js +1 -0
  174. package/.next/static/chunks/app/api/project-trust/route-d1e510cc33aec52f.js +1 -0
  175. package/.next/static/chunks/app/api/projects/route-d1e510cc33aec52f.js +1 -0
  176. package/.next/static/chunks/app/api/runs/[runId]/route-d1e510cc33aec52f.js +1 -0
  177. package/.next/static/chunks/app/api/runs/route-d1e510cc33aec52f.js +1 -0
  178. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-d1e510cc33aec52f.js +1 -0
  179. package/.next/static/chunks/app/api/sessions/[id]/context/route-d1e510cc33aec52f.js +1 -0
  180. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-d1e510cc33aec52f.js +1 -0
  181. package/.next/static/chunks/app/api/sessions/[id]/export/route-d1e510cc33aec52f.js +1 -0
  182. package/.next/static/chunks/app/api/sessions/[id]/route-d1e510cc33aec52f.js +1 -0
  183. package/.next/static/chunks/app/api/sessions/[id]/state/route-d1e510cc33aec52f.js +1 -0
  184. package/.next/static/chunks/app/api/sessions/route-d1e510cc33aec52f.js +1 -0
  185. package/.next/static/chunks/app/api/settings/route-d1e510cc33aec52f.js +1 -0
  186. package/.next/static/chunks/app/api/sidecars/[service]/[...path]/route-d1e510cc33aec52f.js +1 -0
  187. package/.next/static/chunks/app/api/skills/check/route-d1e510cc33aec52f.js +1 -0
  188. package/.next/static/chunks/app/api/skills/install/route-d1e510cc33aec52f.js +1 -0
  189. package/.next/static/chunks/app/api/skills/route-d1e510cc33aec52f.js +1 -0
  190. package/.next/static/chunks/app/api/skills/search/route-d1e510cc33aec52f.js +1 -0
  191. package/.next/static/chunks/app/api/skills/update/route-d1e510cc33aec52f.js +1 -0
  192. package/.next/static/chunks/app/api/theme/route-d1e510cc33aec52f.js +1 -0
  193. package/.next/static/chunks/app/api/tool-image/route-d1e510cc33aec52f.js +1 -0
  194. package/.next/static/chunks/app/api/update-maintenance/route-d1e510cc33aec52f.js +1 -0
  195. package/.next/static/chunks/app/api/updates/route-d1e510cc33aec52f.js +1 -0
  196. package/.next/static/chunks/app/api/web-access/recovery/route-d1e510cc33aec52f.js +1 -0
  197. package/.next/static/chunks/app/api/web-access/route-d1e510cc33aec52f.js +1 -0
  198. package/.next/static/chunks/app/api/web6/consults/route-d1e510cc33aec52f.js +1 -0
  199. package/.next/static/chunks/app/api/worktrees/route-d1e510cc33aec52f.js +1 -0
  200. package/.next/static/chunks/app/{layout-5d694d9fc13701e0.js → layout-4e015d86866518f5.js} +1 -1
  201. package/.next/static/chunks/app/manifest.webmanifest/route-d1e510cc33aec52f.js +1 -0
  202. package/.next/static/chunks/app/page-1933216030ad4353.js +22 -0
  203. package/.next/static/chunks/next/dist/client/components/builtin/app-error-d1e510cc33aec52f.js +1 -0
  204. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-d1e510cc33aec52f.js +1 -0
  205. package/.next/static/chunks/next/dist/client/components/builtin/not-found-d1e510cc33aec52f.js +1 -0
  206. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d1e510cc33aec52f.js +1 -0
  207. package/.next/static/chunks/{webpack-4094d78ef0b4c382.js → webpack-13c58b226bf07c7e.js} +1 -1
  208. package/.next/static/css/{792a9d55c2fd2c0c.css → 078ee14f375802c0.css} +1 -1
  209. package/.next/static/css/1f257674fb782a57.css +1 -0
  210. package/.next/static/jnfhHGBsVK-Y8Lt6wq9XJ/_buildManifest.js +1 -0
  211. package/.next/trace +105 -104
  212. package/.next/trace-build +1 -1
  213. package/.next/types/app/api/lounge/events/route.ts +351 -0
  214. package/.next/types/app/api/lounge/route.ts +351 -0
  215. package/.next/types/routes.d.ts +3 -1
  216. package/.next/types/validator.ts +18 -0
  217. package/README.md +11 -1
  218. package/Tools/CUELO_Setup/files/native-runtime-patch.js +1 -1
  219. package/Tools/OMP_Global_Config/agent/RULES.md +1 -1
  220. package/Tools/OMP_Global_Config/agent/extensions/character-voice.ts +16 -0
  221. package/Tools/OMP_Global_Config/agent/extensions/lib/mcp-selection.ts +6 -4
  222. package/Tools/OMP_Global_Config/agent/extensions/steering-reply-gate.ts +12 -3
  223. package/Tools/OMP_Global_Config/agent/prompt-copies/RULES.en.md +2 -2
  224. package/Tools/OMP_Global_Config/patches/apply-core-patch.mjs +982 -0
  225. package/package.json +2 -1
  226. package/.next/static/HIeC4quKEySGkt_zoRmeC/_buildManifest.js +0 -1
  227. package/.next/static/chunks/6379-7da431a165ac5d41.js +0 -7
  228. package/.next/static/chunks/app/_global-error/page-0c0ee2cbde2b8cfd.js +0 -1
  229. package/.next/static/chunks/app/api/agent/[id]/account/route-0c0ee2cbde2b8cfd.js +0 -1
  230. package/.next/static/chunks/app/api/agent/[id]/bash-output/route-0c0ee2cbde2b8cfd.js +0 -1
  231. package/.next/static/chunks/app/api/agent/[id]/events/route-0c0ee2cbde2b8cfd.js +0 -1
  232. package/.next/static/chunks/app/api/agent/[id]/route-0c0ee2cbde2b8cfd.js +0 -1
  233. package/.next/static/chunks/app/api/agent/new/route-0c0ee2cbde2b8cfd.js +0 -1
  234. package/.next/static/chunks/app/api/agent/running/route-0c0ee2cbde2b8cfd.js +0 -1
  235. package/.next/static/chunks/app/api/attachments/route-0c0ee2cbde2b8cfd.js +0 -1
  236. package/.next/static/chunks/app/api/auth/all-providers/route-0c0ee2cbde2b8cfd.js +0 -1
  237. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-0c0ee2cbde2b8cfd.js +0 -1
  238. package/.next/static/chunks/app/api/auth/login/[provider]/route-0c0ee2cbde2b8cfd.js +0 -1
  239. package/.next/static/chunks/app/api/auth/logout/[provider]/route-0c0ee2cbde2b8cfd.js +0 -1
  240. package/.next/static/chunks/app/api/auth/providers/route-0c0ee2cbde2b8cfd.js +0 -1
  241. package/.next/static/chunks/app/api/cwd/browse/route-0c0ee2cbde2b8cfd.js +0 -1
  242. package/.next/static/chunks/app/api/cwd/validate/route-0c0ee2cbde2b8cfd.js +0 -1
  243. package/.next/static/chunks/app/api/default-cwd/route-0c0ee2cbde2b8cfd.js +0 -1
  244. package/.next/static/chunks/app/api/display-settings/route-0c0ee2cbde2b8cfd.js +0 -1
  245. package/.next/static/chunks/app/api/document-text/route-0c0ee2cbde2b8cfd.js +0 -1
  246. package/.next/static/chunks/app/api/experiments/route-0c0ee2cbde2b8cfd.js +0 -1
  247. package/.next/static/chunks/app/api/file-index/route-0c0ee2cbde2b8cfd.js +0 -1
  248. package/.next/static/chunks/app/api/files/[...path]/route-0c0ee2cbde2b8cfd.js +0 -1
  249. package/.next/static/chunks/app/api/git/diff/route-0c0ee2cbde2b8cfd.js +0 -1
  250. package/.next/static/chunks/app/api/git/status/route-0c0ee2cbde2b8cfd.js +0 -1
  251. package/.next/static/chunks/app/api/gpt6/handles/route-0c0ee2cbde2b8cfd.js +0 -1
  252. package/.next/static/chunks/app/api/gpt6/reply/route-0c0ee2cbde2b8cfd.js +0 -1
  253. package/.next/static/chunks/app/api/gpt6/token/route-0c0ee2cbde2b8cfd.js +0 -1
  254. package/.next/static/chunks/app/api/gpt6/web6-session/route-0c0ee2cbde2b8cfd.js +0 -1
  255. package/.next/static/chunks/app/api/home/route-0c0ee2cbde2b8cfd.js +0 -1
  256. package/.next/static/chunks/app/api/live/call/[callId]/route-0c0ee2cbde2b8cfd.js +0 -1
  257. package/.next/static/chunks/app/api/live/events/route-0c0ee2cbde2b8cfd.js +0 -1
  258. package/.next/static/chunks/app/api/live/offer/route-0c0ee2cbde2b8cfd.js +0 -1
  259. package/.next/static/chunks/app/api/live/voices/route-0c0ee2cbde2b8cfd.js +0 -1
  260. package/.next/static/chunks/app/api/mcp/route-0c0ee2cbde2b8cfd.js +0 -1
  261. package/.next/static/chunks/app/api/model-roles/route-0c0ee2cbde2b8cfd.js +0 -1
  262. package/.next/static/chunks/app/api/models/route-0c0ee2cbde2b8cfd.js +0 -1
  263. package/.next/static/chunks/app/api/models-config/catalog/route-0c0ee2cbde2b8cfd.js +0 -1
  264. package/.next/static/chunks/app/api/models-config/discover/route-0c0ee2cbde2b8cfd.js +0 -1
  265. package/.next/static/chunks/app/api/models-config/route-0c0ee2cbde2b8cfd.js +0 -1
  266. package/.next/static/chunks/app/api/models-config/test/route-0c0ee2cbde2b8cfd.js +0 -1
  267. package/.next/static/chunks/app/api/plugins/route-0c0ee2cbde2b8cfd.js +0 -1
  268. package/.next/static/chunks/app/api/project-trust/route-0c0ee2cbde2b8cfd.js +0 -1
  269. package/.next/static/chunks/app/api/projects/route-0c0ee2cbde2b8cfd.js +0 -1
  270. package/.next/static/chunks/app/api/runs/[runId]/route-0c0ee2cbde2b8cfd.js +0 -1
  271. package/.next/static/chunks/app/api/runs/route-0c0ee2cbde2b8cfd.js +0 -1
  272. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-0c0ee2cbde2b8cfd.js +0 -1
  273. package/.next/static/chunks/app/api/sessions/[id]/context/route-0c0ee2cbde2b8cfd.js +0 -1
  274. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-0c0ee2cbde2b8cfd.js +0 -1
  275. package/.next/static/chunks/app/api/sessions/[id]/export/route-0c0ee2cbde2b8cfd.js +0 -1
  276. package/.next/static/chunks/app/api/sessions/[id]/route-0c0ee2cbde2b8cfd.js +0 -1
  277. package/.next/static/chunks/app/api/sessions/[id]/state/route-0c0ee2cbde2b8cfd.js +0 -1
  278. package/.next/static/chunks/app/api/sessions/route-0c0ee2cbde2b8cfd.js +0 -1
  279. package/.next/static/chunks/app/api/settings/route-0c0ee2cbde2b8cfd.js +0 -1
  280. package/.next/static/chunks/app/api/sidecars/[service]/[...path]/route-0c0ee2cbde2b8cfd.js +0 -1
  281. package/.next/static/chunks/app/api/skills/check/route-0c0ee2cbde2b8cfd.js +0 -1
  282. package/.next/static/chunks/app/api/skills/install/route-0c0ee2cbde2b8cfd.js +0 -1
  283. package/.next/static/chunks/app/api/skills/route-0c0ee2cbde2b8cfd.js +0 -1
  284. package/.next/static/chunks/app/api/skills/search/route-0c0ee2cbde2b8cfd.js +0 -1
  285. package/.next/static/chunks/app/api/skills/update/route-0c0ee2cbde2b8cfd.js +0 -1
  286. package/.next/static/chunks/app/api/theme/route-0c0ee2cbde2b8cfd.js +0 -1
  287. package/.next/static/chunks/app/api/tool-image/route-0c0ee2cbde2b8cfd.js +0 -1
  288. package/.next/static/chunks/app/api/update-maintenance/route-0c0ee2cbde2b8cfd.js +0 -1
  289. package/.next/static/chunks/app/api/updates/route-0c0ee2cbde2b8cfd.js +0 -1
  290. package/.next/static/chunks/app/api/web-access/recovery/route-0c0ee2cbde2b8cfd.js +0 -1
  291. package/.next/static/chunks/app/api/web-access/route-0c0ee2cbde2b8cfd.js +0 -1
  292. package/.next/static/chunks/app/api/web6/consults/route-0c0ee2cbde2b8cfd.js +0 -1
  293. package/.next/static/chunks/app/api/worktrees/route-0c0ee2cbde2b8cfd.js +0 -1
  294. package/.next/static/chunks/app/manifest.webmanifest/route-0c0ee2cbde2b8cfd.js +0 -1
  295. package/.next/static/chunks/app/page-8351ec13279453b5.js +0 -22
  296. package/.next/static/chunks/next/dist/client/components/builtin/app-error-0c0ee2cbde2b8cfd.js +0 -1
  297. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-0c0ee2cbde2b8cfd.js +0 -1
  298. package/.next/static/chunks/next/dist/client/components/builtin/not-found-0c0ee2cbde2b8cfd.js +0 -1
  299. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-0c0ee2cbde2b8cfd.js +0 -1
  300. package/.next/static/css/bbe00993de567f95.css +0 -1
  301. /package/.next/static/{HIeC4quKEySGkt_zoRmeC → jnfhHGBsVK-Y8Lt6wq9XJ}/_ssgManifest.js +0 -0
@@ -5636,6 +5636,988 @@ function matchesFilter(window: DesktopWindow, filter?: WindowFilter): boolean {
5636
5636
  assertWindowFilter(filter);
5637
5637
  const { signal } = getContext();`,
5638
5638
  },
5639
+ {
5640
+ // 2026-09-29 computer 행동 결과 표준화와 stale ref 재획득. 행동은 void 대신 표준 결과
5641
+ // {action, status, suggestedNext, escalation?, evidence?, ref, reacquired?}를 돌려준다. 참고 설계:
5642
+ // Cua action-result 계약(https://github.com/trycua/cua/blob/main/libs/cua-driver/docs/action-result-contract.md
5643
+ // — 전달은 효과의 증거가 아니다, readback만 verified 근거)과 browser-use의 단계별 요소 재식별
5644
+ // (https://github.com/browser-use/browser-use/blob/main/browser_use/agent/service.py
5645
+ // — EXACT→STABLE→XPATH→AX_NAME→ATTRIBUTE). 발급한 ref마다 지문(role·nativeRole·title·description·
5646
+ // bounds·AutomationId·RuntimeId·창 안 이름 있는 조상 경로)을 세션 등록부에 두고, stale이면 axQuery
5647
+ // (ref 세대를 올리지 않는다, 실측)로 같은 요소를 찾는다. 후보 0개·경로 불일치·동점·지문 없음이면 다른
5648
+ // 요소를 건드리지 않고 원래 StaleRef로 실패하며 사유를 error.computerAction에 남긴다.
5649
+ // readback은 행동 전·후 1회씩이고, readback 실패는 행동 실패가 아니라 unverified다.
5650
+ file: "src/tools/computer/worker.ts",
5651
+ marker: "class RefBook {",
5652
+ anchor: `class El {
5653
+ readonly ref: string;
5654
+ readonly role: string;
5655
+ readonly nativeRole: string;
5656
+ readonly title?: string;
5657
+ readonly description?: string;
5658
+ readonly enabled: boolean;
5659
+ readonly focused: boolean;
5660
+ readonly childCount: number;
5661
+ readonly #session: NativeDesktopSession;
5662
+ readonly #getContext: RunContextAccessor;
5663
+
5664
+ constructor(session: NativeDesktopSession, getContext: RunContextAccessor, node: AxNode) {
5665
+ this.#session = session;
5666
+ this.#getContext = getContext;
5667
+ this.ref = node.ref;
5668
+ this.role = node.role;
5669
+ this.nativeRole = node.nativeRole;
5670
+ this.title = node.title;
5671
+ this.description = node.description;
5672
+ this.enabled = node.enabled;
5673
+ this.focused = node.focused;
5674
+ this.childCount = node.childCount;
5675
+ }
5676
+
5677
+ async value(): Promise<string | undefined> {
5678
+ const { signal } = this.#getContext();
5679
+ return (await nativeCall(signal, () => this.#session.axNode(this.ref))).value;
5680
+ }
5681
+
5682
+ async setValue(value: string): Promise<void> {
5683
+ const context = this.#getContext();
5684
+ guardRun(context, "setValue");
5685
+ await nativeCall(context.signal, () => this.#session.axSetValue(this.ref, value));
5686
+ }
5687
+
5688
+ async bounds(): Promise<{ x: number; y: number; width: number; height: number } | null> {
5689
+ const { signal } = this.#getContext();
5690
+ const node = await nativeCall(signal, () => this.#session.axNode(this.ref));
5691
+ if (node.x === undefined || node.y === undefined || node.width === undefined || node.height === undefined)
5692
+ return null;
5693
+ return { x: node.x, y: node.y, width: node.width, height: node.height };
5694
+ }
5695
+
5696
+ async attributes(): Promise<Record<string, string>> {
5697
+ const { signal } = this.#getContext();
5698
+ return Object.fromEntries(await nativeCall(signal, () => this.#session.axAttributes(this.ref)));
5699
+ }
5700
+
5701
+ async actions(): Promise<string[]> {
5702
+ const { signal } = this.#getContext();
5703
+ return (await nativeCall(signal, () => this.#session.axNode(this.ref))).actions ?? [];
5704
+ }
5705
+
5706
+ async perform(action: string): Promise<void> {
5707
+ const context = this.#getContext();
5708
+ guardRun(context, "perform");
5709
+ await nativeCall(context.signal, () => this.#session.axPerform(this.ref, action));
5710
+ }
5711
+
5712
+ async press(): Promise<void> {
5713
+ const context = this.#getContext();
5714
+ guardRun(context, "press");
5715
+ await nativeCall(context.signal, () => this.#session.axPerform(this.ref, "press"));
5716
+ }
5717
+
5718
+ async click(options?: InputOptions): Promise<void> {
5719
+ const context = this.#getContext();
5720
+ guardRun(context, "click");
5721
+ await nativeCall(context.signal, () => this.#session.axClick(this.ref, pointerOptions(options)));
5722
+ }
5723
+
5724
+ async focus(): Promise<void> {
5725
+ const context = this.#getContext();
5726
+ guardRun(context, "focus");
5727
+ await nativeCall(context.signal, () => this.#session.axFocus(this.ref));
5728
+ }
5729
+
5730
+ async parent(): Promise<El | null> {
5731
+ const { signal } = this.#getContext();
5732
+ const node = await nativeCall(signal, () => this.#session.axParent(this.ref));
5733
+ return node ? new El(this.#session, this.#getContext, node) : null;
5734
+ }
5735
+
5736
+ async children(): Promise<El[]> {
5737
+ const { signal } = this.#getContext();
5738
+ return (await nativeCall(signal, () => this.#session.axChildren(this.ref))).map(
5739
+ node => new El(this.#session, this.#getContext, node),
5740
+ );
5741
+ }
5742
+ }`,
5743
+ patched: `type AxBounds = { x: number; y: number; width: number; height: number };
5744
+
5745
+ /** Outcome of one computer action. Delivery is not proof of effect: only an AX readback makes it \`verified\`. */
5746
+ interface ComputerActionResult {
5747
+ action: string;
5748
+ /** verified: a readback shows the change. unverified: delivered, effect not observed. suspected_noop: the readback contradicts the intended change. */
5749
+ status: "verified" | "unverified" | "suspected_noop";
5750
+ suggestedNext: "continue" | "reobserve" | "escalate";
5751
+ escalation?: { target: "pixel" | "takeover"; reason: string };
5752
+ evidence?: string;
5753
+ ref?: string;
5754
+ reacquired?: ComputerReacquired;
5755
+ }
5756
+
5757
+ interface ComputerReacquired {
5758
+ from: string;
5759
+ to: string;
5760
+ matchedBy: string;
5761
+ }
5762
+
5763
+ type ReacquireRefusal = "no-fingerprint" | "no-window" | "no-candidate" | "parent-mismatch" | "ambiguous";
5764
+
5765
+ interface ComputerRefCandidate {
5766
+ ref: string;
5767
+ role: string;
5768
+ title?: string;
5769
+ bounds?: AxBounds;
5770
+ }
5771
+
5772
+ /** Facts attached to a failed action as \`error.computerAction\`; the error type and first message line stay unchanged. */
5773
+ interface ComputerActionRefusal {
5774
+ action: string;
5775
+ status: "refused";
5776
+ suggestedNext: "reobserve" | "escalate";
5777
+ escalation?: { target: "takeover"; reason: string };
5778
+ ref?: string;
5779
+ reacquire?: { outcome: ReacquireRefusal; candidates: ComputerRefCandidate[] };
5780
+ }
5781
+
5782
+ /** Identity kept for an issued ref so a stale ref can be found again with a fresh AX query. */
5783
+ interface AxFingerprint {
5784
+ windowId?: string;
5785
+ role: string;
5786
+ /** Undefined when the source (an ax() text line) does not carry the field. */
5787
+ nativeRole?: string;
5788
+ title: string;
5789
+ description?: string;
5790
+ bounds?: AxBounds;
5791
+ automationId?: string;
5792
+ runtimeId?: string;
5793
+ /** Named ancestors inside the window, nearest first, ending with "window" when the window is reached. */
5794
+ parentPath?: string[];
5795
+ }
5796
+
5797
+ type IdentityAttributes = Pick<AxFingerprint, "automationId" | "runtimeId">;
5798
+ type Judged = Pick<ComputerActionResult, "status" | "suggestedNext" | "escalation" | "evidence">;
5799
+ type ReacquireOutcome =
5800
+ | { node: AxNode; matchedBy: string; print: AxFingerprint }
5801
+ | { node?: undefined; outcome: ReacquireRefusal; candidates: ComputerRefCandidate[] };
5802
+
5803
+ const REF_BOOK_LIMIT = 4000;
5804
+ const PARENT_WALK_LIMIT = 12;
5805
+ const PARENT_NAMED_LIMIT = 3;
5806
+ /** Walking parents costs a native call per level, so bulk issues (large find results) skip it. */
5807
+ const PARENT_WALK_BATCH = 8;
5808
+ const REACQUIRE_QUERY_LIMIT = 500;
5809
+ const CANDIDATE_REPORT_LIMIT = 5;
5810
+ /** Element fields whose change after press/click/perform counts as readback evidence; focus alone does not. */
5811
+ const ELEMENT_STATE_KEYS = ["value", "title", "enabled", "childCount", "x", "y", "width", "height"] as const;
5812
+ /** One ax() text line: indentation, role, optional quoted title, ref. */
5813
+ const SNAPSHOT_LINE = /^( *)- ([^ ]+)(?: "(.*?)")? [[]ref=(e[0-9]+)/;
5814
+
5815
+ const refBooks = new WeakMap<NativeDesktopSession, RefBook>();
5816
+
5817
+ function refBook(session: NativeDesktopSession): RefBook {
5818
+ let book = refBooks.get(session);
5819
+ if (!book) {
5820
+ book = new RefBook();
5821
+ refBooks.set(session, book);
5822
+ }
5823
+ return book;
5824
+ }
5825
+
5826
+ function trimOldest(map: Map<string, unknown>): void {
5827
+ if (map.size > REF_BOOK_LIMIT) map.delete(map.keys().next().value as string);
5828
+ }
5829
+
5830
+ function boundsOf(node: AxNode): AxBounds | undefined {
5831
+ if (node.x === undefined || node.y === undefined || node.width === undefined || node.height === undefined)
5832
+ return undefined;
5833
+ return { x: node.x, y: node.y, width: node.width, height: node.height };
5834
+ }
5835
+
5836
+ function nodePrint(node: AxNode): AxFingerprint {
5837
+ return {
5838
+ role: node.role,
5839
+ nativeRole: node.nativeRole,
5840
+ title: node.title ?? "",
5841
+ description: node.description ?? "",
5842
+ bounds: boundsOf(node),
5843
+ };
5844
+ }
5845
+
5846
+ function decodeTitle(raw: string | undefined): string {
5847
+ if (raw === undefined) return "";
5848
+ try {
5849
+ const decoded: unknown = JSON.parse('"' + raw + '"');
5850
+ return typeof decoded === "string" ? decoded : raw;
5851
+ } catch {
5852
+ return raw;
5853
+ }
5854
+ }
5855
+
5856
+ /** Nearest named ancestors, stopping at the enclosing window; unnamed containers are skipped because ax() text may hide them. */
5857
+ function namedPath(ancestors: Iterable<{ role: string; title?: string }>): string[] {
5858
+ const path: string[] = [];
5859
+ for (const ancestor of ancestors) {
5860
+ if (ancestor.role === "window") {
5861
+ path.push("window");
5862
+ break;
5863
+ }
5864
+ if (ancestor.title) path.push(ancestor.role + ":" + ancestor.title);
5865
+ if (path.length === PARENT_NAMED_LIMIT) break;
5866
+ }
5867
+ return path;
5868
+ }
5869
+
5870
+ function samePath(left: string[], right: string[]): boolean {
5871
+ return left.length === right.length && left.every((entry, index) => entry === right[index]);
5872
+ }
5873
+
5874
+ function attributeText(raw: string | undefined): string | undefined {
5875
+ if (raw === undefined) return undefined;
5876
+ const value = /^[A-Z0-9_]+[(](.*)[)]$/s.exec(raw)?.[1] ?? raw;
5877
+ return value === "" ? undefined : value;
5878
+ }
5879
+
5880
+ function isStaleRef(error: unknown): error is ToolError {
5881
+ return error instanceof ToolError && error.message.startsWith("StaleRef:");
5882
+ }
5883
+
5884
+ function candidateOf(node: AxNode): ComputerRefCandidate {
5885
+ return { ref: node.ref, role: node.role, title: node.title, bounds: boundsOf(node) };
5886
+ }
5887
+
5888
+ function nearBounds(node: AxNode, bounds: AxBounds): boolean {
5889
+ const now = boundsOf(node);
5890
+ if (!now) return false;
5891
+ const dx = Math.abs(now.x + now.width / 2 - (bounds.x + bounds.width / 2));
5892
+ const dy = Math.abs(now.y + now.height / 2 - (bounds.y + bounds.height / 2));
5893
+ return dx <= Math.max(8, bounds.width / 2) && dy <= Math.max(8, bounds.height / 2);
5894
+ }
5895
+
5896
+ /** Session-scoped fingerprints of issued refs and where reacquired stale refs now point. Bounded; oldest entries drop first. */
5897
+ class RefBook {
5898
+ readonly #prints = new Map<string, AxFingerprint>();
5899
+ readonly #moved = new Map<string, ComputerReacquired>();
5900
+
5901
+ get(ref: string): AxFingerprint | undefined {
5902
+ return this.#prints.get(ref);
5903
+ }
5904
+
5905
+ remember(ref: string, print: AxFingerprint): void {
5906
+ const merged: Record<string, unknown> = { ...this.#prints.get(ref) };
5907
+ for (const [key, value] of Object.entries(print)) {
5908
+ if (value !== undefined) merged[key] = value;
5909
+ }
5910
+ this.#prints.delete(ref);
5911
+ this.#prints.set(ref, merged as unknown as AxFingerprint);
5912
+ trimOldest(this.#prints);
5913
+ }
5914
+
5915
+ movedTo(ref: string): ComputerReacquired | undefined {
5916
+ return this.#moved.get(ref);
5917
+ }
5918
+
5919
+ move(reacquired: ComputerReacquired): void {
5920
+ this.#moved.delete(reacquired.from);
5921
+ this.#moved.set(reacquired.from, reacquired);
5922
+ trimOldest(this.#moved);
5923
+ }
5924
+
5925
+ /** Every ax() line carries role, title, and ancestry; refs picked from the text keep a fingerprint without extra native calls. */
5926
+ noteSnapshot(windowId: string, text: string): void {
5927
+ const ancestors: Array<{ depth: number; role: string; title: string }> = [];
5928
+ for (const line of text.split("\\n")) {
5929
+ const match = SNAPSHOT_LINE.exec(line);
5930
+ if (!match) continue;
5931
+ const depth = match[1]!.length;
5932
+ while (ancestors.length > 0 && ancestors[ancestors.length - 1]!.depth >= depth) ancestors.pop();
5933
+ const role = match[2]!;
5934
+ const title = decodeTitle(match[3]);
5935
+ this.remember(match[4]!, { windowId, role, title, parentPath: namedPath([...ancestors].reverse()) });
5936
+ ancestors.push({ depth, role, title });
5937
+ }
5938
+ }
5939
+ }
5940
+
5941
+ async function identityAttributes(
5942
+ session: NativeDesktopSession,
5943
+ signal: AbortSignal,
5944
+ ref: string,
5945
+ ): Promise<IdentityAttributes> {
5946
+ try {
5947
+ const attributes = new Map(await nativeCall(signal, () => session.axAttributes(ref)));
5948
+ return {
5949
+ automationId: attributeText(attributes.get("AutomationId") ?? attributes.get("AXIdentifier")),
5950
+ runtimeId: attributeText(attributes.get("RuntimeId")),
5951
+ };
5952
+ } catch (error) {
5953
+ if (error instanceof ToolAbortError) throw error;
5954
+ return {};
5955
+ }
5956
+ }
5957
+
5958
+ async function walkParentPath(
5959
+ session: NativeDesktopSession,
5960
+ signal: AbortSignal,
5961
+ ref: string,
5962
+ ): Promise<string[] | undefined> {
5963
+ const ancestors: AxNode[] = [];
5964
+ let current = ref;
5965
+ for (let level = 0; level < PARENT_WALK_LIMIT; level++) {
5966
+ let parent: AxNode | null | undefined;
5967
+ try {
5968
+ parent = await nativeCall(signal, () => session.axParent(current));
5969
+ } catch (error) {
5970
+ if (error instanceof ToolAbortError) throw error;
5971
+ return undefined;
5972
+ }
5973
+ if (!parent) return namedPath(ancestors);
5974
+ ancestors.push(parent);
5975
+ const path = namedPath(ancestors);
5976
+ if (parent.role === "window" || path.length === PARENT_NAMED_LIMIT) return path;
5977
+ current = parent.ref;
5978
+ }
5979
+ return undefined;
5980
+ }
5981
+
5982
+ /**
5983
+ * Finds the element a stale fingerprint names, narrowing like browser-use's re-identification:
5984
+ * exact instance (RuntimeId), then role+name, AutomationId, named parent path, and position only to
5985
+ * break ties. Anything short of exactly one candidate is refused, never guessed.
5986
+ */
5987
+ async function reacquire(
5988
+ session: NativeDesktopSession,
5989
+ signal: AbortSignal,
5990
+ print: AxFingerprint | undefined,
5991
+ ): Promise<ReacquireOutcome> {
5992
+ if (!print) return { outcome: "no-fingerprint", candidates: [] };
5993
+ const windowId = print.windowId;
5994
+ if (!windowId) return { outcome: "no-window", candidates: [] };
5995
+ const report = (nodes: AxNode[]): ComputerRefCandidate[] => nodes.slice(0, CANDIDATE_REPORT_LIMIT).map(candidateOf);
5996
+ const sameRole = (
5997
+ await nativeCall(signal, () => session.axQuery(windowId, { role: print.role, limit: REACQUIRE_QUERY_LIMIT }))
5998
+ ).filter(node => node.role === print.role && (print.nativeRole === undefined || node.nativeRole === print.nativeRole));
5999
+ let pool = sameRole.filter(
6000
+ node =>
6001
+ (node.title ?? "") === print.title &&
6002
+ (print.description === undefined || (node.description ?? "") === print.description),
6003
+ );
6004
+ if (pool.length === 0) return { outcome: "no-candidate", candidates: report(sameRole) };
6005
+ const attributes = new Map<string, IdentityAttributes>();
6006
+ for (const node of pool) attributes.set(node.ref, await identityAttributes(session, signal, node.ref));
6007
+ const matched = (node: AxNode, matchedBy: string[]): ReacquireOutcome => ({
6008
+ node,
6009
+ matchedBy: matchedBy.join("+"),
6010
+ print: { ...print, ...nodePrint(node), ...attributes.get(node.ref), parentPath: print.parentPath },
6011
+ });
6012
+ if (print.runtimeId) {
6013
+ const exact = pool.filter(node => attributes.get(node.ref)?.runtimeId === print.runtimeId);
6014
+ if (exact.length === 1) return matched(exact[0]!, ["runtimeId"]);
6015
+ }
6016
+ const matchedBy = ["role", "name"];
6017
+ if (print.automationId) {
6018
+ const named = pool;
6019
+ pool = pool.filter(node => attributes.get(node.ref)?.automationId === print.automationId);
6020
+ if (pool.length === 0) return { outcome: "no-candidate", candidates: report(named) };
6021
+ matchedBy.push("automationId");
6022
+ }
6023
+ if (print.parentPath && pool.length <= PARENT_WALK_BATCH) {
6024
+ const expected = print.parentPath;
6025
+ const kept: AxNode[] = [];
6026
+ for (const node of pool) {
6027
+ const path = await walkParentPath(session, signal, node.ref);
6028
+ if (path && samePath(path, expected)) kept.push(node);
6029
+ }
6030
+ if (kept.length === 0) return { outcome: "parent-mismatch", candidates: report(pool) };
6031
+ pool = kept;
6032
+ matchedBy.push("parent");
6033
+ }
6034
+ const weak = !print.title && !print.description && !print.automationId && !matchedBy.includes("parent");
6035
+ if (pool.length === 1 && !weak) return matched(pool[0]!, matchedBy);
6036
+ if (print.bounds) {
6037
+ const bounds = print.bounds;
6038
+ const near = pool.filter(node => nearBounds(node, bounds));
6039
+ if (near.length === 1) return matched(near[0]!, [...matchedBy, "position"]);
6040
+ }
6041
+ return { outcome: "ambiguous", candidates: report(pool) };
6042
+ }
6043
+
6044
+ function attachRefusal(error: ToolError, refusal: ComputerActionRefusal): ToolError {
6045
+ (error as ToolError & { computerAction?: ComputerActionRefusal }).computerAction = refusal;
6046
+ return error;
6047
+ }
6048
+
6049
+ function refuseStale(
6050
+ error: ToolError,
6051
+ ref: string,
6052
+ refusal: { outcome: ReacquireRefusal; candidates: ComputerRefCandidate[] },
6053
+ ): ToolError {
6054
+ const detail = refusal.candidates
6055
+ .map(candidate => candidate.ref + " " + candidate.role + (candidate.title ? " " + JSON.stringify(candidate.title) : ""))
6056
+ .join(", ");
6057
+ const refused = new ToolError(error.message + "\\nreacquire refused (" + refusal.outcome + ")" + (detail ? ": " + detail : ""));
6058
+ return attachRefusal(refused, {
6059
+ action: "ref",
6060
+ status: "refused",
6061
+ suggestedNext: "reobserve",
6062
+ ref,
6063
+ reacquire: { outcome: refusal.outcome, candidates: refusal.candidates },
6064
+ });
6065
+ }
6066
+
6067
+ /** Keeps the thrown error and adds structured facts; aborts and non-tool errors pass through untouched. */
6068
+ function refuseAction(error: unknown, action: string, ref?: string, takeover?: boolean): unknown {
6069
+ if (!(error instanceof ToolError)) return error;
6070
+ const previous = (error as ToolError & { computerAction?: ComputerActionRefusal }).computerAction;
6071
+ const routeUnavailable = !takeover && error.message.startsWith("BackgroundUnavailable:");
6072
+ return attachRefusal(error, {
6073
+ ...previous,
6074
+ action,
6075
+ status: "refused",
6076
+ suggestedNext: routeUnavailable ? "escalate" : "reobserve",
6077
+ ...(routeUnavailable ? { escalation: { target: "takeover" as const, reason: "route_unavailable" } } : {}),
6078
+ ...(ref ? { ref } : {}),
6079
+ });
6080
+ }
6081
+
6082
+ /** Resolves a ref, following an earlier reacquisition or reacquiring a stale ref from its fingerprint. */
6083
+ async function resolveNode(
6084
+ session: NativeDesktopSession,
6085
+ signal: AbortSignal,
6086
+ ref: string,
6087
+ windowHint?: string,
6088
+ ): Promise<{ node: AxNode; reacquired?: ComputerReacquired }> {
6089
+ const book = refBook(session);
6090
+ const moved = book.movedTo(ref);
6091
+ const live = moved?.to ?? ref;
6092
+ try {
6093
+ const node = await nativeCall(signal, () => session.axNode(live));
6094
+ return moved ? { node, reacquired: moved } : { node };
6095
+ } catch (error) {
6096
+ if (!isStaleRef(error)) throw error;
6097
+ const known = book.get(live) ?? book.get(ref);
6098
+ const print = known && !known.windowId && windowHint ? { ...known, windowId: windowHint } : known;
6099
+ const outcome = await reacquire(session, signal, print);
6100
+ if (outcome.node === undefined) throw refuseStale(error, live, outcome);
6101
+ const reacquired = { from: ref, to: outcome.node.ref, matchedBy: outcome.matchedBy };
6102
+ book.move(reacquired);
6103
+ book.remember(outcome.node.ref, outcome.print);
6104
+ return { node: outcome.node, reacquired };
6105
+ }
6106
+ }
6107
+
6108
+ /** Wraps nodes as elements and records their fingerprints; attributes are cheap, parent walks only for small batches. */
6109
+ async function issueElements(
6110
+ session: NativeDesktopSession,
6111
+ getContext: RunContextAccessor,
6112
+ nodes: AxNode[],
6113
+ windowId?: string,
6114
+ reacquired?: ComputerReacquired,
6115
+ ): Promise<El[]> {
6116
+ const { signal } = getContext();
6117
+ const book = refBook(session);
6118
+ for (const node of nodes) {
6119
+ const known = book.get(node.ref);
6120
+ const parentPath =
6121
+ known?.parentPath === undefined && nodes.length <= PARENT_WALK_BATCH
6122
+ ? await walkParentPath(session, signal, node.ref)
6123
+ : undefined;
6124
+ book.remember(node.ref, {
6125
+ ...nodePrint(node),
6126
+ windowId: known?.windowId ?? windowId,
6127
+ ...(await identityAttributes(session, signal, node.ref)),
6128
+ parentPath,
6129
+ });
6130
+ }
6131
+ return nodes.map(node => new El(session, getContext, node, reacquired));
6132
+ }
6133
+
6134
+ async function resolveElement(
6135
+ session: NativeDesktopSession,
6136
+ getContext: RunContextAccessor,
6137
+ ref: string,
6138
+ windowHint?: string,
6139
+ ): Promise<El> {
6140
+ const { signal } = getContext();
6141
+ const { node, reacquired } = await resolveNode(session, signal, ref, windowHint);
6142
+ const [element] = await issueElements(session, getContext, [node], windowHint, reacquired);
6143
+ return element!;
6144
+ }
6145
+
6146
+ function verified(evidence: string): Judged {
6147
+ return { status: "verified", suggestedNext: "continue", evidence };
6148
+ }
6149
+
6150
+ function unverified(evidence: string): Judged {
6151
+ return { status: "unverified", suggestedNext: "reobserve", evidence };
6152
+ }
6153
+
6154
+ function suspectedNoop(evidence: string, reason: string): Judged {
6155
+ return { status: "suspected_noop", suggestedNext: "escalate", escalation: { target: "pixel", reason }, evidence };
6156
+ }
6157
+
6158
+ function judgeStateChange(before: AxNode | undefined, after: AxNode | undefined): Judged {
6159
+ if (!before || !after) return unverified("element could not be read back around the action");
6160
+ const changed = ELEMENT_STATE_KEYS.filter(key => before[key] !== after[key]);
6161
+ return changed.length > 0
6162
+ ? verified("element " + changed.join(", ") + " changed")
6163
+ : unverified("element state unchanged; the effect may be elsewhere");
6164
+ }
6165
+
6166
+ function windowInputResult(action: string, target: string, options?: InputOptions): ComputerActionResult {
6167
+ const route = target === "desktop" ? "desktop" : options?.takeover ? "takeover" : "background";
6168
+ return { action, ...unverified("input accepted via the " + route + " route; application effect not observed") };
6169
+ }
6170
+
6171
+ class El {
6172
+ /** Updated when an action reacquires this element after its ref went stale. */
6173
+ ref: string;
6174
+ readonly role: string;
6175
+ readonly nativeRole: string;
6176
+ readonly title?: string;
6177
+ readonly description?: string;
6178
+ readonly enabled: boolean;
6179
+ readonly focused: boolean;
6180
+ readonly childCount: number;
6181
+ /** Stale ref this element was reacquired from; present only after a reacquisition. */
6182
+ declare reacquiredFrom?: string;
6183
+ readonly #session: NativeDesktopSession;
6184
+ readonly #getContext: RunContextAccessor;
6185
+ #reacquired?: ComputerReacquired;
6186
+
6187
+ constructor(session: NativeDesktopSession, getContext: RunContextAccessor, node: AxNode, reacquired?: ComputerReacquired) {
6188
+ this.#session = session;
6189
+ this.#getContext = getContext;
6190
+ this.ref = node.ref;
6191
+ this.role = node.role;
6192
+ this.nativeRole = node.nativeRole;
6193
+ this.title = node.title;
6194
+ this.description = node.description;
6195
+ this.enabled = node.enabled;
6196
+ this.focused = node.focused;
6197
+ this.childCount = node.childCount;
6198
+ if (reacquired) this.#noteReacquired(reacquired);
6199
+ }
6200
+
6201
+ #noteReacquired(reacquired: ComputerReacquired): void {
6202
+ this.#reacquired = this.#reacquired ? { ...reacquired, from: this.#reacquired.from } : reacquired;
6203
+ this.reacquiredFrom = this.#reacquired.from;
6204
+ }
6205
+
6206
+ /**
6207
+ * One readback before and one after the delivery, no polling. The before read doubles as the stale
6208
+ * check that may reacquire; once input reaches the native layer nothing is retried. A failed
6209
+ * readback never turns a delivered action into an error; it leaves the result unverified.
6210
+ */
6211
+ async #act(
6212
+ action: string,
6213
+ deliver: (ref: string) => Promise<void>,
6214
+ judge: (before: AxNode | undefined, after: AxNode | undefined) => Judged,
6215
+ takeover?: boolean,
6216
+ ): Promise<ComputerActionResult> {
6217
+ const context = this.#getContext();
6218
+ guardRun(context, action);
6219
+ let before: AxNode | undefined;
6220
+ try {
6221
+ const live = await resolveNode(this.#session, context.signal, this.ref);
6222
+ before = live.node;
6223
+ if (live.reacquired) {
6224
+ this.ref = live.node.ref;
6225
+ this.#noteReacquired(live.reacquired);
6226
+ }
6227
+ } catch (error) {
6228
+ if (isStaleRef(error)) throw refuseAction(error, action, this.ref, takeover);
6229
+ if (error instanceof ToolAbortError) throw error;
6230
+ }
6231
+ try {
6232
+ await nativeCall(context.signal, () => deliver(this.ref));
6233
+ } catch (error) {
6234
+ throw refuseAction(error, action, this.ref, takeover);
6235
+ }
6236
+ let after: AxNode | undefined;
6237
+ try {
6238
+ after = await nativeCall(context.signal, () => this.#session.axNode(this.ref));
6239
+ } catch (error) {
6240
+ if (error instanceof ToolAbortError) throw error;
6241
+ }
6242
+ return {
6243
+ action,
6244
+ ...judge(before, after),
6245
+ ref: this.ref,
6246
+ ...(this.#reacquired ? { reacquired: this.#reacquired } : {}),
6247
+ };
6248
+ }
6249
+
6250
+ async value(): Promise<string | undefined> {
6251
+ const { signal } = this.#getContext();
6252
+ return (await nativeCall(signal, () => this.#session.axNode(this.ref))).value;
6253
+ }
6254
+
6255
+ setValue(value: string): Promise<ComputerActionResult> {
6256
+ return this.#act(
6257
+ "setValue",
6258
+ ref => this.#session.axSetValue(ref, value),
6259
+ (_before, after) => {
6260
+ if (after?.value === undefined) return unverified("value could not be read back");
6261
+ return after.value === value
6262
+ ? verified("value read back as requested")
6263
+ : suspectedNoop("value read back as " + JSON.stringify(after.value), "value_mismatch");
6264
+ },
6265
+ );
6266
+ }
6267
+
6268
+ async bounds(): Promise<{ x: number; y: number; width: number; height: number } | null> {
6269
+ const { signal } = this.#getContext();
6270
+ const node = await nativeCall(signal, () => this.#session.axNode(this.ref));
6271
+ if (node.x === undefined || node.y === undefined || node.width === undefined || node.height === undefined)
6272
+ return null;
6273
+ return { x: node.x, y: node.y, width: node.width, height: node.height };
6274
+ }
6275
+
6276
+ async attributes(): Promise<Record<string, string>> {
6277
+ const { signal } = this.#getContext();
6278
+ return Object.fromEntries(await nativeCall(signal, () => this.#session.axAttributes(this.ref)));
6279
+ }
6280
+
6281
+ async actions(): Promise<string[]> {
6282
+ const { signal } = this.#getContext();
6283
+ return (await nativeCall(signal, () => this.#session.axNode(this.ref))).actions ?? [];
6284
+ }
6285
+
6286
+ perform(action: string): Promise<ComputerActionResult> {
6287
+ return this.#act("perform", ref => this.#session.axPerform(ref, action), judgeStateChange);
6288
+ }
6289
+
6290
+ press(): Promise<ComputerActionResult> {
6291
+ return this.#act("press", ref => this.#session.axPerform(ref, "press"), judgeStateChange);
6292
+ }
6293
+
6294
+ click(options?: InputOptions): Promise<ComputerActionResult> {
6295
+ return this.#act(
6296
+ "click",
6297
+ ref => this.#session.axClick(ref, pointerOptions(options)),
6298
+ judgeStateChange,
6299
+ options?.takeover,
6300
+ );
6301
+ }
6302
+
6303
+ focus(): Promise<ComputerActionResult> {
6304
+ return this.#act(
6305
+ "focus",
6306
+ ref => this.#session.axFocus(ref),
6307
+ (_before, after) => {
6308
+ if (!after) return unverified("focus could not be read back");
6309
+ return after.focused
6310
+ ? verified("element reports focus")
6311
+ : suspectedNoop("element does not report focus", "focus_not_observed");
6312
+ },
6313
+ );
6314
+ }
6315
+
6316
+ async parent(): Promise<El | null> {
6317
+ const { signal } = this.#getContext();
6318
+ const node = await nativeCall(signal, () => this.#session.axParent(this.ref));
6319
+ if (!node) return null;
6320
+ const [parent] = await issueElements(this.#session, this.#getContext, [node], refBook(this.#session).get(this.ref)?.windowId);
6321
+ return parent!;
6322
+ }
6323
+
6324
+ async children(): Promise<El[]> {
6325
+ const { signal } = this.#getContext();
6326
+ const nodes = await nativeCall(signal, () => this.#session.axChildren(this.ref));
6327
+ return issueElements(this.#session, this.#getContext, nodes, refBook(this.#session).get(this.ref)?.windowId);
6328
+ }
6329
+ }`,
6330
+ },
6331
+ {
6332
+ // 창 좌표·키 입력은 앱 쪽 효과를 읽어 올 방법이 없다: 결과는 늘 unverified/reobserve다. ax()는 텍스트의
6333
+ // 모든 ref에 지문을 남기고, find()/ref()는 발급하는 요소에 지문을 남긴다.
6334
+ file: "src/tools/computer/worker.ts",
6335
+ marker: "return windowInputResult(action, this.id, options);",
6336
+ anchor: ` async click(x: number, y: number, options?: ClickOptions): Promise<void> {
6337
+ const context = this.#getContext();
6338
+ guardRun(context, "click");
6339
+ await nativeCall(context.signal, () => this.#session.click(this.id, x, y, pointerOptions(options)));
6340
+ }
6341
+
6342
+ async doubleClick(x: number, y: number, options?: Omit<ClickOptions, "count">): Promise<void> {
6343
+ const context = this.#getContext();
6344
+ guardRun(context, "doubleClick");
6345
+ await nativeCall(context.signal, () =>
6346
+ this.#session.click(this.id, x, y, pointerOptions({ ...options, count: 2 })),
6347
+ );
6348
+ }
6349
+
6350
+ async move(x: number, y: number): Promise<void> {
6351
+ const context = this.#getContext();
6352
+ guardRun(context, "move");
6353
+ await nativeCall(context.signal, () => this.#session.moveMouse(this.id, x, y));
6354
+ }
6355
+
6356
+ async drag(points: Array<[number, number]>, options?: DragOptions): Promise<void> {
6357
+ const context = this.#getContext();
6358
+ guardRun(context, "drag");
6359
+ await nativeCall(context.signal, () =>
6360
+ this.#session.drag(
6361
+ this.id,
6362
+ points.map(([x, y]) => ({ x, y })),
6363
+ pointerOptions(options),
6364
+ ),
6365
+ );
6366
+ }
6367
+
6368
+ async scroll(x: number, y: number, options: ScrollOptions = {}): Promise<void> {
6369
+ const context = this.#getContext();
6370
+ guardRun(context, "scroll");
6371
+ await nativeCall(context.signal, () =>
6372
+ this.#session.scroll(this.id, x, y, options.dx ?? 0, options.dy ?? 0, pointerOptions(options)),
6373
+ );
6374
+ }
6375
+
6376
+ async type(text: string, options?: InputOptions): Promise<void> {
6377
+ const context = this.#getContext();
6378
+ guardRun(context, "type");
6379
+ await nativeCall(context.signal, () => this.#session.typeText(this.id, text, pointerOptions(options)));
6380
+ }
6381
+
6382
+ async press(chord: string | string[], options?: InputOptions): Promise<void> {
6383
+ const context = this.#getContext();
6384
+ guardRun(context, "press");
6385
+ await nativeCall(context.signal, () =>
6386
+ this.#session.keyChord(this.id, chordKeys(chord), pointerOptions(options)),
6387
+ );
6388
+ }
6389
+
6390
+ async raise(): Promise<void> {
6391
+ const context = this.#getContext();
6392
+ guardRun(context, "raise");
6393
+ await nativeCall(context.signal, () => this.#session.raiseWindow(this.id));
6394
+ }
6395
+
6396
+ async ax(options?: AxOptions): Promise<string> {
6397
+ const { signal } = this.#getContext();
6398
+ return (await nativeCall(signal, () => this.#session.axSnapshot(this.id, options))).text;
6399
+ }
6400
+
6401
+ async find(query: AxQuery): Promise<El[]> {
6402
+ const { signal } = this.#getContext();
6403
+ return (await nativeCall(signal, () => this.#session.axQuery(this.id, query))).map(
6404
+ node => new El(this.#session, this.#getContext, node),
6405
+ );
6406
+ }
6407
+
6408
+ async ref(ref: string): Promise<El> {
6409
+ const { signal } = this.#getContext();
6410
+ return new El(this.#session, this.#getContext, await nativeCall(signal, () => this.#session.axNode(ref)));
6411
+ }`,
6412
+ patched: ` async #input(action: string, options: InputOptions | undefined, call: () => Promise<void>): Promise<ComputerActionResult> {
6413
+ const context = this.#getContext();
6414
+ guardRun(context, action);
6415
+ try {
6416
+ await nativeCall(context.signal, call);
6417
+ } catch (error) {
6418
+ throw refuseAction(error, action, undefined, options?.takeover);
6419
+ }
6420
+ return windowInputResult(action, this.id, options);
6421
+ }
6422
+
6423
+ click(x: number, y: number, options?: ClickOptions): Promise<ComputerActionResult> {
6424
+ return this.#input("click", options, () => this.#session.click(this.id, x, y, pointerOptions(options)));
6425
+ }
6426
+
6427
+ doubleClick(x: number, y: number, options?: Omit<ClickOptions, "count">): Promise<ComputerActionResult> {
6428
+ return this.#input("doubleClick", options, () =>
6429
+ this.#session.click(this.id, x, y, pointerOptions({ ...options, count: 2 })),
6430
+ );
6431
+ }
6432
+
6433
+ move(x: number, y: number): Promise<ComputerActionResult> {
6434
+ return this.#input("move", undefined, () => this.#session.moveMouse(this.id, x, y));
6435
+ }
6436
+
6437
+ drag(points: Array<[number, number]>, options?: DragOptions): Promise<ComputerActionResult> {
6438
+ return this.#input("drag", options, () =>
6439
+ this.#session.drag(
6440
+ this.id,
6441
+ points.map(([x, y]) => ({ x, y })),
6442
+ pointerOptions(options),
6443
+ ),
6444
+ );
6445
+ }
6446
+
6447
+ scroll(x: number, y: number, options: ScrollOptions = {}): Promise<ComputerActionResult> {
6448
+ return this.#input("scroll", options, () =>
6449
+ this.#session.scroll(this.id, x, y, options.dx ?? 0, options.dy ?? 0, pointerOptions(options)),
6450
+ );
6451
+ }
6452
+
6453
+ type(text: string, options?: InputOptions): Promise<ComputerActionResult> {
6454
+ return this.#input("type", options, () => this.#session.typeText(this.id, text, pointerOptions(options)));
6455
+ }
6456
+
6457
+ press(chord: string | string[], options?: InputOptions): Promise<ComputerActionResult> {
6458
+ return this.#input("press", options, () =>
6459
+ this.#session.keyChord(this.id, chordKeys(chord), pointerOptions(options)),
6460
+ );
6461
+ }
6462
+
6463
+ raise(): Promise<ComputerActionResult> {
6464
+ return this.#input("raise", undefined, () => this.#session.raiseWindow(this.id));
6465
+ }
6466
+
6467
+ async ax(options?: AxOptions): Promise<string> {
6468
+ const { signal } = this.#getContext();
6469
+ const text = (await nativeCall(signal, () => this.#session.axSnapshot(this.id, options))).text;
6470
+ refBook(this.#session).noteSnapshot(this.id, text);
6471
+ return text;
6472
+ }
6473
+
6474
+ async find(query: AxQuery): Promise<El[]> {
6475
+ const { signal } = this.#getContext();
6476
+ const nodes = await nativeCall(signal, () => this.#session.axQuery(this.id, query));
6477
+ return issueElements(this.#session, this.#getContext, nodes, this.id);
6478
+ }
6479
+
6480
+ ref(ref: string): Promise<El> {
6481
+ return resolveElement(this.#session, this.#getContext, ref, this.id);
6482
+ }`,
6483
+ },
6484
+ {
6485
+ // Python·JS 직접 헬퍼는 win.ref(ref)도 매번 desktop.ref(ref)로 푼다. 재획득은 이 경로에서도 일어나야 한다.
6486
+ file: "src/tools/computer/worker.ts",
6487
+ marker: "ref: (ref: string): Promise<El> => resolveElement(session, getContext, ref),",
6488
+ anchor: ` ref: async (ref: string): Promise<El> => {
6489
+ const { signal } = getContext();
6490
+ return el(await nativeCall(signal, () => session.axNode(ref)));
6491
+ },`,
6492
+ patched: ` ref: (ref: string): Promise<El> => resolveElement(session, getContext, ref),`,
6493
+ },
6494
+ {
6495
+ // 모델이 보는 타입: 행동 결과·거절 필드와 재획득 규칙을 적는다.
6496
+ file: "src/tools/computer/declarations.d.ts",
6497
+ marker: "interface ComputerActionResult {",
6498
+ anchor: `/** Live accessibility element resolved from a snapshot ref; expired refs throw \`StaleRef\`. */
6499
+ interface ComputerElement {
6500
+ /** Snapshot ref tag, e.g. \`e5\`. */
6501
+ readonly ref: string;
6502
+ readonly role: string;
6503
+ readonly nativeRole: string;
6504
+ readonly title?: string;
6505
+ readonly description?: string;
6506
+ readonly enabled: boolean;
6507
+ readonly focused: boolean;
6508
+ readonly childCount: number;
6509
+ value(): Promise<string | undefined>;
6510
+ setValue(value: string): Promise<void>;
6511
+ /** Bounds in global desktop coordinates, or null when the element has none. */
6512
+ bounds(): Promise<ComputerBounds | null>;
6513
+ attributes(): Promise<Record<string, string>>;
6514
+ actions(): Promise<string[]>;
6515
+ perform(action: string): Promise<void>;
6516
+ /** Perform the element's native press action; needs no screenshot. */
6517
+ press(): Promise<void>;
6518
+ /** Click the element's center with native input. */
6519
+ click(options?: ComputerInputOptions): Promise<void>;
6520
+ focus(): Promise<void>;
6521
+ parent(): Promise<ComputerElement | null>;
6522
+ children(): Promise<ComputerElement[]>;
6523
+ }
6524
+
6525
+ /** Native input helpers shared by the desktop root and window handles; \`x\`/\`y\` are pixels in the most recent screenshot of the same target. */
6526
+ interface ComputerInputTarget {
6527
+ screenshot(options?: ComputerScreenshotOptions): Promise<ComputerScreenshotResult>;
6528
+ click(x: number, y: number, options?: ComputerClickOptions): Promise<void>;
6529
+ doubleClick(x: number, y: number, options?: Omit<ComputerClickOptions, "count">): Promise<void>;
6530
+ move(x: number, y: number): Promise<void>;
6531
+ drag(points: Array<[number, number]>, options?: ComputerDragOptions): Promise<void>;
6532
+ scroll(x: number, y: number, options?: ComputerScrollOptions): Promise<void>;
6533
+ type(text: string, options?: ComputerInputOptions): Promise<void>;
6534
+ /** Key chord such as \`"cmd+shift+p"\` or \`["cmd", "shift", "p"]\`. */
6535
+ press(chord: string | string[], options?: ComputerInputOptions): Promise<void>;
6536
+ }`,
6537
+ patched: `/** Result of an input or element action. Delivery is not proof of effect. */
6538
+ interface ComputerActionResult {
6539
+ action: string;
6540
+ /** \`verified\`: an AX readback shows the change. \`unverified\`: delivered, effect not observed. \`suspected_noop\`: the readback contradicts the intended change. */
6541
+ status: "verified" | "unverified" | "suspected_noop";
6542
+ /** \`reobserve\`: screenshot or AX before relying on the effect. \`escalate\`: follow \`escalation\`. */
6543
+ suggestedNext: "continue" | "reobserve" | "escalate";
6544
+ escalation?: { target: "pixel" | "takeover"; reason: string };
6545
+ /** Readback the status rests on. */
6546
+ evidence?: string;
6547
+ ref?: string;
6548
+ /** Present when the action ran on an element reacquired from a stale ref. */
6549
+ reacquired?: { from: string; to: string; matchedBy: string };
6550
+ }
6551
+
6552
+ /** Attached to a failed action's error as \`error.computerAction\` (visible inside \`computer.run\`); the error message is unchanged. */
6553
+ interface ComputerActionRefusal {
6554
+ action: string;
6555
+ status: "refused";
6556
+ suggestedNext: "reobserve" | "escalate";
6557
+ escalation?: { target: "takeover"; reason: string };
6558
+ ref?: string;
6559
+ /** Why a stale ref was not reacquired, with up to five candidates. */
6560
+ reacquire?: {
6561
+ outcome: "no-fingerprint" | "no-window" | "no-candidate" | "parent-mismatch" | "ambiguous";
6562
+ candidates: Array<{ ref: string; role: string; title?: string; bounds?: ComputerBounds }>;
6563
+ };
6564
+ }
6565
+
6566
+ /** Live accessibility element resolved from a snapshot ref. A stale ref is reacquired only when its fingerprint matches exactly one element; otherwise it throws \`StaleRef\`. */
6567
+ interface ComputerElement {
6568
+ /** Snapshot ref tag, e.g. \`e5\`; the new ref after a reacquisition. */
6569
+ readonly ref: string;
6570
+ /** Stale ref this element was reacquired from. */
6571
+ readonly reacquiredFrom?: string;
6572
+ readonly role: string;
6573
+ readonly nativeRole: string;
6574
+ readonly title?: string;
6575
+ readonly description?: string;
6576
+ readonly enabled: boolean;
6577
+ readonly focused: boolean;
6578
+ readonly childCount: number;
6579
+ value(): Promise<string | undefined>;
6580
+ setValue(value: string): Promise<ComputerActionResult>;
6581
+ /** Bounds in global desktop coordinates, or null when the element has none. */
6582
+ bounds(): Promise<ComputerBounds | null>;
6583
+ attributes(): Promise<Record<string, string>>;
6584
+ actions(): Promise<string[]>;
6585
+ perform(action: string): Promise<ComputerActionResult>;
6586
+ /** Perform the element's native press action; needs no screenshot. */
6587
+ press(): Promise<ComputerActionResult>;
6588
+ /** Click the element's center with native input. */
6589
+ click(options?: ComputerInputOptions): Promise<ComputerActionResult>;
6590
+ focus(): Promise<ComputerActionResult>;
6591
+ parent(): Promise<ComputerElement | null>;
6592
+ children(): Promise<ComputerElement[]>;
6593
+ }
6594
+
6595
+ /** Native input helpers shared by the desktop root and window handles; \`x\`/\`y\` are pixels in the most recent screenshot of the same target. Input results are always \`unverified\`. */
6596
+ interface ComputerInputTarget {
6597
+ screenshot(options?: ComputerScreenshotOptions): Promise<ComputerScreenshotResult>;
6598
+ click(x: number, y: number, options?: ComputerClickOptions): Promise<ComputerActionResult>;
6599
+ doubleClick(x: number, y: number, options?: Omit<ComputerClickOptions, "count">): Promise<ComputerActionResult>;
6600
+ move(x: number, y: number): Promise<ComputerActionResult>;
6601
+ drag(points: Array<[number, number]>, options?: ComputerDragOptions): Promise<ComputerActionResult>;
6602
+ scroll(x: number, y: number, options?: ComputerScrollOptions): Promise<ComputerActionResult>;
6603
+ type(text: string, options?: ComputerInputOptions): Promise<ComputerActionResult>;
6604
+ /** Key chord such as \`"cmd+shift+p"\` or \`["cmd", "shift", "p"]\`. */
6605
+ press(chord: string | string[], options?: ComputerInputOptions): Promise<ComputerActionResult>;
6606
+ }`,
6607
+ },
6608
+ {
6609
+ file: "src/tools/computer/declarations.d.ts",
6610
+ marker: "\traise(): Promise<ComputerActionResult>;",
6611
+ anchor: "\traise(): Promise<void>;",
6612
+ patched: "\traise(): Promise<ComputerActionResult>;",
6613
+ },
6614
+ {
6615
+ // 모델 지시: 재획득 규칙과 결과 필드를 읽는 법. 기존 takeover 규칙(다음 줄)은 그대로 둔다.
6616
+ file: "src/prompts/tools/computer.md",
6617
+ marker: "Actions return `{ action, status, suggestedNext",
6618
+ anchor: "- Each window `.ax()` starts a ref generation. Current/previous snapshot refs remain valid; older refs throw `StaleRef`. Re-snapshot; NEVER guess.\n",
6619
+ patched: "- Each window `.ax()` starts a ref generation. Current/previous snapshot refs remain valid. An older ref is reacquired only when its saved fingerprint (role, name, AutomationId, named parents, position) matches exactly one element; the element's `ref` changes and the action result carries `reacquired`. Otherwise it throws `StaleRef` naming why and the candidates: re-snapshot; NEVER guess.\n- Actions return `{ action, status, suggestedNext, evidence?, escalation?, reacquired? }`. `verified` rests on an AX readback; `unverified` (all pointer/keyboard input) means delivered but unobserved: `reobserve` before relying on it; `suspected_noop` → follow `escalation`. Inside `computer.run`, a thrown action error carries `error.computerAction`.\n",
6620
+ },
5639
6621
  {
5640
6622
  // MCP 선택 연결: 요청별 MCP 선택(opt-in). all이 기본이며 per-request면 시작 시 연결하지 않고 요청마다 확장이 고른다.
5641
6623
  file: "src/mcp/settings.ts",