@tyvm/knowhow 0.0.158 → 0.0.160

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 (870) hide show
  1. package/package.json +2 -2
  2. package/ts_build/package.json +2 -2
  3. package/ts_build/src/chat/CliChatService.d.ts +2 -1
  4. package/ts_build/src/chat/CliChatService.js +29 -3
  5. package/ts_build/src/chat/CliChatService.js.map +1 -1
  6. package/ts_build/src/chat/modules/AgentModule.js +21 -17
  7. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  8. package/ts_build/src/chat/renderer/ConsoleRenderer.js +32 -25
  9. package/ts_build/src/chat/renderer/ConsoleRenderer.js.map +1 -1
  10. package/ts_build/src/logger.d.ts +1 -0
  11. package/ts_build/src/logger.js +13 -1
  12. package/ts_build/src/logger.js.map +1 -1
  13. package/ts_build/src/utils/InputQueueManager.d.ts +8 -1
  14. package/ts_build/src/utils/InputQueueManager.js +72 -2
  15. package/ts_build/src/utils/InputQueueManager.js.map +1 -1
  16. package/ts_build/src/utils/index.d.ts +3 -1
  17. package/ts_build/src/utils/index.js +11 -3
  18. package/ts_build/src/utils/index.js.map +1 -1
  19. package/CONFIG.md +0 -429
  20. package/PROCESSING.md +0 -450
  21. package/WORKER.md +0 -260
  22. package/autodoc/README.md +0 -324
  23. package/autodoc/chat-guide.md +0 -444
  24. package/autodoc/cli-reference.md +0 -720
  25. package/autodoc/config-reference.md +0 -642
  26. package/autodoc/embeddings-guide.md +0 -467
  27. package/autodoc/generate-guide.md +0 -437
  28. package/autodoc/language-plugin-guide.md +0 -417
  29. package/autodoc/modules-guide.md +0 -379
  30. package/autodoc/plugins-guide.md +0 -721
  31. package/autodoc/quickstart-guide.md +0 -126
  32. package/autodoc/skills-guide.md +0 -584
  33. package/autodoc/worker-guide.md +0 -519
  34. package/docs/input-queue-manager.md +0 -142
  35. package/docs/multi-worker-management.md +0 -142
  36. package/docs/shell-commands.md +0 -174
  37. package/jest.config.js +0 -19
  38. package/jest.manual.config.js +0 -19
  39. package/scripts/README.md +0 -119
  40. package/scripts/build-for-node.sh +0 -148
  41. package/scripts/cache-miss-debug.ts +0 -365
  42. package/scripts/check-isolated-deps.sh +0 -69
  43. package/scripts/check-model-pricing.ts +0 -509
  44. package/scripts/compare-openrouter-coverage.ts +0 -576
  45. package/scripts/migrate-usage-json.js +0 -147
  46. package/scripts/publish.sh +0 -86
  47. package/scripts/restore_keys.sh +0 -59
  48. package/scripts/test-repetition-hint.ts +0 -302
  49. package/scripts/unset_keys.sh +0 -60
  50. package/src/agents/base/base.ts +0 -1963
  51. package/src/agents/base/prompt.ts +0 -55
  52. package/src/agents/configurable/ConfigAgent.ts +0 -24
  53. package/src/agents/developer/developer.ts +0 -76
  54. package/src/agents/historyRollback.ts +0 -36
  55. package/src/agents/index.ts +0 -52
  56. package/src/agents/interface.ts +0 -11
  57. package/src/agents/patcher/codebase.md +0 -27
  58. package/src/agents/patcher/patcher.ts +0 -131
  59. package/src/agents/researcher/researcher.ts +0 -115
  60. package/src/agents/setup/setup.ts +0 -63
  61. package/src/agents/tools/addInternalTools.ts +0 -21
  62. package/src/agents/tools/agentCall.ts +0 -34
  63. package/src/agents/tools/aiClient.ts +0 -178
  64. package/src/agents/tools/askHuman.ts +0 -10
  65. package/src/agents/tools/callPlugin.ts +0 -10
  66. package/src/agents/tools/connectAgent.ts +0 -355
  67. package/src/agents/tools/embeddingSearch.ts +0 -6
  68. package/src/agents/tools/execCommand.ts +0 -162
  69. package/src/agents/tools/fileSearch.ts +0 -35
  70. package/src/agents/tools/finalAnswer.ts +0 -4
  71. package/src/agents/tools/googleSearch.ts +0 -243
  72. package/src/agents/tools/index.ts +0 -33
  73. package/src/agents/tools/language/definitions.ts +0 -105
  74. package/src/agents/tools/language/index.ts +0 -20
  75. package/src/agents/tools/lazy/definitions.ts +0 -72
  76. package/src/agents/tools/lazy/disableTools.ts +0 -16
  77. package/src/agents/tools/lazy/enableTools.ts +0 -16
  78. package/src/agents/tools/lazy/index.ts +0 -3
  79. package/src/agents/tools/lazy/listAvailableTools.ts +0 -17
  80. package/src/agents/tools/lintFile.ts +0 -19
  81. package/src/agents/tools/list.ts +0 -739
  82. package/src/agents/tools/loadImageAsBase64.ts +0 -83
  83. package/src/agents/tools/loadWebpage.ts +0 -19
  84. package/src/agents/tools/mcp/connectMcpServer.ts +0 -40
  85. package/src/agents/tools/mcp/definitions.ts +0 -67
  86. package/src/agents/tools/mcp/disconnectMcpServer.ts +0 -40
  87. package/src/agents/tools/mcp/index.ts +0 -3
  88. package/src/agents/tools/mcp/listAvailableMcpServers.ts +0 -28
  89. package/src/agents/tools/minimal/callTool.ts +0 -45
  90. package/src/agents/tools/minimal/definitions.ts +0 -50
  91. package/src/agents/tools/minimal/index.ts +0 -3
  92. package/src/agents/tools/minimal/inspectTools.ts +0 -27
  93. package/src/agents/tools/modifyFile.ts +0 -53
  94. package/src/agents/tools/observe.ts +0 -247
  95. package/src/agents/tools/patch.ts +0 -1287
  96. package/src/agents/tools/readBlocks.ts +0 -83
  97. package/src/agents/tools/readFile.ts +0 -105
  98. package/src/agents/tools/replyToParent.ts +0 -123
  99. package/src/agents/tools/runGenerate.ts +0 -210
  100. package/src/agents/tools/scanFile.ts +0 -16
  101. package/src/agents/tools/sendAgentMessage.ts +0 -139
  102. package/src/agents/tools/skills.ts +0 -79
  103. package/src/agents/tools/startAgentTask.ts +0 -393
  104. package/src/agents/tools/stringReplace.ts +0 -105
  105. package/src/agents/tools/textSearch.ts +0 -128
  106. package/src/agents/tools/types/fileblock.ts +0 -5
  107. package/src/agents/tools/visionTool.ts +0 -35
  108. package/src/agents/tools/waitForAgentCompleted.ts +0 -270
  109. package/src/agents/tools/writeFile.ts +0 -106
  110. package/src/agents/tools/ycmd/client.ts +0 -608
  111. package/src/agents/tools/ycmd/definitions.ts +0 -294
  112. package/src/agents/tools/ycmd/detection.ts +0 -211
  113. package/src/agents/tools/ycmd/index.ts +0 -11
  114. package/src/agents/tools/ycmd/installer.ts +0 -251
  115. package/src/agents/tools/ycmd/server.ts +0 -545
  116. package/src/agents/tools/ycmd/serverManager.ts +0 -316
  117. package/src/agents/tools/ycmd/tools/completion.ts +0 -113
  118. package/src/agents/tools/ycmd/tools/diagnostics.ts +0 -166
  119. package/src/agents/tools/ycmd/tools/getLocations.ts +0 -173
  120. package/src/agents/tools/ycmd/tools/goto.ts +0 -169
  121. package/src/agents/tools/ycmd/tools/refactor.ts +0 -204
  122. package/src/agents/tools/ycmd/tools/signature.ts +0 -174
  123. package/src/agents/tools/ycmd/tools/start.ts +0 -95
  124. package/src/agents/tools/ycmd/utils/pathUtils.ts +0 -59
  125. package/src/ai.ts +0 -306
  126. package/src/auth/browserLogin.ts +0 -406
  127. package/src/auth/environmentAuth.ts +0 -51
  128. package/src/auth/errors.ts +0 -6
  129. package/src/auth/jwtStore.ts +0 -70
  130. package/src/auth/keyAuth.ts +0 -142
  131. package/src/auth/keyManager.ts +0 -331
  132. package/src/auth/registerIdentity.ts +0 -67
  133. package/src/auth/spinner.ts +0 -23
  134. package/src/chat/CliChatService.ts +0 -438
  135. package/src/chat/modules/AgentModule.ts +0 -1664
  136. package/src/chat/modules/AskModule.ts +0 -98
  137. package/src/chat/modules/BaseChatModule.ts +0 -65
  138. package/src/chat/modules/ClipboardImageModule.ts +0 -136
  139. package/src/chat/modules/CustomCommandsModule.ts +0 -80
  140. package/src/chat/modules/InternalChatModule.ts +0 -216
  141. package/src/chat/modules/RemoteSyncModule.ts +0 -482
  142. package/src/chat/modules/RendererModule.ts +0 -139
  143. package/src/chat/modules/SearchModule.ts +0 -168
  144. package/src/chat/modules/SessionsModule.ts +0 -969
  145. package/src/chat/modules/SetupModule.ts +0 -185
  146. package/src/chat/modules/ShellCommandModule.ts +0 -98
  147. package/src/chat/modules/SystemModule.ts +0 -161
  148. package/src/chat/modules/ToolCommandModule.ts +0 -102
  149. package/src/chat/modules/VoiceModule.ts +0 -70
  150. package/src/chat/modules/index.ts +0 -8
  151. package/src/chat/renderer/CompactRenderer.ts +0 -229
  152. package/src/chat/renderer/ConsoleRenderer.ts +0 -160
  153. package/src/chat/renderer/FancyRenderer.ts +0 -440
  154. package/src/chat/renderer/PlainRenderer.ts +0 -218
  155. package/src/chat/renderer/index.ts +0 -6
  156. package/src/chat/renderer/loadRenderer.ts +0 -316
  157. package/src/chat/renderer/messagesToRenderEvents.ts +0 -96
  158. package/src/chat/renderer/types.ts +0 -99
  159. package/src/chat/types.ts +0 -146
  160. package/src/chat.ts +0 -140
  161. package/src/cli.ts +0 -180
  162. package/src/clients/anthropic.ts +0 -772
  163. package/src/clients/attribution.ts +0 -53
  164. package/src/clients/cerebras.ts +0 -10
  165. package/src/clients/contextLimits.ts +0 -263
  166. package/src/clients/copilot.ts +0 -23
  167. package/src/clients/deepseek.ts +0 -16
  168. package/src/clients/fireworks.ts +0 -71
  169. package/src/clients/gemini.ts +0 -1169
  170. package/src/clients/github.ts +0 -16
  171. package/src/clients/groq.ts +0 -15
  172. package/src/clients/http.ts +0 -719
  173. package/src/clients/index.ts +0 -1153
  174. package/src/clients/knowhow.ts +0 -130
  175. package/src/clients/knowhowMcp.ts +0 -118
  176. package/src/clients/llama.ts +0 -16
  177. package/src/clients/meta.ts +0 -27
  178. package/src/clients/mistral.ts +0 -16
  179. package/src/clients/nvidia.ts +0 -16
  180. package/src/clients/openai.ts +0 -1186
  181. package/src/clients/openrouter.ts +0 -24
  182. package/src/clients/pricing/anthropic.ts +0 -149
  183. package/src/clients/pricing/cerebras.ts +0 -11
  184. package/src/clients/pricing/copilot.ts +0 -60
  185. package/src/clients/pricing/deepseek.ts +0 -15
  186. package/src/clients/pricing/fireworks.ts +0 -182
  187. package/src/clients/pricing/github.ts +0 -69
  188. package/src/clients/pricing/google.ts +0 -385
  189. package/src/clients/pricing/groq.ts +0 -56
  190. package/src/clients/pricing/index.ts +0 -44
  191. package/src/clients/pricing/llama.ts +0 -18
  192. package/src/clients/pricing/meta.ts +0 -12
  193. package/src/clients/pricing/mistral.ts +0 -34
  194. package/src/clients/pricing/models.ts +0 -25
  195. package/src/clients/pricing/nvidia.ts +0 -102
  196. package/src/clients/pricing/openai.ts +0 -409
  197. package/src/clients/pricing/openrouter.ts +0 -36
  198. package/src/clients/pricing/qwen.ts +0 -80
  199. package/src/clients/pricing/types.ts +0 -125
  200. package/src/clients/pricing/xai.ts +0 -137
  201. package/src/clients/qwen.ts +0 -16
  202. package/src/clients/responseMetadata.ts +0 -221
  203. package/src/clients/types.ts +0 -531
  204. package/src/clients/withRetry.ts +0 -89
  205. package/src/clients/xai.ts +0 -693
  206. package/src/cloudWorker.ts +0 -394
  207. package/src/commands/agent.ts +0 -342
  208. package/src/commands/agents.ts +0 -1037
  209. package/src/commands/behaviors.ts +0 -47
  210. package/src/commands/convert.ts +0 -291
  211. package/src/commands/hash.ts +0 -179
  212. package/src/commands/mcp.ts +0 -743
  213. package/src/commands/misc.ts +0 -373
  214. package/src/commands/modules.ts +0 -704
  215. package/src/commands/processes.ts +0 -248
  216. package/src/commands/remote.ts +0 -77
  217. package/src/commands/replay.ts +0 -503
  218. package/src/commands/sandbox.ts +0 -566
  219. package/src/commands/services.ts +0 -168
  220. package/src/commands/skills.ts +0 -107
  221. package/src/commands/workers.ts +0 -168
  222. package/src/config.ts +0 -468
  223. package/src/conversion.ts +0 -69
  224. package/src/dataset/diffs/README.md +0 -12
  225. package/src/dataset/diffs/debug-errors.ts +0 -29
  226. package/src/dataset/diffs/debug.ts +0 -64
  227. package/src/dataset/diffs/generate.ts +0 -71
  228. package/src/dataset/diffs/jsonl.ts +0 -53
  229. package/src/dataset/diffs/test.ts +0 -194
  230. package/src/embeddings.ts +0 -494
  231. package/src/fileSync.ts +0 -369
  232. package/src/generate.ts +0 -529
  233. package/src/hashes.ts +0 -180
  234. package/src/index.ts +0 -261
  235. package/src/logger.ts +0 -197
  236. package/src/login.ts +0 -209
  237. package/src/microphone.ts +0 -141
  238. package/src/migrations.ts +0 -151
  239. package/src/plugins/AgentsMdPlugin.ts +0 -118
  240. package/src/plugins/GitPlugin.ts +0 -598
  241. package/src/plugins/LinterPlugin.ts +0 -214
  242. package/src/plugins/PluginBase.ts +0 -70
  243. package/src/plugins/SkillsPlugin.ts +0 -37
  244. package/src/plugins/embedding.ts +0 -82
  245. package/src/plugins/exec.ts +0 -70
  246. package/src/plugins/language.ts +0 -290
  247. package/src/plugins/plugins.ts +0 -175
  248. package/src/plugins/tmux.ts +0 -132
  249. package/src/plugins/types.ts +0 -36
  250. package/src/plugins/url.ts +0 -101
  251. package/src/plugins/vim.ts +0 -89
  252. package/src/processes/ProcessManager.ts +0 -96
  253. package/src/processes/managedProcessShim.ts +0 -138
  254. package/src/processors/Base64ImageDetector.ts +0 -502
  255. package/src/processors/CustomVariables.ts +0 -693
  256. package/src/processors/GemmaToolProcessor.ts +0 -163
  257. package/src/processors/HarmonyToolProcessor.ts +0 -264
  258. package/src/processors/JsonCompressor.ts +0 -510
  259. package/src/processors/MinimalToolsMessageProcessor.ts +0 -113
  260. package/src/processors/TokenCompressor.ts +0 -620
  261. package/src/processors/ToolResponseCache.ts +0 -322
  262. package/src/processors/XmlToolCallProcessor.ts +0 -533
  263. package/src/processors/index.ts +0 -14
  264. package/src/processors/tools/boundedToolResponse.ts +0 -49
  265. package/src/processors/tools/grepToolResponse.ts +0 -230
  266. package/src/processors/tools/index.ts +0 -23
  267. package/src/processors/tools/jqToolResponse.ts +0 -159
  268. package/src/processors/tools/listStoredToolResponses.ts +0 -124
  269. package/src/processors/tools/tailToolResponse.ts +0 -148
  270. package/src/prompts/BasicCodeDocumenter.ts +0 -1
  271. package/src/prompts/BasicProjectDocumenter.ts +0 -1
  272. package/src/prompts/EmbeddingSeachHelper.ts +0 -1
  273. package/src/prompts/KnowhowConfigExamples.ts +0 -376
  274. package/src/prompts/index.ts +0 -9
  275. package/src/remotes.ts +0 -110
  276. package/src/server/index.ts +0 -16
  277. package/src/services/AgentService.ts +0 -134
  278. package/src/services/AgentSyncFs.ts +0 -775
  279. package/src/services/AgentSyncKnowhowWeb.ts +0 -389
  280. package/src/services/BehaviorsService.ts +0 -466
  281. package/src/services/DockerService.ts +0 -511
  282. package/src/services/EmbeddingService.ts +0 -427
  283. package/src/services/EmbeddingsService.ts +0 -73
  284. package/src/services/EventService.ts +0 -279
  285. package/src/services/ExtensionsService.ts +0 -25
  286. package/src/services/KnowhowClient.ts +0 -928
  287. package/src/services/LazyToolsService.ts +0 -210
  288. package/src/services/Mcp.ts +0 -727
  289. package/src/services/McpServer.ts +0 -155
  290. package/src/services/McpWebsocketTransport.ts +0 -87
  291. package/src/services/MediaProcessorService.ts +0 -669
  292. package/src/services/MessageProcessor.ts +0 -114
  293. package/src/services/MinimalToolsService.ts +0 -177
  294. package/src/services/RuntimeReloadService.ts +0 -31
  295. package/src/services/S3.ts +0 -61
  296. package/src/services/SessionManager.ts +0 -358
  297. package/src/services/SkillsService.ts +0 -822
  298. package/src/services/SyncedAgentWatcher.ts +0 -124
  299. package/src/services/SyncerService.ts +0 -191
  300. package/src/services/TaskRegistry.ts +0 -110
  301. package/src/services/Tools.ts +0 -580
  302. package/src/services/TracingService.ts +0 -116
  303. package/src/services/conversion/ConversionService.ts +0 -757
  304. package/src/services/conversion/index.ts +0 -2
  305. package/src/services/conversion/types.ts +0 -87
  306. package/src/services/flags.ts +0 -51
  307. package/src/services/index.ts +0 -117
  308. package/src/services/modules/computerUse.ts +0 -218
  309. package/src/services/modules/index.ts +0 -314
  310. package/src/services/modules/types.ts +0 -109
  311. package/src/services/types.ts +0 -60
  312. package/src/services/watchers/FsSyncer.ts +0 -199
  313. package/src/services/watchers/RemoteSyncer.ts +0 -196
  314. package/src/services/watchers/index.ts +0 -2
  315. package/src/tunnel.ts +0 -243
  316. package/src/types.ts +0 -282
  317. package/src/util/Trace.ts +0 -236
  318. package/src/utils/InputQueueManager.ts +0 -493
  319. package/src/utils/errors.ts +0 -0
  320. package/src/utils/http.ts +0 -150
  321. package/src/utils/index.ts +0 -111
  322. package/src/worker.ts +0 -696
  323. package/src/workerRegistry.ts +0 -152
  324. package/src/workers/auth/PasskeySetup.ts +0 -181
  325. package/src/workers/auth/WorkerPasskeyAuth.ts +0 -190
  326. package/src/workers/auth/WsMiddleware.ts +0 -99
  327. package/src/workers/auth/authMiddleware.ts +0 -104
  328. package/src/workers/auth/types.ts +0 -70
  329. package/src/workers/tools/getChallenge.ts +0 -33
  330. package/src/workers/tools/index.ts +0 -20
  331. package/src/workers/tools/listAllowedPorts.ts +0 -30
  332. package/src/workers/tools/lock.ts +0 -31
  333. package/src/workers/tools/reloadConfig.ts +0 -84
  334. package/src/workers/tools/unlock.ts +0 -116
  335. package/tests/XmlToolCallProcessor.test.ts +0 -468
  336. package/tests/agents/interrupt.test.ts +0 -200
  337. package/tests/agents/observe-base.test.ts +0 -183
  338. package/tests/agents/tools/connectAgent.test.ts +0 -138
  339. package/tests/agents/tools/observe.test.ts +0 -179
  340. package/tests/agents/tools/readFile.test.ts +0 -88
  341. package/tests/agents/tools/replyToParent.test.ts +0 -125
  342. package/tests/agents/tools/sendAgentMessage.test.ts +0 -99
  343. package/tests/agents/tools/waitForAgentCompleted.test.ts +0 -147
  344. package/tests/chat/detach-attach-rendering.test.ts +0 -315
  345. package/tests/clients/AIClient.test.ts +0 -668
  346. package/tests/clients/anthropic.test.ts +0 -202
  347. package/tests/clients/contextLimits.test.ts +0 -97
  348. package/tests/clients/fireworks.test.ts +0 -65
  349. package/tests/clients/openai.images.test.ts +0 -105
  350. package/tests/clients/pricing.test.ts +0 -206
  351. package/tests/clients/reasoningEffort.test.ts +0 -140
  352. package/tests/compressor/bigstring.test.ts +0 -450
  353. package/tests/compressor/bigstring.txt +0 -1
  354. package/tests/compressor/githubjson.txt +0 -1
  355. package/tests/compressor/toolResponseCache.test.ts +0 -304
  356. package/tests/compressor/usageBase64.json +0 -159
  357. package/tests/compressor/usageBase64.test.ts +0 -175
  358. package/tests/fixtures/fake-secret.txt +0 -1
  359. package/tests/manual/agent-events/run-test.ts +0 -203
  360. package/tests/manual/browser-login/README.md +0 -189
  361. package/tests/manual/browser-login/test_browser_login_basic.ts +0 -115
  362. package/tests/manual/browser-login/test_cli_integration.ts +0 -169
  363. package/tests/manual/browser-login/test_cross_platform_browser.ts +0 -186
  364. package/tests/manual/browser-login/test_error_scenarios.ts +0 -223
  365. package/tests/manual/cli/no-env.sh +0 -274
  366. package/tests/manual/clients/completions.json +0 -1151
  367. package/tests/manual/clients/completions.test.ts +0 -198
  368. package/tests/manual/file-edits/figma.test.ts +0 -3
  369. package/tests/manual/file-edits/fileblocks/readwrite.test.ts +0 -100
  370. package/tests/manual/file-edits/patching/input.txt +0 -145
  371. package/tests/manual/file-edits/patching/output.txt +0 -145
  372. package/tests/manual/file-edits/patching/patch.txt +0 -15
  373. package/tests/manual/file-edits/patching/unseen.txt +0 -80
  374. package/tests/manual/file-edits/patching.test.ts +0 -139
  375. package/tests/manual/modalities/README.md +0 -157
  376. package/tests/manual/modalities/google.modalities.test.ts +0 -335
  377. package/tests/manual/modalities/openai.modalities.test.ts +0 -329
  378. package/tests/manual/modalities/streaming.test.ts +0 -260
  379. package/tests/manual/modalities/xai.modalities.test.ts +0 -294
  380. package/tests/manual/test-concurrent-ask.ts +0 -43
  381. package/tests/manual/ycmd/debug_diagnostics_test.ts +0 -127
  382. package/tests/manual/ycmd/fixtures/debug_diagnostics.ts +0 -26
  383. package/tests/manual/ycmd/fixtures/file_change_test.ts +0 -17
  384. package/tests/manual/ycmd/minimal_advanced_test.ts +0 -108
  385. package/tests/manual/ycmd/simple_diagnostics_test.ts +0 -61
  386. package/tests/manual/ycmd/simple_test.ts +0 -74
  387. package/tests/manual/ycmd/test-typescript-sample.ts +0 -34
  388. package/tests/manual/ycmd/test_advanced_features.ts +0 -407
  389. package/tests/manual/ycmd/test_advanced_with_tools.ts +0 -320
  390. package/tests/manual/ycmd/test_comprehensive_typescript.ts +0 -179
  391. package/tests/manual/ycmd/test_diagnostics_file_changes.ts +0 -249
  392. package/tests/manual/ycmd/test_diagnostics_fix.ts +0 -99
  393. package/tests/manual/ycmd/test_diagnostics_simple.ts +0 -100
  394. package/tests/manual/ycmd/test_diagnostics_timing.ts +0 -120
  395. package/tests/manual/ycmd/test_discover_commands.ts +0 -310
  396. package/tests/manual/ycmd/test_endpoints.ts +0 -115
  397. package/tests/manual/ycmd/test_final_comprehensive.ts +0 -218
  398. package/tests/manual/ycmd/test_final_validation.ts +0 -150
  399. package/tests/manual/ycmd/test_implementation.js +0 -42
  400. package/tests/manual/ycmd/test_individual_ycmd_tool.ts +0 -39
  401. package/tests/manual/ycmd/test_server_manager.ts +0 -52
  402. package/tests/manual/ycmd/test_simple_debug.ts +0 -86
  403. package/tests/manual/ycmd/test_tsserver_workflow.js +0 -83
  404. package/tests/manual/ycmd/test_tsserver_workflow.ts +0 -122
  405. package/tests/manual/ycmd/test_typescript_simple.ts +0 -48
  406. package/tests/manual/ycmd/test_typescript_ycmd.ts +0 -105
  407. package/tests/manual/ycmd/test_workspace_config.ts +0 -90
  408. package/tests/manual/ycmd/test_ycmd_auto_start.ts +0 -137
  409. package/tests/manual/ycmd/test_ycmd_comprehensive.ts +0 -73
  410. package/tests/manual/ycmd/test_ycmd_connection.py +0 -10
  411. package/tests/manual/ycmd/test_ycmd_direct.ts +0 -142
  412. package/tests/manual/ycmd/test_ycmd_experiment.ts +0 -48
  413. package/tests/manual/ycmd/test_ycmd_final.ts +0 -200
  414. package/tests/manual/ycmd/test_ycmd_fixed.py +0 -18
  415. package/tests/manual/ycmd/test_ycmd_integration.ts +0 -112
  416. package/tests/manual/ycmd/test_ycmd_simple.ts +0 -45
  417. package/tests/manual/ycmd/test_ycmd_usage.py +0 -27
  418. package/tests/manual/ycmd/working_simple_test.ts +0 -134
  419. package/tests/patching/corrupted.test.ts +0 -78
  420. package/tests/patching/fixtures/transcript-mangles/agent-sync-fs-nested-catch.json +0 -9
  421. package/tests/patching/fixtures/transcript-mangles/automation-functions-crossed.json +0 -9
  422. package/tests/patching/fixtures/transcript-mangles/fruit-ninja-confirmed-retirement.json +0 -8
  423. package/tests/patching/imports.patch.txt +0 -11
  424. package/tests/patching/imports.test.ts +0 -43
  425. package/tests/patching/imports.txt +0 -11
  426. package/tests/patching/interface.patch.txt +0 -15
  427. package/tests/patching/interface.txt +0 -7
  428. package/tests/patching/patchFileOutput.test.ts +0 -328
  429. package/tests/patching/regression-2026.test.ts +0 -752
  430. package/tests/patching/transcriptMangleRegression.test.ts +0 -125
  431. package/tests/plugins/language/languagePlugin-content-triggers.test.ts +0 -346
  432. package/tests/plugins/language/languagePlugin-integration.test.ts +0 -471
  433. package/tests/plugins/language/languagePlugin.test.ts +0 -385
  434. package/tests/processes/managedProcessShim.test.ts +0 -59
  435. package/tests/processors/Base64ImageDetector.test.ts +0 -979
  436. package/tests/processors/CustomVariables.test.ts +0 -981
  437. package/tests/processors/CustomVariablesBenchmark.test.ts +0 -237
  438. package/tests/processors/HarmonyToolProcessor.test.ts +0 -490
  439. package/tests/processors/TokenCompressor.test.ts +0 -674
  440. package/tests/processors/ToolResponseCache.test.ts +0 -864
  441. package/tests/processors/tools/boundedRetrievalTools.test.ts +0 -68
  442. package/tests/processors/tools/grepToolResponse.test.ts +0 -159
  443. package/tests/services/ConversionService.test.ts +0 -154
  444. package/tests/services/DockerService.test.ts +0 -24
  445. package/tests/services/Tools.test.ts +0 -1738
  446. package/tests/services/ToolsService.setFunction.test.ts +0 -68
  447. package/tests/services/WorkerReloadConfig.test.ts +0 -141
  448. package/tests/test.spec.ts +0 -163
  449. package/tests/unit/InputQueueManager.test.ts +0 -174
  450. package/tests/unit/McpWebsocketTransport.test.ts +0 -56
  451. package/tests/unit/agents/historyRollback.test.ts +0 -53
  452. package/tests/unit/agents/tools/loadImageAsBase64.test.ts +0 -44
  453. package/tests/unit/auth/jwtStore.test.ts +0 -55
  454. package/tests/unit/auth/keyAuth.test.ts +0 -152
  455. package/tests/unit/auth/keyManager.test.ts +0 -130
  456. package/tests/unit/auth/registerIdentity.test.ts +0 -99
  457. package/tests/unit/chat/ToolCommandModule.test.ts +0 -71
  458. package/tests/unit/chat/historyCommandArgs.test.ts +0 -37
  459. package/tests/unit/clients/AIClient.test.ts +0 -454
  460. package/tests/unit/clients/anthropic.responseMetadata.test.ts +0 -81
  461. package/tests/unit/clients/attribution.test.ts +0 -185
  462. package/tests/unit/clients/http.responseMetadata.test.ts +0 -86
  463. package/tests/unit/clients/openai.responseMetadata.test.ts +0 -90
  464. package/tests/unit/clients/responseMetadata.test.ts +0 -123
  465. package/tests/unit/clients/withRetry.test.ts +0 -319
  466. package/tests/unit/commands/agents.test.ts +0 -111
  467. package/tests/unit/commands/github-credentials.test.ts +0 -210
  468. package/tests/unit/commands/misc.test.ts +0 -85
  469. package/tests/unit/commands/remote.test.ts +0 -79
  470. package/tests/unit/commands/sandbox.test.ts +0 -350
  471. package/tests/unit/hashes.test.ts +0 -23
  472. package/tests/unit/input-queue.test.ts +0 -80
  473. package/tests/unit/login.test.ts +0 -218
  474. package/tests/unit/modules/moduleLoading.test.ts +0 -305
  475. package/tests/unit/plugins/pluginLoading.test.ts +0 -97
  476. package/tests/unit/services/AgentSyncKnowhowWeb.test.ts +0 -38
  477. package/tests/unit/services/KnowhowClient.test.ts +0 -84
  478. package/tests/unit/services/LazyToolsService.test.ts +0 -53
  479. package/tests/unit/services/Mcp.test.ts +0 -56
  480. package/tests/unit/services/MinimalToolsService.test.ts +0 -424
  481. package/tests/unit/services/RuntimeReloadService.test.ts +0 -29
  482. package/tests/unit/services/SessionManager.test.ts +0 -43
  483. package/tests/unit/services/SyncedAgentWatcher.test.ts +0 -89
  484. package/tests/unit/services/SyncerService.test.ts +0 -45
  485. package/tests/unit/tunnel.test.ts +0 -51
  486. package/tests/unit/util/Trace.test.ts +0 -119
  487. package/tests/unit/utils/http.test.ts +0 -43
  488. package/ts_build/tests/XmlToolCallProcessor.test.d.ts +0 -1
  489. package/ts_build/tests/XmlToolCallProcessor.test.js +0 -376
  490. package/ts_build/tests/XmlToolCallProcessor.test.js.map +0 -1
  491. package/ts_build/tests/agents/interrupt.test.d.ts +0 -14
  492. package/ts_build/tests/agents/interrupt.test.js +0 -136
  493. package/ts_build/tests/agents/interrupt.test.js.map +0 -1
  494. package/ts_build/tests/agents/observe-base.test.d.ts +0 -1
  495. package/ts_build/tests/agents/observe-base.test.js +0 -149
  496. package/ts_build/tests/agents/observe-base.test.js.map +0 -1
  497. package/ts_build/tests/agents/tools/connectAgent.test.d.ts +0 -1
  498. package/ts_build/tests/agents/tools/connectAgent.test.js +0 -142
  499. package/ts_build/tests/agents/tools/connectAgent.test.js.map +0 -1
  500. package/ts_build/tests/agents/tools/observe.test.d.ts +0 -1
  501. package/ts_build/tests/agents/tools/observe.test.js +0 -148
  502. package/ts_build/tests/agents/tools/observe.test.js.map +0 -1
  503. package/ts_build/tests/agents/tools/readFile.test.d.ts +0 -1
  504. package/ts_build/tests/agents/tools/readFile.test.js +0 -90
  505. package/ts_build/tests/agents/tools/readFile.test.js.map +0 -1
  506. package/ts_build/tests/agents/tools/replyToParent.test.d.ts +0 -1
  507. package/ts_build/tests/agents/tools/replyToParent.test.js +0 -116
  508. package/ts_build/tests/agents/tools/replyToParent.test.js.map +0 -1
  509. package/ts_build/tests/agents/tools/sendAgentMessage.test.d.ts +0 -1
  510. package/ts_build/tests/agents/tools/sendAgentMessage.test.js +0 -112
  511. package/ts_build/tests/agents/tools/sendAgentMessage.test.js.map +0 -1
  512. package/ts_build/tests/agents/tools/waitForAgentCompleted.test.d.ts +0 -1
  513. package/ts_build/tests/agents/tools/waitForAgentCompleted.test.js +0 -147
  514. package/ts_build/tests/agents/tools/waitForAgentCompleted.test.js.map +0 -1
  515. package/ts_build/tests/chat/detach-attach-rendering.test.d.ts +0 -1
  516. package/ts_build/tests/chat/detach-attach-rendering.test.js +0 -168
  517. package/ts_build/tests/chat/detach-attach-rendering.test.js.map +0 -1
  518. package/ts_build/tests/clients/AIClient.test.d.ts +0 -1
  519. package/ts_build/tests/clients/AIClient.test.js +0 -483
  520. package/ts_build/tests/clients/AIClient.test.js.map +0 -1
  521. package/ts_build/tests/clients/anthropic.test.d.ts +0 -1
  522. package/ts_build/tests/clients/anthropic.test.js +0 -159
  523. package/ts_build/tests/clients/anthropic.test.js.map +0 -1
  524. package/ts_build/tests/clients/contextLimits.test.d.ts +0 -1
  525. package/ts_build/tests/clients/contextLimits.test.js +0 -69
  526. package/ts_build/tests/clients/contextLimits.test.js.map +0 -1
  527. package/ts_build/tests/clients/fireworks.test.d.ts +0 -1
  528. package/ts_build/tests/clients/fireworks.test.js +0 -65
  529. package/ts_build/tests/clients/fireworks.test.js.map +0 -1
  530. package/ts_build/tests/clients/openai.images.test.d.ts +0 -1
  531. package/ts_build/tests/clients/openai.images.test.js +0 -94
  532. package/ts_build/tests/clients/openai.images.test.js.map +0 -1
  533. package/ts_build/tests/clients/pricing.test.d.ts +0 -1
  534. package/ts_build/tests/clients/pricing.test.js +0 -124
  535. package/ts_build/tests/clients/pricing.test.js.map +0 -1
  536. package/ts_build/tests/clients/reasoningEffort.test.d.ts +0 -1
  537. package/ts_build/tests/clients/reasoningEffort.test.js +0 -116
  538. package/ts_build/tests/clients/reasoningEffort.test.js.map +0 -1
  539. package/ts_build/tests/compressor/bigstring.test.d.ts +0 -1
  540. package/ts_build/tests/compressor/bigstring.test.js +0 -275
  541. package/ts_build/tests/compressor/bigstring.test.js.map +0 -1
  542. package/ts_build/tests/compressor/toolResponseCache.test.d.ts +0 -1
  543. package/ts_build/tests/compressor/toolResponseCache.test.js +0 -250
  544. package/ts_build/tests/compressor/toolResponseCache.test.js.map +0 -1
  545. package/ts_build/tests/compressor/usageBase64.test.d.ts +0 -1
  546. package/ts_build/tests/compressor/usageBase64.test.js +0 -109
  547. package/ts_build/tests/compressor/usageBase64.test.js.map +0 -1
  548. package/ts_build/tests/manual/agent-events/run-test.d.ts +0 -2
  549. package/ts_build/tests/manual/agent-events/run-test.js +0 -148
  550. package/ts_build/tests/manual/agent-events/run-test.js.map +0 -1
  551. package/ts_build/tests/manual/browser-login/test_browser_login_basic.d.ts +0 -2
  552. package/ts_build/tests/manual/browser-login/test_browser_login_basic.js +0 -118
  553. package/ts_build/tests/manual/browser-login/test_browser_login_basic.js.map +0 -1
  554. package/ts_build/tests/manual/browser-login/test_cli_integration.d.ts +0 -2
  555. package/ts_build/tests/manual/browser-login/test_cli_integration.js +0 -163
  556. package/ts_build/tests/manual/browser-login/test_cli_integration.js.map +0 -1
  557. package/ts_build/tests/manual/browser-login/test_cross_platform_browser.d.ts +0 -2
  558. package/ts_build/tests/manual/browser-login/test_cross_platform_browser.js +0 -169
  559. package/ts_build/tests/manual/browser-login/test_cross_platform_browser.js.map +0 -1
  560. package/ts_build/tests/manual/browser-login/test_error_scenarios.d.ts +0 -2
  561. package/ts_build/tests/manual/browser-login/test_error_scenarios.js +0 -207
  562. package/ts_build/tests/manual/browser-login/test_error_scenarios.js.map +0 -1
  563. package/ts_build/tests/manual/clients/completions.test.d.ts +0 -1
  564. package/ts_build/tests/manual/clients/completions.test.js +0 -151
  565. package/ts_build/tests/manual/clients/completions.test.js.map +0 -1
  566. package/ts_build/tests/manual/file-edits/figma.test.d.ts +0 -0
  567. package/ts_build/tests/manual/file-edits/figma.test.js +0 -2
  568. package/ts_build/tests/manual/file-edits/figma.test.js.map +0 -1
  569. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.d.ts +0 -1
  570. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js +0 -110
  571. package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js.map +0 -1
  572. package/ts_build/tests/manual/file-edits/patching.test.d.ts +0 -1
  573. package/ts_build/tests/manual/file-edits/patching.test.js +0 -129
  574. package/ts_build/tests/manual/file-edits/patching.test.js.map +0 -1
  575. package/ts_build/tests/manual/modalities/google.modalities.test.d.ts +0 -1
  576. package/ts_build/tests/manual/modalities/google.modalities.test.js +0 -262
  577. package/ts_build/tests/manual/modalities/google.modalities.test.js.map +0 -1
  578. package/ts_build/tests/manual/modalities/openai.modalities.test.d.ts +0 -1
  579. package/ts_build/tests/manual/modalities/openai.modalities.test.js +0 -262
  580. package/ts_build/tests/manual/modalities/openai.modalities.test.js.map +0 -1
  581. package/ts_build/tests/manual/modalities/streaming.test.d.ts +0 -1
  582. package/ts_build/tests/manual/modalities/streaming.test.js +0 -216
  583. package/ts_build/tests/manual/modalities/streaming.test.js.map +0 -1
  584. package/ts_build/tests/manual/modalities/xai.modalities.test.d.ts +0 -1
  585. package/ts_build/tests/manual/modalities/xai.modalities.test.js +0 -219
  586. package/ts_build/tests/manual/modalities/xai.modalities.test.js.map +0 -1
  587. package/ts_build/tests/manual/test-concurrent-ask.d.ts +0 -1
  588. package/ts_build/tests/manual/test-concurrent-ask.js +0 -22
  589. package/ts_build/tests/manual/test-concurrent-ask.js.map +0 -1
  590. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.d.ts +0 -1
  591. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js +0 -124
  592. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js.map +0 -1
  593. package/ts_build/tests/manual/ycmd/minimal_advanced_test.d.ts +0 -2
  594. package/ts_build/tests/manual/ycmd/minimal_advanced_test.js +0 -114
  595. package/ts_build/tests/manual/ycmd/minimal_advanced_test.js.map +0 -1
  596. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.d.ts +0 -1
  597. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js +0 -84
  598. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js.map +0 -1
  599. package/ts_build/tests/manual/ycmd/simple_test.d.ts +0 -2
  600. package/ts_build/tests/manual/ycmd/simple_test.js +0 -92
  601. package/ts_build/tests/manual/ycmd/simple_test.js.map +0 -1
  602. package/ts_build/tests/manual/ycmd/test-typescript-sample.d.ts +0 -14
  603. package/ts_build/tests/manual/ycmd/test-typescript-sample.js +0 -20
  604. package/ts_build/tests/manual/ycmd/test-typescript-sample.js.map +0 -1
  605. package/ts_build/tests/manual/ycmd/test_advanced_features.d.ts +0 -2
  606. package/ts_build/tests/manual/ycmd/test_advanced_features.js +0 -306
  607. package/ts_build/tests/manual/ycmd/test_advanced_features.js.map +0 -1
  608. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.d.ts +0 -3
  609. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js +0 -271
  610. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js.map +0 -1
  611. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.d.ts +0 -2
  612. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js +0 -196
  613. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js.map +0 -1
  614. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.d.ts +0 -1
  615. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js +0 -184
  616. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js.map +0 -1
  617. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.d.ts +0 -2
  618. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js +0 -116
  619. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js.map +0 -1
  620. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.d.ts +0 -1
  621. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js +0 -114
  622. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js.map +0 -1
  623. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.d.ts +0 -1
  624. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js +0 -129
  625. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js.map +0 -1
  626. package/ts_build/tests/manual/ycmd/test_discover_commands.d.ts +0 -2
  627. package/ts_build/tests/manual/ycmd/test_discover_commands.js +0 -252
  628. package/ts_build/tests/manual/ycmd/test_discover_commands.js.map +0 -1
  629. package/ts_build/tests/manual/ycmd/test_endpoints.d.ts +0 -2
  630. package/ts_build/tests/manual/ycmd/test_endpoints.js +0 -130
  631. package/ts_build/tests/manual/ycmd/test_endpoints.js.map +0 -1
  632. package/ts_build/tests/manual/ycmd/test_final_comprehensive.d.ts +0 -2
  633. package/ts_build/tests/manual/ycmd/test_final_comprehensive.js +0 -231
  634. package/ts_build/tests/manual/ycmd/test_final_comprehensive.js.map +0 -1
  635. package/ts_build/tests/manual/ycmd/test_final_validation.d.ts +0 -2
  636. package/ts_build/tests/manual/ycmd/test_final_validation.js +0 -170
  637. package/ts_build/tests/manual/ycmd/test_final_validation.js.map +0 -1
  638. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.d.ts +0 -2
  639. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js +0 -37
  640. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js.map +0 -1
  641. package/ts_build/tests/manual/ycmd/test_server_manager.d.ts +0 -1
  642. package/ts_build/tests/manual/ycmd/test_server_manager.js +0 -38
  643. package/ts_build/tests/manual/ycmd/test_server_manager.js.map +0 -1
  644. package/ts_build/tests/manual/ycmd/test_simple_debug.d.ts +0 -2
  645. package/ts_build/tests/manual/ycmd/test_simple_debug.js +0 -109
  646. package/ts_build/tests/manual/ycmd/test_simple_debug.js.map +0 -1
  647. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.d.ts +0 -1
  648. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js +0 -138
  649. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js.map +0 -1
  650. package/ts_build/tests/manual/ycmd/test_typescript_simple.d.ts +0 -1
  651. package/ts_build/tests/manual/ycmd/test_typescript_simple.js +0 -76
  652. package/ts_build/tests/manual/ycmd/test_typescript_simple.js.map +0 -1
  653. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.d.ts +0 -1
  654. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js +0 -115
  655. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js.map +0 -1
  656. package/ts_build/tests/manual/ycmd/test_workspace_config.d.ts +0 -1
  657. package/ts_build/tests/manual/ycmd/test_workspace_config.js +0 -99
  658. package/ts_build/tests/manual/ycmd/test_workspace_config.js.map +0 -1
  659. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.d.ts +0 -2
  660. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js +0 -140
  661. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js.map +0 -1
  662. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.d.ts +0 -1
  663. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js +0 -93
  664. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js.map +0 -1
  665. package/ts_build/tests/manual/ycmd/test_ycmd_direct.d.ts +0 -2
  666. package/ts_build/tests/manual/ycmd/test_ycmd_direct.js +0 -159
  667. package/ts_build/tests/manual/ycmd/test_ycmd_direct.js.map +0 -1
  668. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.d.ts +0 -15
  669. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js +0 -68
  670. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js.map +0 -1
  671. package/ts_build/tests/manual/ycmd/test_ycmd_final.d.ts +0 -2
  672. package/ts_build/tests/manual/ycmd/test_ycmd_final.js +0 -205
  673. package/ts_build/tests/manual/ycmd/test_ycmd_final.js.map +0 -1
  674. package/ts_build/tests/manual/ycmd/test_ycmd_integration.d.ts +0 -3
  675. package/ts_build/tests/manual/ycmd/test_ycmd_integration.js +0 -119
  676. package/ts_build/tests/manual/ycmd/test_ycmd_integration.js.map +0 -1
  677. package/ts_build/tests/manual/ycmd/test_ycmd_simple.d.ts +0 -2
  678. package/ts_build/tests/manual/ycmd/test_ycmd_simple.js +0 -36
  679. package/ts_build/tests/manual/ycmd/test_ycmd_simple.js.map +0 -1
  680. package/ts_build/tests/manual/ycmd/working_simple_test.d.ts +0 -2
  681. package/ts_build/tests/manual/ycmd/working_simple_test.js +0 -144
  682. package/ts_build/tests/manual/ycmd/working_simple_test.js.map +0 -1
  683. package/ts_build/tests/patching/corrupted.test.d.ts +0 -1
  684. package/ts_build/tests/patching/corrupted.test.js +0 -53
  685. package/ts_build/tests/patching/corrupted.test.js.map +0 -1
  686. package/ts_build/tests/patching/imports.test.d.ts +0 -1
  687. package/ts_build/tests/patching/imports.test.js +0 -71
  688. package/ts_build/tests/patching/imports.test.js.map +0 -1
  689. package/ts_build/tests/patching/patchFileOutput.test.d.ts +0 -1
  690. package/ts_build/tests/patching/patchFileOutput.test.js +0 -269
  691. package/ts_build/tests/patching/patchFileOutput.test.js.map +0 -1
  692. package/ts_build/tests/patching/regression-2026.test.d.ts +0 -1
  693. package/ts_build/tests/patching/regression-2026.test.js +0 -528
  694. package/ts_build/tests/patching/regression-2026.test.js.map +0 -1
  695. package/ts_build/tests/patching/transcriptMangleRegression.test.d.ts +0 -1
  696. package/ts_build/tests/patching/transcriptMangleRegression.test.js +0 -104
  697. package/ts_build/tests/patching/transcriptMangleRegression.test.js.map +0 -1
  698. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.d.ts +0 -1
  699. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +0 -294
  700. package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +0 -1
  701. package/ts_build/tests/plugins/language/languagePlugin-integration.test.d.ts +0 -1
  702. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +0 -343
  703. package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +0 -1
  704. package/ts_build/tests/plugins/language/languagePlugin.test.d.ts +0 -1
  705. package/ts_build/tests/plugins/language/languagePlugin.test.js +0 -315
  706. package/ts_build/tests/plugins/language/languagePlugin.test.js.map +0 -1
  707. package/ts_build/tests/processes/managedProcessShim.test.d.ts +0 -1
  708. package/ts_build/tests/processes/managedProcessShim.test.js +0 -92
  709. package/ts_build/tests/processes/managedProcessShim.test.js.map +0 -1
  710. package/ts_build/tests/processors/Base64ImageDetector.test.d.ts +0 -1
  711. package/ts_build/tests/processors/Base64ImageDetector.test.js +0 -792
  712. package/ts_build/tests/processors/Base64ImageDetector.test.js.map +0 -1
  713. package/ts_build/tests/processors/CustomVariables.test.d.ts +0 -1
  714. package/ts_build/tests/processors/CustomVariables.test.js +0 -764
  715. package/ts_build/tests/processors/CustomVariables.test.js.map +0 -1
  716. package/ts_build/tests/processors/CustomVariablesBenchmark.test.d.ts +0 -1
  717. package/ts_build/tests/processors/CustomVariablesBenchmark.test.js +0 -179
  718. package/ts_build/tests/processors/CustomVariablesBenchmark.test.js.map +0 -1
  719. package/ts_build/tests/processors/HarmonyToolProcessor.test.d.ts +0 -1
  720. package/ts_build/tests/processors/HarmonyToolProcessor.test.js +0 -382
  721. package/ts_build/tests/processors/HarmonyToolProcessor.test.js.map +0 -1
  722. package/ts_build/tests/processors/TokenCompressor.test.d.ts +0 -1
  723. package/ts_build/tests/processors/TokenCompressor.test.js +0 -473
  724. package/ts_build/tests/processors/TokenCompressor.test.js.map +0 -1
  725. package/ts_build/tests/processors/ToolResponseCache.test.d.ts +0 -1
  726. package/ts_build/tests/processors/ToolResponseCache.test.js +0 -657
  727. package/ts_build/tests/processors/ToolResponseCache.test.js.map +0 -1
  728. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.d.ts +0 -1
  729. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js +0 -57
  730. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js.map +0 -1
  731. package/ts_build/tests/processors/tools/grepToolResponse.test.d.ts +0 -1
  732. package/ts_build/tests/processors/tools/grepToolResponse.test.js +0 -77
  733. package/ts_build/tests/processors/tools/grepToolResponse.test.js.map +0 -1
  734. package/ts_build/tests/services/ConversionService.test.d.ts +0 -1
  735. package/ts_build/tests/services/ConversionService.test.js +0 -154
  736. package/ts_build/tests/services/ConversionService.test.js.map +0 -1
  737. package/ts_build/tests/services/DockerService.test.d.ts +0 -1
  738. package/ts_build/tests/services/DockerService.test.js +0 -22
  739. package/ts_build/tests/services/DockerService.test.js.map +0 -1
  740. package/ts_build/tests/services/Tools.test.d.ts +0 -1
  741. package/ts_build/tests/services/Tools.test.js +0 -1365
  742. package/ts_build/tests/services/Tools.test.js.map +0 -1
  743. package/ts_build/tests/services/ToolsService.setFunction.test.d.ts +0 -1
  744. package/ts_build/tests/services/ToolsService.setFunction.test.js +0 -51
  745. package/ts_build/tests/services/ToolsService.setFunction.test.js.map +0 -1
  746. package/ts_build/tests/services/WorkerReloadConfig.test.d.ts +0 -1
  747. package/ts_build/tests/services/WorkerReloadConfig.test.js +0 -86
  748. package/ts_build/tests/services/WorkerReloadConfig.test.js.map +0 -1
  749. package/ts_build/tests/test.spec.d.ts +0 -1
  750. package/ts_build/tests/test.spec.js +0 -139
  751. package/ts_build/tests/test.spec.js.map +0 -1
  752. package/ts_build/tests/unit/InputQueueManager.test.d.ts +0 -1
  753. package/ts_build/tests/unit/InputQueueManager.test.js +0 -104
  754. package/ts_build/tests/unit/InputQueueManager.test.js.map +0 -1
  755. package/ts_build/tests/unit/McpWebsocketTransport.test.d.ts +0 -1
  756. package/ts_build/tests/unit/McpWebsocketTransport.test.js +0 -47
  757. package/ts_build/tests/unit/McpWebsocketTransport.test.js.map +0 -1
  758. package/ts_build/tests/unit/agents/historyRollback.test.d.ts +0 -1
  759. package/ts_build/tests/unit/agents/historyRollback.test.js +0 -42
  760. package/ts_build/tests/unit/agents/historyRollback.test.js.map +0 -1
  761. package/ts_build/tests/unit/agents/tools/loadImageAsBase64.test.d.ts +0 -1
  762. package/ts_build/tests/unit/agents/tools/loadImageAsBase64.test.js +0 -67
  763. package/ts_build/tests/unit/agents/tools/loadImageAsBase64.test.js.map +0 -1
  764. package/ts_build/tests/unit/auth/jwtStore.test.d.ts +0 -1
  765. package/ts_build/tests/unit/auth/jwtStore.test.js +0 -46
  766. package/ts_build/tests/unit/auth/jwtStore.test.js.map +0 -1
  767. package/ts_build/tests/unit/auth/keyAuth.test.d.ts +0 -1
  768. package/ts_build/tests/unit/auth/keyAuth.test.js +0 -118
  769. package/ts_build/tests/unit/auth/keyAuth.test.js.map +0 -1
  770. package/ts_build/tests/unit/auth/keyManager.test.d.ts +0 -1
  771. package/ts_build/tests/unit/auth/keyManager.test.js +0 -96
  772. package/ts_build/tests/unit/auth/keyManager.test.js.map +0 -1
  773. package/ts_build/tests/unit/auth/registerIdentity.test.d.ts +0 -1
  774. package/ts_build/tests/unit/auth/registerIdentity.test.js +0 -92
  775. package/ts_build/tests/unit/auth/registerIdentity.test.js.map +0 -1
  776. package/ts_build/tests/unit/chat/ToolCommandModule.test.d.ts +0 -1
  777. package/ts_build/tests/unit/chat/ToolCommandModule.test.js +0 -61
  778. package/ts_build/tests/unit/chat/ToolCommandModule.test.js.map +0 -1
  779. package/ts_build/tests/unit/chat/historyCommandArgs.test.d.ts +0 -1
  780. package/ts_build/tests/unit/chat/historyCommandArgs.test.js +0 -29
  781. package/ts_build/tests/unit/chat/historyCommandArgs.test.js.map +0 -1
  782. package/ts_build/tests/unit/clients/AIClient.test.d.ts +0 -1
  783. package/ts_build/tests/unit/clients/AIClient.test.js +0 -342
  784. package/ts_build/tests/unit/clients/AIClient.test.js.map +0 -1
  785. package/ts_build/tests/unit/clients/anthropic.responseMetadata.test.d.ts +0 -1
  786. package/ts_build/tests/unit/clients/anthropic.responseMetadata.test.js +0 -77
  787. package/ts_build/tests/unit/clients/anthropic.responseMetadata.test.js.map +0 -1
  788. package/ts_build/tests/unit/clients/attribution.test.d.ts +0 -1
  789. package/ts_build/tests/unit/clients/attribution.test.js +0 -153
  790. package/ts_build/tests/unit/clients/attribution.test.js.map +0 -1
  791. package/ts_build/tests/unit/clients/http.responseMetadata.test.d.ts +0 -1
  792. package/ts_build/tests/unit/clients/http.responseMetadata.test.js +0 -77
  793. package/ts_build/tests/unit/clients/http.responseMetadata.test.js.map +0 -1
  794. package/ts_build/tests/unit/clients/openai.responseMetadata.test.d.ts +0 -1
  795. package/ts_build/tests/unit/clients/openai.responseMetadata.test.js +0 -86
  796. package/ts_build/tests/unit/clients/openai.responseMetadata.test.js.map +0 -1
  797. package/ts_build/tests/unit/clients/responseMetadata.test.d.ts +0 -1
  798. package/ts_build/tests/unit/clients/responseMetadata.test.js +0 -96
  799. package/ts_build/tests/unit/clients/responseMetadata.test.js.map +0 -1
  800. package/ts_build/tests/unit/clients/withRetry.test.d.ts +0 -1
  801. package/ts_build/tests/unit/clients/withRetry.test.js +0 -225
  802. package/ts_build/tests/unit/clients/withRetry.test.js.map +0 -1
  803. package/ts_build/tests/unit/commands/agents.test.d.ts +0 -1
  804. package/ts_build/tests/unit/commands/agents.test.js +0 -119
  805. package/ts_build/tests/unit/commands/agents.test.js.map +0 -1
  806. package/ts_build/tests/unit/commands/github-credentials.test.d.ts +0 -1
  807. package/ts_build/tests/unit/commands/github-credentials.test.js +0 -145
  808. package/ts_build/tests/unit/commands/github-credentials.test.js.map +0 -1
  809. package/ts_build/tests/unit/commands/misc.test.d.ts +0 -1
  810. package/ts_build/tests/unit/commands/misc.test.js +0 -70
  811. package/ts_build/tests/unit/commands/misc.test.js.map +0 -1
  812. package/ts_build/tests/unit/commands/remote.test.d.ts +0 -1
  813. package/ts_build/tests/unit/commands/remote.test.js +0 -70
  814. package/ts_build/tests/unit/commands/remote.test.js.map +0 -1
  815. package/ts_build/tests/unit/commands/sandbox.test.d.ts +0 -1
  816. package/ts_build/tests/unit/commands/sandbox.test.js +0 -258
  817. package/ts_build/tests/unit/commands/sandbox.test.js.map +0 -1
  818. package/ts_build/tests/unit/hashes.test.d.ts +0 -1
  819. package/ts_build/tests/unit/hashes.test.js +0 -25
  820. package/ts_build/tests/unit/hashes.test.js.map +0 -1
  821. package/ts_build/tests/unit/input-queue.test.d.ts +0 -1
  822. package/ts_build/tests/unit/input-queue.test.js +0 -32
  823. package/ts_build/tests/unit/input-queue.test.js.map +0 -1
  824. package/ts_build/tests/unit/login.test.d.ts +0 -1
  825. package/ts_build/tests/unit/login.test.js +0 -166
  826. package/ts_build/tests/unit/login.test.js.map +0 -1
  827. package/ts_build/tests/unit/modules/moduleLoading.test.d.ts +0 -1
  828. package/ts_build/tests/unit/modules/moduleLoading.test.js +0 -272
  829. package/ts_build/tests/unit/modules/moduleLoading.test.js.map +0 -1
  830. package/ts_build/tests/unit/plugins/pluginLoading.test.d.ts +0 -1
  831. package/ts_build/tests/unit/plugins/pluginLoading.test.js +0 -117
  832. package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +0 -1
  833. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.d.ts +0 -1
  834. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js +0 -32
  835. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js.map +0 -1
  836. package/ts_build/tests/unit/services/KnowhowClient.test.d.ts +0 -1
  837. package/ts_build/tests/unit/services/KnowhowClient.test.js +0 -69
  838. package/ts_build/tests/unit/services/KnowhowClient.test.js.map +0 -1
  839. package/ts_build/tests/unit/services/LazyToolsService.test.d.ts +0 -1
  840. package/ts_build/tests/unit/services/LazyToolsService.test.js +0 -47
  841. package/ts_build/tests/unit/services/LazyToolsService.test.js.map +0 -1
  842. package/ts_build/tests/unit/services/Mcp.test.d.ts +0 -1
  843. package/ts_build/tests/unit/services/Mcp.test.js +0 -45
  844. package/ts_build/tests/unit/services/Mcp.test.js.map +0 -1
  845. package/ts_build/tests/unit/services/MinimalToolsService.test.d.ts +0 -1
  846. package/ts_build/tests/unit/services/MinimalToolsService.test.js +0 -320
  847. package/ts_build/tests/unit/services/MinimalToolsService.test.js.map +0 -1
  848. package/ts_build/tests/unit/services/RuntimeReloadService.test.d.ts +0 -1
  849. package/ts_build/tests/unit/services/RuntimeReloadService.test.js +0 -26
  850. package/ts_build/tests/unit/services/RuntimeReloadService.test.js.map +0 -1
  851. package/ts_build/tests/unit/services/SessionManager.test.d.ts +0 -1
  852. package/ts_build/tests/unit/services/SessionManager.test.js +0 -72
  853. package/ts_build/tests/unit/services/SessionManager.test.js.map +0 -1
  854. package/ts_build/tests/unit/services/SyncedAgentWatcher.test.d.ts +0 -1
  855. package/ts_build/tests/unit/services/SyncedAgentWatcher.test.js +0 -78
  856. package/ts_build/tests/unit/services/SyncedAgentWatcher.test.js.map +0 -1
  857. package/ts_build/tests/unit/services/SyncerService.test.d.ts +0 -1
  858. package/ts_build/tests/unit/services/SyncerService.test.js +0 -40
  859. package/ts_build/tests/unit/services/SyncerService.test.js.map +0 -1
  860. package/ts_build/tests/unit/tunnel.test.d.ts +0 -1
  861. package/ts_build/tests/unit/tunnel.test.js +0 -47
  862. package/ts_build/tests/unit/tunnel.test.js.map +0 -1
  863. package/ts_build/tests/unit/util/Trace.test.d.ts +0 -1
  864. package/ts_build/tests/unit/util/Trace.test.js +0 -107
  865. package/ts_build/tests/unit/util/Trace.test.js.map +0 -1
  866. package/ts_build/tests/unit/utils/http.test.d.ts +0 -1
  867. package/ts_build/tests/unit/utils/http.test.js +0 -69
  868. package/ts_build/tests/unit/utils/http.test.js.map +0 -1
  869. package/tsconfig.json +0 -34
  870. package/tslint.json +0 -11
@@ -1,9 +0,0 @@
1
- {
2
- "taskId": "1785613689-for-the-usage-tracking-write-the-full-agent-thread",
3
- "sourceBefore": "/**\n * Agent Synchronization Service - Filesystem-based synchronization\n * Handles synchronization via filesystem files in .knowhow/processes/agents/taskId/\n */\nimport { BaseAgent } from \"../agents/base/base\";\nimport { promises as fs } from \"fs\";\nimport * as path from \"path\";\nimport { watch } from \"fs\";\n\nexport interface FsSyncOptions {\n taskId: string;\n prompt: string;\n agentName?: string;\n /** The taskId of the parent agent that spawned this task, if any. */\n parentTaskId?: string;\n}\n\n/**\n * AgentSyncFs handles filesystem-based synchronization for agent tasks\n * Creates files in .knowhow/processes/agents/{taskId}/ for status and input\n */\nexport class AgentSyncFs {\n /** Shared cleanup interval across all instances to avoid duplicate cleanup runs */\n private static sharedCleanupInterval: NodeJS.Timeout | null = null;\n private static sharedBasePath: string = \".knowhow/processes/agents\";\n private static cleanupStarted: boolean = false;\n\n private taskId: string | undefined;\n private basePath: string = \".knowhow/processes/agents\";\n private taskPath: string | undefined;\n private eventHandlersSetup: boolean = false;\n private watcher: ReturnType<typeof watch> | null = null;\n private lastInputContent: string = \"\";\n private finalizationPromise: Promise<void> | null = null;\n private agent: BaseAgent | undefined;\n private threadUpdateHandler: ((...args: any[]) => void) | undefined;\n private doneHandler: ((...args: any[]) => void) | undefined;\n private tokenUsageHandler: ((...args: any[]) => void) | undefined;\n /**\n * Tracks the most recent in-flight filesystem metadata update.\n * The done handler awaits this before finalizing, preventing a race where\n * the completion call writes before the last thread sync finishes.\n */\n private pendingThreadUpdatePromise: Promise<void> | null = null;\n\n constructor() {\n // Start cleanup process when created\n AgentSyncFs.startSharedCleanupProcess();\n }\n\n /**\n * Create filesystem sync for a task\n */\n async createTask(options: FsSyncOptions): Promise<string> {\n this.taskId = options.taskId;\n this.taskPath = path.join(this.basePath, this.taskId);\n\n try {\n // Create directory structure\n await fs.mkdir(this.taskPath, { recursive: true });\n\n // Create initial files\n await this.writeStatus(\"running\");\n await this.writeInput(\"\");\n await this.writeMetadata({\n taskId: this.taskId,\n // Record the OS process id of this agent subprocess so orchestrating\n // tools (e.g. waitForAgentCompleted) can detect a crashed-but-not-\n // finalized task via process-liveness. This is the child's own pid,\n // so it needs no coordination with the spawner and never touches\n // execCommand's child processes.\n pid: process.pid,\n prompt: options.prompt,\n agentName: options.agentName || \"unknown\",\n ...(options.parentTaskId ? { parentTaskId: options.parentTaskId } : {}),\n startTime: new Date().toISOString(),\n status: \"running\",\n });\n\n console.log(`\u2705 Created filesystem sync at: ${this.taskPath}`);\n return this.taskId;\n } catch (error) {\n console.error(`\u274c Failed to create filesystem sync:`, error);\n throw error;\n }\n }\n\n /**\n * Update task status\n */\n private async writeStatus(status: string): Promise<void> {\n if (!this.taskPath) return;\n\n try {\n const statusPath = path.join(this.taskPath, \"status.txt\");\n await fs.writeFile(statusPath, status, \"utf8\");\n } catch (error) {\n console.error(`\u274c Failed to write status:`, error);\n }\n }\n\n /**\n * Write input file (used for initial state)\n */\n private async writeInput(content: string): Promise<void> {\n if (!this.taskPath) return;\n\n try {\n const inputPath = path.join(this.taskPath, \"input.txt\");\n await fs.writeFile(inputPath, content, \"utf8\");\n this.lastInputContent = content;\n } catch (error) {\n console.error(`\u274c Failed to write input:`, error);\n }\n }\n\n /**\n * Write metadata file\n */\n private async writeMetadata(data: any): Promise<void> {\n if (!this.taskPath) return;\n\n try {\n const metadataPath = path.join(this.taskPath, \"metadata.json\");\n await fs.writeFile(metadataPath, JSON.stringify(data, null, 2), \"utf8\");\n } catch (error) {\n console.error(`\u274c Failed to write metadata:`, error);\n }\n }\n\n /**\n * Append a token usage entry (including the full message chain sent for\n * that call) to usage.json. This is intended for debugging cache-hit\n * issues, where comparing the message chains and usage values between\n * consecutive calls can reveal when a cache prefix was invalidated.\n */\n private async appendUsageEntry(entry: any): Promise<void> {\n if (!this.taskPath) return;\n\n try {\n const usagePath = path.join(this.taskPath, \"usage.json\");\n let entries: any[] = [];\n\n try {\n const existingData = await fs.readFile(usagePath, \"utf8\");\n entries = JSON.parse(existingData);\n } catch {\n // File doesn't exist or is invalid, start fresh\n }\n\n entries.push(entry);\n await fs.writeFile(usagePath, JSON.stringify(entries, null, 2), \"utf8\");\n } catch (error) {\n console.error(`\u274c Failed to append usage entry:`, error);\n }\n }\n\n /**\n * Update metadata file with current agent state\n */\n private async updateMetadata(\n agent: BaseAgent,\n inProgress: boolean,\n result?: string\n ): Promise<void> {\n if (!this.taskPath) return;\n\n try {\n const metadataPath = path.join(this.taskPath, \"metadata.json\");\n let metadata: any = {};\n\n try {\n const existingData = await fs.readFile(metadataPath, \"utf8\");\n metadata = JSON.parse(existingData);\n } catch {\n // File doesn't exist or is invalid, start fresh\n }\n\n metadata.threads = agent.getThreads();\n metadata.totalCostUsd = agent.getTotalCostUsd();\n metadata.tokenUsage = agent.getTokenUsage();\n metadata.agentName = agent.name;\n // Record the model/provider actually in use at this sync so task\n // history reflects the real model (including mid-run fallbacks), not\n // just the named agent.\n metadata.model = agent.getModel();\n metadata.provider = agent.getProvider();\n // Persist reasoning settings so a resume can restore the exact\n // reasoning effort / summarize behavior the run was using. (The\n // encrypted reasoning items + summaries themselves ride along on the\n // thread messages via `_reasoning_details` / `reasoning_summary`.)\n metadata.reasoningEffort = agent.getReasoningEffort?.();\n metadata.summarizeReasoning = agent.getSummarizeReasoning?.();\n metadata.inProgress = inProgress;\n metadata.lastUpdate = new Date().toISOString();\n\n if (result !== undefined) {\n metadata.result = result;\n metadata.status = \"completed\";\n await this.writeStatus(\"completed\");\n }\n\n await fs.writeFile(\n metadataPath,\n JSON.stringify(metadata, null, 2),\n \"utf8\"\n );\n } catch (error) {\n console.error(`\u274c Failed to update metadata:`, error);\n }\n }\n\n /**\n * Read and process status file changes\n */\n private async readStatus(): Promise<string | null> {\n if (!this.taskPath) return null;\n\n try {\n const statusPath = path.join(this.taskPath, \"status.txt\");\n const content = await fs.readFile(statusPath, \"utf8\");\n return content.trim();\n } catch (error) {\n // File might not exist or be accessible\n return null;\n }\n }\n\n /**\n * Read and process input file changes\n */\n private async readInput(): Promise<string | null> {\n if (!this.taskPath) return null;\n\n try {\n const inputPath = path.join(this.taskPath, \"input.txt\");\n const content = await fs.readFile(inputPath, \"utf8\");\n return content;\n } catch (error) {\n // File might not exist or be accessible\n return null;\n }\n }\n\n /**\n * Check for file changes and process them\n */\n private async checkForChanges(agent: BaseAgent): Promise<void> {\n if (!this.taskPath) return;\n\n try {\n // Check status changes\n const status = await this.readStatus();\n if (status === \"paused\") {\n console.log(`\u23f8\ufe0f Agent task ${this.taskId} paused via filesystem`);\n await agent.pause();\n await this.waitForResume(agent);\n } else if (status === \"killed\") {\n console.log(`\ud83d\uded1 Agent task ${this.taskId} killed via filesystem`);\n await agent.kill();\n }\n\n // Check for new input/messages\n const input = await this.readInput();\n if (input && input !== this.lastInputContent && input.trim() !== \"\") {\n console.log(\n `\ud83d\udcec New message received via filesystem for task ${this.taskId}`\n );\n this.lastInputContent = input;\n\n // Detect slash commands in the input\n if (input.trim().startsWith(\"/\")) {\n await this.handleInputCommand(agent, input.trim());\n } else {\n agent.addPendingUserMessage({\n role: \"user\",\n content: input,\n });\n }\n\n // Clear the input file after processing\n await this.writeInput(\"\");\n }\n } catch (error) {\n console.error(`\u274c Error checking for changes:`, error);\n }\n }\n\n /**\n * Handle slash commands sent via input.txt\n */\n private async handleInputCommand(agent: BaseAgent, input: string): Promise<void> {\n const [command, ...rest] = input.split(\" \");\n const message = rest.join(\" \").trim() || undefined;\n\n if (command === \"/poke\") {\n console.log(`\ud83e\udef5 Received /poke command for task ${this.taskId}`);\n agent.interrupt(message);\n } else {\n // Unknown command \u2014 treat as a regular message\n console.warn(`\u26a0\ufe0f Unknown command \"${command}\", treating as message`);\n agent.addPendingUserMessage({ role: \"user\", content: input });\n }\n }\n\n /**\n * Wait for resume by monitoring status file\n */\n private async waitForResume(agent: BaseAgent): Promise<void> {\n const POLL_INTERVAL_MS = 2000;\n const MAX_WAIT_MS = 60 * 60 * 1000; // 1 hour\n const startTime = Date.now();\n\n while (Date.now() - startTime < MAX_WAIT_MS) {\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n\n const status = await this.readStatus();\n\n if (status === \"killed\") {\n console.log(`\ud83d\uded1 Agent task ${this.taskId} killed while paused`);\n await agent.kill();\n return;\n }\n\n if (status === \"running\") {\n console.log(`\u25b6\ufe0f Agent task ${this.taskId} resumed`);\n await agent.unpause();\n return;\n }\n }\n\n console.warn(`\u26a0\ufe0f Timeout waiting for resume on task ${this.taskId}`);\n }\n\n /**\n * Setup filesystem watching for the task\n */\n private setupFileWatcher(agent: BaseAgent): void {\n if (!this.taskPath || this.watcher) return;\n\n try {\n this.watcher = watch(this.taskPath, async (eventType, filename) => {\n if (filename === \"status.txt\" || filename === \"input.txt\") {\n await this.checkForChanges(agent);\n }\n });\n\n console.log(`\ud83d\udc41\ufe0f Watching filesystem at: ${this.taskPath}`);\n } catch (error) {\n console.error(`\u274c Failed to setup file watcher:`, error);\n }\n }\n\n /**\n * Set up event-based synchronization for an agent task\n */\n async setupAgentSync(agent: BaseAgent, taskId?: string): Promise<void> {\n if (!taskId) return;\n\n this.taskId = taskId;\n this.taskPath = path.join(this.basePath, this.taskId);\n\n // Ensure directory exists (might have been created by createTask)\n try {\n await fs.mkdir(this.taskPath, { recursive: true });\n } catch (error) {\n // Directory might already exist\n }\n\n if (!this.eventHandlersSetup) {\n this.setupEventHandlers(agent);\n this.setupFileWatcher(agent);\n this.eventHandlersSetup = true;\n }\n }\n\n /**\n * Set up event handlers for automatic synchronization\n */\n private setupEventHandlers(agent: BaseAgent): void {\n this.agent = agent;\n\n // Listen to thread updates to sync state (store reference for cleanup)\n this.threadUpdateHandler = async () => {\n if (!this.taskId) return;\n\n try {\n // Track the pending update so the done handler can await it.\n this.pendingThreadUpdatePromise = (async () => {\n await this.updateMetadata(agent, true);\n await this.checkForChanges(agent);\n })();\n await this.pendingThreadUpdatePromise;\n } catch (error) {\n console.error(`\u274c Error during threadUpdate sync:`, error);\n }\n };\n agent.agentEvents.on(\n agent.eventTypes.threadUpdate,\n this.threadUpdateHandler\n );\n\n // Listen to token usage events to record per-call usage + message chain\n // (store reference for cleanup). This is written to usage.json so that\n // cache-hit/cache-miss issues can be debugged by comparing the message\n // chain and usage values sent/received on consecutive AI calls.\n this.tokenUsageHandler = (usage: any) => {\n this.appendUsageEntry(usage).catch((error) => {\n console.error(`\u274c Error recording token usage:`, error);\n });\n };\n agent.agentEvents.on(\n agent.eventTypes.tokenUsage,\n this.tokenUsageHandler\n );\n\n // Listen to completion event to finalize task (store reference for cleanup)\n this.doneHandler = (result: string) => {\n if (!this.taskId) {\n console.warn(`\u26a0\ufe0f [AgentSyncFs] Cannot finalize: taskId=${this.taskId}`);\n return;\n }\n\n console.log(\n `\ud83c\udfaf [AgentSyncFs] Done event received for task: ${this.taskId}`\n );\n\n // Store finalization promise so callers can await it (same pattern as AgentSyncKnowhowWeb)\n this.finalizationPromise = (async () => {\n try {\n // Flush any in-flight thread update before finalizing.\n // This prevents the race where a pending \"inProgress: true\" metadata write\n // overwrites the finalization write.\n if (this.pendingThreadUpdatePromise) {\n console.log(\n `\u23f3 [AgentSyncFs] Awaiting pending thread update before finalizing...`\n );\n await this.pendingThreadUpdatePromise.catch(() => {\n // Ignore errors in pending update \u2014 we still want to finalize\n });\n this.pendingThreadUpdatePromise = null;\n }\n\n await this.updateMetadata(agent, false, result);\n console.log(`\u2705 Completed filesystem sync for task: ${this.taskId}`);\n await this.cleanup();\n } catch (error) {\n console.error(`\u274c Error finalizing task:`, error);\n throw error;\n }\n })();\n };\n agent.agentEvents.on(agent.eventTypes.done, this.doneHandler);\n }\n\n /**\n * Wait for finalization to complete (for CLI usage)\n */\n async waitForFinalization(): Promise<void> {\n if (this.finalizationPromise) {\n await this.finalizationPromise;\n }\n }\n\n /**\n * Cleanup task directory and watcher\n */\n async cleanup(): Promise<void> {\n if (this.watcher) {\n this.watcher.close();\n this.watcher = null;\n }\n\n // Note: We don't delete the directory here to preserve task history\n // The cleanup process will handle old directories\n }\n\n /**\n * Clean up old task directories (older than 3 days)\n */\n private static async cleanupOldTasks(): Promise<void> {\n try {\n const agentsPath = AgentSyncFs.sharedBasePath;\n\n // Check if directory exists\n try {\n await fs.access(agentsPath);\n } catch {\n // Directory doesn't exist, nothing to clean\n return;\n }\n\n const entries = await fs.readdir(agentsPath, { withFileTypes: true });\n const now = Date.now();\n const threeDaysMs = 3 * 24 * 60 * 60 * 1000;\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const taskPath = path.join(agentsPath, entry.name);\n\n try {\n const stats = await fs.stat(taskPath);\n const age = now - stats.mtimeMs;\n\n if (age > threeDaysMs) {\n console.log(`\ud83e\uddf9 Cleaning up old task directory: ${entry.name}`);\n await fs.rm(taskPath, { recursive: true, force: true });\n }\n } catch (error) {\n // Skip if we can't stat or delete\n console.error(`\u274c Error cleaning up ${entry.name}:`, error);\n }\n }\n\n // Also clean up old execCommand background log files in .knowhow/processes/*.txt\n await AgentSyncFs.cleanupOldProcessLogs(threeDaysMs);\n } catch (error) {\n console.error(`\u274c Error during cleanup:`, error);\n }\n }\n\n /**\n * Clean up old execCommand background log files (.knowhow/processes/*.txt).\n * These are created by the execCommand tool when running background/long-lived\n * commands, and are never cleaned up otherwise.\n */\n private static async cleanupOldProcessLogs(maxAgeMs: number): Promise<void> {\n try {\n // execCommand writes logs to the parent of the agents dir: .knowhow/processes\n const processesPath = path.dirname(AgentSyncFs.sharedBasePath);\n\n try {\n await fs.access(processesPath);\n } catch {\n return;\n }\n\n const entries = await fs.readdir(processesPath, { withFileTypes: true });\n const now = Date.now();\n\n for (const entry of entries) {\n // Only target the .txt log files that execCommand creates; leave the\n // agents/ directory (and any other subdirectories) alone.\n if (!entry.isFile() || !entry.name.endsWith(\".txt\")) continue;\n\n const logPath = path.join(processesPath, entry.name);\n\n try {\n const stats = await fs.stat(logPath);\n const age = now - stats.mtimeMs;\n\n if (age > maxAgeMs) {\n console.log(`\ud83e\uddf9 Cleaning up old process log file: ${entry.name}`);\n await fs.rm(logPath, { force: true });\n }\n } catch (error) {\n // Skip if we can't stat or delete\n console.error(`\u274c Error cleaning up log ${entry.name}:`, error);\n }\n }\n } catch (error) {\n console.error(`\u274c Error during process log cleanup:`, error);\n }\n }\n\n /**\n * Start periodic cleanup process\n */\n private static startSharedCleanupProcess(): void {\n if (AgentSyncFs.cleanupStarted) return;\n AgentSyncFs.cleanupStarted = true;\n\n // Run cleanup every hour (shared across all instances)\n AgentSyncFs.sharedCleanupInterval = setInterval(() => {\n AgentSyncFs.cleanupOldTasks();\n }, 60 * 60 * 1000);\n\n // Also run once on startup\n AgentSyncFs.cleanupOldTasks();\n }\n\n /**\n * Stop cleanup process\n */\n stopCleanup(): void {\n if (AgentSyncFs.sharedCleanupInterval) {\n clearInterval(AgentSyncFs.sharedCleanupInterval);\n AgentSyncFs.sharedCleanupInterval = null;\n AgentSyncFs.cleanupStarted = false;\n }\n }\n\n /**\n * Reset synchronization state\n */\n reset(): void {\n // Remove old event listeners from the agent before resetting\n if (this.agent) {\n if (this.threadUpdateHandler) {\n this.agent.agentEvents.removeListener(\n this.agent.eventTypes.threadUpdate,\n this.threadUpdateHandler\n );\n this.threadUpdateHandler = undefined;\n }\n if (this.tokenUsageHandler) {\n this.agent.agentEvents.removeListener(\n this.agent.eventTypes.tokenUsage,\n this.tokenUsageHandler\n );\n this.tokenUsageHandler = undefined;\n }\n if (this.doneHandler) {\n this.agent.agentEvents.removeListener(\n this.agent.eventTypes.done,\n this.doneHandler\n );\n this.doneHandler = undefined;\n }\n this.agent = undefined;\n }\n this.cleanup();\n this.taskId = undefined;\n this.taskPath = undefined;\n this.eventHandlersSetup = false;\n this.lastInputContent = \"\";\n this.finalizationPromise = null;\n this.pendingThreadUpdatePromise = null;\n }\n}\n",
4
- "patch": "@@ -131,7 +131,7 @@\n /**\n * Append a token usage entry (including the full message chain sent for\n * that call) to usage.json. This is intended for debugging cache-hit\n- * issues, where comparing the message chains and usage values between\n+ * issues, where comparing the message chains and usage values between\n * consecutive calls can reveal when a cache prefix was invalidated.\n+ *\n+ * To prevent exponential file growth, if the new entry's message thread\n+ * fully contains the previous entry's thread as a prefix, the previous\n+ * thread is replaced with { PREV_CACHE_HIT: true } so only the new\n+ * messages (the delta) are stored alongside the new usage data.\n */\n private async appendUsageEntry(entry: any): Promise<void> {\n if (!this.taskPath) return;\n@@ -143,7 +143,26 @@\n try {\n const existingData = await fs.readFile(usagePath, \"utf8\");\n entries = JSON.parse(existingData);\n } catch {\n // File doesn't exist or is invalid, start fresh\n }\n \n- entries.push(entry);\n+ // If the new entry's messages are a superset of the last entry's\n+ // messages (i.e. the last thread is a prefix of the new thread),\n+ // collapse the last entry's messages to { PREV_CACHE_HIT: true }\n+ // and store only the new delta \u2014 preventing exponential growth.\n+ if (entries.length > 0) {\n+ const lastEntry = entries[entries.length - 1];\n+ const prevMessages: any[] = lastEntry?.messages;\n+ const newMessages: any[] = entry?.messages;\n+ if (\n+ Array.isArray(prevMessages) &&\n+ Array.isArray(newMessages) &&\n+ prevMessages.length > 0 &&\n+ newMessages.length >= prevMessages.length &&\n+ JSON.stringify(newMessages.slice(0, prevMessages.length)) ===\n+ JSON.stringify(prevMessages)\n+ ) {\n+ // Replace the previous full thread with a compact sentinel\n+ lastEntry.messages = [{ PREV_CACHE_HIT: true }];\n+ }\n+ }\n+\n+ entries.push(entry);\n await fs.writeFile(usagePath, JSON.stringify(entries, null, 2), \"utf8\");\n } catch (error) {\n console.error(`\u274c Failed to append usage entry:`, error);\n",
5
- "observedAfter": "131: /**\n132: * Append a token usage entry (including the full message chain sent for\n133: * that call) to usage.json. This is intended for debugging cache-hit\n134: * issues, where comparing the message chains and usage values between\n135: * consecutive calls can reveal when a cache prefix was invalidated.\n136: *\n137: * To prevent exponential file growth, if the new entry's message thread\n138: * fully contains the previous entry's thread as a prefix, the previous\n139: * thread is replaced with { PREV_CACHE_HIT: true } so only the new\n140: * messages (the delta) are stored alongside the new usage data.\n141: */\n142: private async appendUsageEntry(entry: any): Promise<void> {\n143: if (!this.taskPath) return;\n144: \n145: try {\n146: const usagePath = path.join(this.taskPath, \"usage.json\");\n147: let entries: any[] = [];\n148: \n149: try {\n150: const existingData = await fs.readFile(usagePath, \"utf8\");\n151: // If the new entry's messages are a superset of the last entry's\n152: // messages (i.e. the last thread is a prefix of the new thread),\n153: // collapse the last entry's messages to { PREV_CACHE_HIT: true }\n154: // and store only the new delta \u2014 preventing exponential growth.\n155: if (entries.length > 0) {\n156: const lastEntry = entries[entries.length - 1];\n157: const prevMessages: any[] = lastEntry?.messages;\n158: const newMessages: any[] = entry?.messages;\n159: if (\n160: Array.isArray(prevMessages) &&\n161: Array.isArray(newMessages) &&\n162: prevMessages.length > 0 &&\n163: newMessages.length >= prevMessages.length &&\n164: JSON.stringify(newMessages.slice(0, prevMessages.length)) ===\n165: JSON.stringify(prevMessages)\n166: ) {\n167: // Replace the previous full thread with a compact sentinel\n168: lastEntry.messages = [{ PREV_CACHE_HIT: true }];\n169: }\n170: }\n171: \n172: entries.push(entry);\n173: } catch {\n174: // File doesn't exist or is invalid, start fresh\n175: }\n176: \n177: entries.push(entry);\n178: await fs.writeFile(usagePath, JSON.stringify(entries, null, 2), \"utf8\");\n179: } catch (error) {\n180: console.error(`\u274c Failed to append usage entry:`, error);\n181: }\n182: }\n183: \n184: /**\n185: * Update metadata file with current agent state",
6
- "agentStatement": "The patch got mangled \u2014 the code is nested incorrectly. Let me rewrite the method cleanly:",
7
- "sourceRevision": "b0634f8^",
8
- "sourcePath": "packages/knowhow/src/services/AgentSyncFs.ts"
9
- }
@@ -1,9 +0,0 @@
1
- {
2
- "taskId": "1785594693-okay-just-tried-the-computer-use-agent-play-game",
3
- "sourceBefore": "import * as fs from \"fs\";\nimport * as path from \"path\";\nimport {\n AccessibilityElement,\n AccessibilityOptions,\n Point,\n Region,\n} from \"@tyvm/knowhow\";\nimport {\n ComputerService,\n ColorRegion,\n DesktopBox,\n DesktopShape,\n OcrResult,\n ReadTextOptions,\n} from \"./ComputerService\";\nimport { resolveRegionAsync } from \"./regions\";\n\n/**\n * Automations \u2014 a locally-run perception\u2192action loop that the LLM authors once\n * (after watching a game/UI) and then launches with a single tool call. The LLM\n * (the slow, smart \"coach\") stays OUT of the per-frame loop; the automation (the\n * fast, dumb \"actor\") runs entirely in-process at a tight interval with no model\n * round-trip per target, which is the only way to beat the ~1s human bar.\n *\n * Design (see .knowhow/tasks/computer-use-improvements/implementation-plan.md):\n * - The automation is a .ts async function body with access to a small `sdk`.\n * - It can call `await sdk.requiredWindow(...)`; if OS focus leaves that window\n * the runner auto-pauses (action methods become no-ops), so a human\n * interrupts any automation just by clicking away / Cmd-Tabbing out.\n * - It supports `dryRun`, where action methods RECORD intent instead of moving\n * the real mouse \u2014 this powers offline testAutomation against a recording.\n */\n\nconst STORE_DIR = path.join(\".knowhow\", \"automations\");\n\n/**\n * Hard ceiling on how long ANY automation may run before it is force-stopped.\n * Automations take over the real mouse/keyboard, so a human needs to be able to\n * reliably reclaim control quickly. We cap every run at 10s (regardless of what\n * the caller requests) so a runaway automation can never hold the mouse hostage\n * for longer than that. Re-launch the automation if you legitimately need more time.\n */\nexport const MAX_AUTOMATION_DURATION_MS = 30000;\n\n/** Default run duration when the caller doesn't specify one. */\nexport const DEFAULT_AUTOMATION_DURATION_MS = 30000;\n\nexport interface WindowMatch {\n /** Substring (case-insensitive) that must appear in the active window title. */\n titleIncludes?: string;\n /** Substring (case-insensitive) that must appear in the active window app. */\n app?: string;\n}\n\nexport interface AutomationSpec {\n name: string;\n /** Async function body. Receives (sdk). May `await` sdk.* calls. */\n script: string;\n /** Parsed structured header (see parseAutomationDoc) describing when to use it. */\n doc?: AutomationDoc;\n /** Absolute path to the saved .ts file (populated by loaders). */\n filePath?: string;\n}\n\n/**\n * Structured \"skill card\" for an automation, parsed from a JSDoc-style header\n * comment at the very top of the script. This is what makes an automation\n * DISCOVERABLE: it tells a future agent what the automation does, WHEN to reach\n * for it, what the screen must look like before it runs, and what it leaves\n * behind afterward \u2014 so the agent can pick the right automation without reading\n * (or guessing at) the whole implementation.\n */\nexport interface AutomationDoc {\n description?: string;\n useWhen?: string;\n startState?: string;\n endState?: string;\n window?: string;\n notes?: string;\n}\n\nexport interface AutomationAction {\n t: number;\n kind:\n | \"clickAt\"\n | \"moveMouse\"\n | \"type\"\n | \"key\"\n | \"hotkey\"\n | \"focus\"\n | \"selectAccessibilityOption\"\n | \"setAccessibilityValue\"\n | \"performAccessibilityAction\";\n x?: number;\n y?: number;\n button?: string;\n text?: string;\n /** True when the runner suppressed this action (paused / dry-run). */\n suppressed?: boolean;\n}\n\nexport interface AutomationLogEntry {\n t: number;\n data: any;\n}\n\nexport interface AutomationRunResult {\n name: string;\n elapsedMs: number;\n stopped: \"duration\" | \"manual\" | \"completed\" | \"error\";\n error?: string;\n actions: AutomationAction[];\n actionCount: number;\n logs: AutomationLogEntry[];\n pausedMs: number;\n dryRun: boolean;\n /** The window gate that was in effect (if any) \u2014 the focus-loss auto-pause. */\n requiredWindow?: WindowMatch;\n /**\n * True when a LIVE run performed real actions without ever configuring a\n * required-window gate. Such a run can't be reclaimed by clicking away, so\n * callers should treat this as a warning.\n */\n ranWithoutWindowGate?: boolean;\n}\n\nexport interface AutomationControl {\n paused: boolean;\n stopped: boolean;\n requiredWindow?: WindowMatch;\n stop(): void;\n}\n\n/**\n * The surface handed to an authored automation script. Perception methods read\n * real rendered pixels; action methods drive the real mouse/keyboard (unless\n * paused or in dry-run). Everything is in ABSOLUTE DESKTOP coordinates.\n */\nexport interface AutomationSDK {\n // \u2500\u2500 perception (real pixels) \u2500\u2500\n screenSize(): Promise<{ width: number; height: number }>;\n /** Return the currently focused window, if one can be identified. */\n activeWindow(): Promise<{ title: string; app?: string; bounds?: Region } | null>;\n /**\n * Inspect the focused window's native accessibility tree. Element IDs are\n * short-lived: discover and use an element before requesting another tree.\n */\n accessibilityTrusted(): Promise<boolean>;\n accessibilityElements(opts?: AccessibilityOptions): Promise<AccessibilityElement[]>;\n findColor(\n colors: string | string[],\n opts?: {\n region?: Region | string;\n tolerance?: number;\n minPixels?: number;\n minSize?: number;\n maxSize?: number;\n }\n ): Promise<ColorRegion[]>;\n findShape(opts: {\n kind: \"line-h\" | \"line-v\" | \"rect\" | \"square\" | \"circle\" | \"blob\";\n color?: string;\n region?: Region | string;\n tolerance?: number;\n minSize?: number;\n maxSize?: number;\n length?: number;\n thickness?: number;\n }): Promise<DesktopShape[]>;\n findBoxes(opts?: {\n region?: Region | string;\n minSize?: number;\n maxSize?: number;\n minEdgeScore?: number;\n maxBoxes?: number;\n }): Promise<DesktopBox[]>;\n /**\n * Detect UI element regions by color segmentation, returned as a nested\n * containment hierarchy in ABSOLUTE DESKTOP coords (each box: bounds, center,\n * area, depth, children). Useful for \"find the clickable things in the play\n * area\" without knowing their exact color:\n * - mode \"panels\" (default here): find large flat BACKGROUND surfaces and\n * group the FOREGROUND content on each into element boxes (score readouts,\n * button rows) \u2014 i.e. things that AREN'T the background color.\n * - mode \"colors\": one box per contiguous same-color area, nested.\n * - mode \"foreground\": everything differing from the dominant background.\n * Pass a region to constrain the search (e.g. the playfield) so you only get\n * targets inside the game area.\n */\n findRegions(opts?: {\n region?: Region | string;\n mode?: \"foreground\" | \"colors\" | \"panels\";\n minSize?: number;\n colorBits?: number;\n clusterGap?: number;\n minPixels?: number;\n maxBoxes?: number;\n }): Promise<DesktopBox[]>;\n pixelColor(x: number, y: number): Promise<string>;\n\n // \u2500\u2500 action (no-op while paused; recorded in dry-run) \u2500\u2500\n clickAt(x: number, y: number, button?: \"left\" | \"right\" | \"middle\"): Promise<void>;\n moveMouse(x: number, y: number): Promise<void>;\n type(text: string): Promise<void>;\n key(name: string): Promise<void>;\n /** Press a key chord, e.g. `[\"command\", \"a\"]`. */\n hotkey(keys: string[]): Promise<void>;\n /** Focus an app/window. Call before installing requiredWindow. */\n focus(match: string): Promise<boolean>;\n /** Select a pop-up/combo-box option without keyboard type-ahead. */\n selectAccessibilityOption(id: string, option: string): Promise<void>;\n /** Set a settable accessibility element value using a fresh discovered ID. */\n setAccessibilityValue(id: string, value: string): Promise<void>;\n /** Perform an allowlisted AX action (for example AXPress or AXShowMenu). */\n performAccessibilityAction(id: string, action: string): Promise<void>;\n\n // \u2500\u2500 control / telemetry \u2500\u2500\n sleep(ms: number): Promise<void>;\n now(): number;\n elapsed(): number;\n log(data: any): void;\n /**\n * Run this callback repeatedly on a fixed interval (in MILLISECONDS, like\n * setInterval) until the run is stopped (or the max duration cap is\n * reached). The interval is measured between iteration starts; if a callback\n * overruns its interval it simply runs again immediately (after a yield).\n * Pass `intervalMs` of 0 to run as fast as possible. Optionally pass\n * `{ requiredWindow }` to gate the loop on a focused window in one call \u2014\n * equivalent to awaiting sdk.requiredWindow(match) first, so actions auto-\n * pause the moment focus leaves that window (the primary way a human reclaims\n * the mouse mid-run).\n */\n runEvery(\n callback: () => void | Promise<void>,\n intervalMs: number,\n opts?: { requiredWindow?: WindowMatch }\n ): Promise<void>;\n /** Set/clear the focus gate. Await before performing actions. */\n requiredWindow(match?: WindowMatch): Promise<void>;\n /**\n * Read text from the screen (or a named/explicit region) using macOS Vision\n * OCR. Returns recognized text regions in ABSOLUTE DESKTOP coordinates,\n * sorted top-to-bottom then left-to-right.\n * Each result: { text, confidence, bounds, center }\n * bounds/center are desktop coords ready for clickAt().\n * Pass a region to restrict OCR to part of the screen \u2014 faster, less noise.\n * On non-macOS platforms, returns [].\n */\n readText(opts?: {\n region?: Region | string;\n displayId?: number;\n activeWindow?: boolean;\n minConfidence?: number;\n }): Promise<OcrResult[]>;\n readonly ctl: AutomationControl;\n}\n\n/**\n * Editor/type-only binding for authored automation files. At execution time\n * the runner injects the real value and removes its SDK import declaration.\n */\nexport const sdk: AutomationSDK = undefined as any;\n\n// \u2500\u2500 registry (running instances, so stopAutomation can reach them) \u2500\u2500\nconst running = new Map<string, AutomationRunner>();\n\nexport function getRunning(name: string): AutomationRunner | undefined {\n return running.get(name);\n}\n\nexport function listRunning(): string[] {\n return [...running.keys()];\n}\n\n/** Persisted automation storage (git-trackable). */\nexport function automationPath(name: string): string {\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return path.join(STORE_DIR, `${safe}.ts`);\n}\n\n/**\n * Extract the structured \"skill card\" from an automation script. We look for a\n * leading block comment (before any executable code) and read JSDoc-style tags:\n * @description one-liner of what it does\n * @useWhen the situation/trigger that should make an agent pick this\n * @startState what the screen must look like BEFORE running\n * @endState what the screen will look like AFTER it finishes\n * @window the required window (title/app) it operates on\n * @notes anything else worth knowing (limits, caveats)\n * Tag text may wrap onto continuation lines. Returns undefined when no\n * recognizable header is present.\n */\nexport function parseAutomationDoc(script: string): AutomationDoc | undefined {\n const block = script.match(/^\\s*\\/\\*\\*?([\\s\\S]*?)\\*\\//);\n if (!block) return undefined;\n // Strip leading \" * \" decoration from each comment line.\n const body = block[1]\n .split(\"\\n\")\n .map((l) => l.replace(/^\\s*\\*?\\s?/, \"\"))\n .join(\"\\n\");\n\n const tags: Record<string, string> = {};\n let current: string | null = null;\n const known = new Set([\n \"description\",\n \"usewhen\",\n \"startstate\",\n \"endstate\",\n \"window\",\n \"notes\",\n ]);\n for (const rawLine of body.split(\"\\n\")) {\n const line = rawLine.trimEnd();\n const m = line.match(/^@(\\w+)\\s*(.*)$/);\n if (m && known.has(m[1].toLowerCase())) {\n current = m[1].toLowerCase();\n tags[current] = m[2].trim();\n } else if (current && line.trim()) {\n tags[current] = (tags[current] + \" \" + line.trim()).trim();\n }\n }\n if (!Object.keys(tags).length) return undefined;\n const doc: AutomationDoc = {\n description: tags[\"description\"],\n useWhen: tags[\"usewhen\"],\n startState: tags[\"startstate\"],\n endState: tags[\"endstate\"],\n window: tags[\"window\"],\n notes: tags[\"notes\"],\n };\n // Drop empty keys for a tidy summary.\n for (const k of Object.keys(doc) as (keyof AutomationDoc)[]) {\n if (!doc[k]) delete doc[k];\n }\n return Object.keys(doc).length ? doc : undefined;\n}\n\nexport function saveAutomation(spec: AutomationSpec): AutomationSpec {\n fs.mkdirSync(STORE_DIR, { recursive: true });\n fs.writeFileSync(automationPath(spec.name), spec.script);\n return { ...spec, doc: parseAutomationDoc(spec.script), filePath: automationPath(spec.name) };\n}\n\nexport function loadAutomation(name: string): AutomationSpec {\n const spec = loadAutomationSafe(name);\n if (!spec) throw new Error(`No automation named \"${name}\".`);\n return spec;\n}\n\nexport function loadAutomationSafe(name: string): AutomationSpec | undefined {\n try {\n const p = automationPath(name);\n if (fs.existsSync(p)) {\n const script = fs.readFileSync(p, \"utf8\");\n return { name, script, doc: parseAutomationDoc(script), filePath: p };\n }\n // Read old files during migration, but all new writes use plain .ts files.\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n const legacy = path.join(STORE_DIR, `${safe}.automation.json`);\n if (!fs.existsSync(legacy)) return undefined;\n const parsed = JSON.parse(fs.readFileSync(legacy, \"utf8\"));\n return {\n name,\n script: parsed.script,\n doc: parseAutomationDoc(parsed.script || \"\"),\n filePath: legacy,\n };\n } catch {\n return undefined;\n }\n}\n\nexport function listAutomations(): AutomationSpec[] {\n try {\n if (!fs.existsSync(STORE_DIR)) return [];\n return fs\n .readdirSync(STORE_DIR)\n .filter((f) => f.endsWith(\".ts\"))\n .map((f) => loadAutomationSafe(f.slice(0, -3)) || null)\n .filter((x): x is AutomationSpec => !!x);\n } catch {\n return [];\n }\n}\n\nexport function deleteAutomation(name: string): boolean {\n const p = automationPath(name);\n let deleted = false;\n if (fs.existsSync(p)) {\n fs.unlinkSync(p);\n deleted = true;\n }\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n const legacy = path.join(STORE_DIR, `${safe}.automation.json`);\n if (fs.existsSync(legacy)) {\n fs.unlinkSync(legacy);\n deleted = true;\n }\n return deleted;\n}\n\n/**\n * Reject scripts that try to escape the SDK sandbox. Automations must \"play\"\n * honestly \u2014 only real pixels in, real mouse out \u2014 so we forbid network/shell/\n * filesystem/module access. This is a static guard, not a full sandbox; the\n * script still runs with `new Function` and only `sdk` in scope.\n */\nconst FORBIDDEN_TOKENS = [\n \"require\",\n \"import\",\n \"process\",\n \"child_process\",\n \"fetch\",\n \"eval\",\n \"Function\",\n \"globalThis\",\n \"__dirname\",\n \"__filename\",\n \"XMLHttpRequest\",\n \"WebSocket\",\n];\n\nconst SDK_IMPORT = /^\\s*import\\s*\\{\\s*sdk\\s*\\}\\s*from\\s*[\"']@tyvm\\/knowhow-module-computer-use[\"']\\s*;?\\s*$/gm;\n\n/** Remove the one editor-only import supported by automation source files. */\nexport function prepareAutomationScript(script: string): string {\n return script.replace(SDK_IMPORT, \"\");\n}\n\nexport function validateScript(script: string): void {\n script = prepareAutomationScript(script);\n for (const tok of FORBIDDEN_TOKENS) {\n const re = new RegExp(`\\\\b${tok}\\\\b`);\n if (re.test(script)) {\n throw new Error(\n `Automation script rejected: forbidden token \"${tok}\". Automations may only use the provided sdk (perception + mouse/keyboard). No network, shell, filesystem, or module access.`\n );\n }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst AsyncFunction = Object.getPrototypeOf(async function () {})\n .constructor as {\n new (...args: string[]): (...a: any[]) => Promise<any>;\n};\n\nexport interface RunOptions {\n maxDurationMs?: number;\n /** When true, action methods record intent but do NOT move the real mouse. */\n dryRun?: boolean;\n /** Poll interval for the window-focus gate (default 200ms). */\n gatePollMs?: number;\n /** Optional callback for streamed telemetry (e.g. push to the coach). */\n onLog?: (entry: AutomationLogEntry) => void;\n /**\n * Delay (ms) between the SDK's moveMouse and the click inside clickAt so the\n * OS commits the new cursor position before the button event \u2014 otherwise a\n * click posted back-to-back with a move can register at a stale location\n * (default 40).\n */\n clickSettleMs?: number;\n}\n\n/**\n * Runs a single automation instance: builds the SDK, enforces the window gate\n * (auto-pause on focus loss), guards a max duration, and collects telemetry.\n */\nexport class AutomationRunner {\n readonly spec: AutomationSpec;\n private svc: ComputerService;\n private opts: RunOptions;\n private startedAt = 0;\n private pausedAccumMs = 0;\n private pauseStartedAt = 0;\n private actions: AutomationAction[] = [];\n private logs: AutomationLogEntry[] = [];\n private gateTimer: NodeJS.Timeout | null = null;\n private durationTimer: NodeJS.Timeout | null = null;\n /** True once a non-empty required-window gate has been configured. */\n private everGatedWindow = false;\n /** Resolved max run duration (ms). Set at the start of run(). */\n maxDurationMs = DEFAULT_AUTOMATION_DURATION_MS;\n private stopReason: \"duration\" | \"manual\" | \"completed\" | \"error\" | null =\n null;\n\n readonly ctl: AutomationControl = {\n paused: false,\n stopped: false,\n requiredWindow: undefined,\n stop: () => {\n if (!this.ctl.stopped) this.stopReason = this.stopReason ?? \"manual\";\n this.ctl.stopped = true;\n },\n };\n\n constructor(spec: AutomationSpec, svc: ComputerService, opts: RunOptions = {}) {\n this.spec = spec;\n this.svc = svc;\n this.opts = opts;\n }\n\n private now(): number {\n return Date.now();\n }\n\n elapsed(): number {\n return this.startedAt ? this.now() - this.startedAt : 0;\n }\n\n private matchesWindow(\n active: { title: string; app?: string } | null,\n match?: WindowMatch\n ): boolean {\n if (!match || (!match.titleIncludes && !match.app)) return true;\n if (!active) return false;\n const title = (active.title || \"\").toLowerCase();\n const app = (active.app || \"\").toLowerCase();\n const titleMatches = !match.titleIncludes ||\n title.includes(match.titleIncludes.toLowerCase());\n const appMatches = !match.app || app.includes(match.app.toLowerCase());\n // When both selectors are supplied they describe one target window, not\n // alternatives. Requiring both prevents another Chrome tab from opening\n // the gate merely because its owning application matches.\n return titleMatches && appMatches;\n }\n\n private async pollGate(): Promise<void> {\n if (this.ctl.stopped) return;\n if (!this.ctl.requiredWindow) return;\n let active: { title: string; app?: string } | null = null;\n try {\n active = (await this.svc.getActiveWindow()) as any;\n } catch {\n active = null;\n }\n const ok = this.matchesWindow(active, this.ctl.requiredWindow);\n if (!ok && !this.ctl.paused) {\n this.ctl.paused = true;\n this.pauseStartedAt = this.now();\n this.emit({\n paused: \"window-focus-lost\",\n active: active?.title || null,\n });\n } else if (ok && this.ctl.paused) {\n this.ctl.paused = false;\n if (this.pauseStartedAt) {\n this.pausedAccumMs += this.now() - this.pauseStartedAt;\n this.pauseStartedAt = 0;\n }\n this.emit({ resumed: true, active: active?.title || null });\n }\n }\n\n private async configureRequiredWindow(match?: WindowMatch): Promise<void> {\n this.ctl.requiredWindow = match;\n if (match && (match.titleIncludes || match.app)) {\n this.everGatedWindow = true;\n }\n if (this.gateTimer) {\n clearInterval(this.gateTimer);\n this.gateTimer = null;\n }\n if (!match || (!match.titleIncludes && !match.app)) {\n if (this.ctl.paused) {\n this.ctl.paused = false;\n if (this.pauseStartedAt) {\n this.pausedAccumMs += this.now() - this.pauseStartedAt;\n this.pauseStartedAt = 0;\n }\n this.emit({ resumed: true, gateCleared: true });\n }\n return;\n }\n\n // Awaiting this function guarantees the next action is already gated.\n await this.pollGate();\n const gateMs = Math.max(50, this.opts.gatePollMs ?? 200);\n this.gateTimer = setInterval(() => {\n this.pollGate().catch(() => {});\n }, gateMs);\n if (this.gateTimer.unref) this.gateTimer.unref();\n }\n\n private emit(data: any): void {\n const entry: AutomationLogEntry = { t: this.elapsed(), data };\n this.logs.push(entry);\n if (this.opts.onLog) {\n try {\n this.opts.onLog(entry);\n } catch {\n /* streaming is best-effort */\n }\n }\n }\n\n private canAct(): boolean {\n return !this.ctl.stopped && !this.ctl.paused && !this.opts.dryRun;\n }\n\n private buildSDK(): AutomationSDK {\n const svc = this.svc;\n const self = this;\n const clickSettleMs = Math.max(0, this.opts.clickSettleMs ?? 40);\n const sdk: AutomationSDK = {\n ctl: this.ctl,\n runEvery: async (callback, intervalMs, opts) => {\n if (typeof callback !== \"function\") {\n throw new Error(\"sdk.runEvery(callback, intervalMs) requires a function.\");\n }\n if (!Number.isFinite(intervalMs) || intervalMs < 0) {\n throw new Error(\n \"sdk.runEvery(callback, intervalMs) requires a non-negative interval in milliseconds.\"\n );\n }\n // Inline focus gate: gate the loop on a window in one call so authors\n // don't forget the requiredWindow guard that lets a human reclaim the\n // mouse just by clicking away.\n if (opts?.requiredWindow) {\n await self.configureRequiredWindow(opts.requiredWindow);\n }\n // Hard backstop: even if the OS-level duration timer is starved (see\n // below), never let this loop outlive the configured max duration.\n const deadline = self.startedAt\n ? self.startedAt + self.maxDurationMs\n : Number.POSITIVE_INFINITY;\n while (!self.ctl.stopped) {\n const iterationStarted = self.now();\n // In-loop duration guard. The setTimeout-based durationTimer is a\n // macrotask; a callback that consistently runs longer than intervalMs\n // (screen capture + shape detection easily do) would otherwise leave\n // `remaining <= 0`, skip the setTimeout yield, and spin as a tight\n // microtask loop \u2014 starving timers AND SIGINT so neither the 30s\n // timeout nor Ctrl-C could ever fire. Check the deadline directly.\n if (iterationStarted >= deadline) {\n if (!self.ctl.stopped) {\n self.stopReason = self.stopReason ?? \"duration\";\n self.ctl.stopped = true;\n self.emit({ stopped: \"duration\", maxDurationMs: self.maxDurationMs });\n }\n break;\n }\n // A required-window gate scopes perception as well as input. Do not\n // start the callback while paused: OCR/screenshot calls are reads and\n // cannot be suppressed by canAct(), so running them here would capture\n // the terminal used to launch the automation on another display.\n if (self.ctl.paused) {\n await new Promise((resolve) => setTimeout(resolve, 25));\n continue;\n }\n await callback();\n if (self.ctl.stopped) break;\n const remaining = intervalMs - (self.now() - iterationStarted);\n if (remaining > 0) {\n await new Promise((resolve) => setTimeout(resolve, remaining));\n } else {\n // The callback overran its interval budget (screen capture + shape\n // detection routinely do). Yield with a real timer tick rather than\n // setImmediate: setImmediate callbacks run in the event loop's\n // \"check\" phase and, when re-queued every iteration, can keep\n // starving the \"timers\" phase \u2014 which is exactly where the /poke\n // input watcher's setInterval and the agent's interrupt handling\n // live. A setTimeout(0) forces the loop through the timers phase\n // each iteration, so /poke (and Ctrl-C) stay responsive while an\n // automation is running hot.\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n }\n },\n requiredWindow: (match) => self.configureRequiredWindow(match),\n\n screenSize: () => svc.screenSize(),\n activeWindow: () => svc.getActiveWindow() as any,\n accessibilityTrusted: () => svc.accessibilityTrusted(),\n accessibilityElements: (o = {}) => svc.accessibilityElements(o),\n\n findColor: async (colors, o = {}) =>\n svc.findColorRegions({\n colors: Array.isArray(colors) ? colors : [colors],\n region: await resolveRegionAsync(o.region as any, () => svc.getActiveWindow()),\n tolerance: o.tolerance,\n minPixels: o.minPixels,\n minSize: o.minSize,\n maxSize: o.maxSize,\n } as any),\n\n findShape: async (o) =>\n svc.findShapes({\n kind: o.kind,\n color: o.color,\n region: await resolveRegionAsync(o.region as any, () => svc.getActiveWindow()),\n tolerance: o.tolerance,\n minSize: o.minSize,\n maxSize: o.maxSize,\n length: o.length,\n thickness: o.thickness,\n } as any),\n\n findBoxes: async (o = {}) =>\n svc.findBoxes({\n region: await resolveRegionAsync(o.region as any, () => svc.getActiveWindow()),\n minSize: o.minSize,\n maxSize: o.maxSize,\n minEdgeScore: o.minEdgeScore,\n maxBoxes: o.maxBoxes,\n } as any),\n\n findRegions: async (o = {}) =>\n svc.findRegions({\n region: await resolveRegionAsync(o.region as any, () => svc.getActiveWindow()),\n // Default to \"panels\" in automations: it groups foreground content\n // over background surfaces, which is what \"find the clickable things\n // that aren't the background\" usually means for a game/UI.\n mode: o.mode ?? \"panels\",\n minSize: o.minSize,\n colorBits: o.colorBits,\n clusterGap: o.clusterGap,\n minPixels: o.minPixels,\n maxBoxes: o.maxBoxes,\n } as any),\n\n pixelColor: (x, y) => svc.pixelColor({ x, y }),\n\n readText: (o = {}) => svc.readText(o as ReadTextOptions),\n\n clickAt: async (x, y, button = \"left\") => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"clickAt\",\n x,\n y,\n button,\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.moveMouse({ x, y });\n // Let the OS commit the cursor move before the button event; a click\n // fired back-to-back with a move can register at a stale position.\n if (clickSettleMs) await new Promise((r) => setTimeout(r, clickSettleMs));\n await svc.click(button);\n },\n\n moveMouse: async (x, y) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"moveMouse\",\n x,\n y,\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.moveMouse({ x, y });\n },\n\n type: async (text) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"type\",\n text,\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.typeText(text);\n },\n\n key: async (name) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"key\",\n text: name,\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.pressKey(name);\n },\n\n hotkey: async (keys) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"hotkey\",\n text: keys.join(\"+\"),\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.hotkey(...keys);\n },\n\n focus: async (match) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"focus\",\n text: match,\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n // Intentionally obeys the same dry-run, stopped, and focus-gate pause\n // rules as every other action. Authors that need to establish focus\n // must call this before requiredWindow/runEvery installs its gate.\n if (!self.canAct()) return false;\n return svc.focusWindow(match);\n },\n\n selectAccessibilityOption: async (id, option) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"selectAccessibilityOption\",\n text: JSON.stringify({ id, option }),\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.selectAccessibilityOption(id, option);\n },\n\n setAccessibilityValue: async (id, value) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"setAccessibilityValue\",\n text: JSON.stringify({ id, value }),\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.setAccessibilityValue(id, value);\n },\n\n performAccessibilityAction: async (id, action) => {\n const act: AutomationAction = {\n t: self.elapsed(),\n kind: \"performAccessibilityAction\",\n text: JSON.stringify({ id, action }),\n suppressed: !self.canAct(),\n };\n self.actions.push(act);\n if (!self.canAct()) return;\n await svc.performAccessibilityAction(id, action);\n },\n\n sleep: (ms) =>\n new Promise((resolve) => {\n const capped = Math.max(0, Math.min(60000, ms || 0));\n setTimeout(resolve, capped);\n }),\n\n now: () => self.now(),\n elapsed: () => self.elapsed(),\n log: (data) => self.emit(data),\n };\n return sdk;\n }\n\n async run(): Promise<AutomationRunResult> {\n const script = prepareAutomationScript(this.spec.script);\n validateScript(script);\n running.set(this.spec.name, this);\n this.startedAt = this.now();\n let stopped: AutomationRunResult[\"stopped\"] = \"completed\";\n let error: string | undefined;\n\n const maxDurationMs = (this.maxDurationMs = Math.max(\n 500,\n Math.min(\n MAX_AUTOMATION_DURATION_MS,\n this.opts.maxDurationMs ?? DEFAULT_AUTOMATION_DURATION_MS\n )\n ));\n this.durationTimer = setTimeout(() => {\n if (!this.ctl.stopped) {\n this.stopReason = \"duration\";\n this.ctl.stopped = true;\n this.emit({ stopped: \"duration\", maxDurationMs });\n }\n }, maxDurationMs);\n if (this.durationTimer.unref) this.durationTimer.unref();\n\n const sdk = this.buildSDK();\n const fn = new AsyncFunction(\"sdk\", script);\n try {\n await fn(sdk);\n // Script returned. The reason is whatever set ctl.stopped (duration/\n // manual), or a clean completion if nothing forced a stop.\n stopped = this.stopReason ?? \"completed\";\n } catch (e: any) {\n if (this.ctl.stopped && this.stopReason) {\n stopped = this.stopReason;\n } else {\n stopped = \"error\";\n error = e?.message || String(e);\n this.emit({ error });\n }\n } finally {\n this.ctl.stopped = true;\n if (this.gateTimer) clearInterval(this.gateTimer);\n if (this.durationTimer) clearTimeout(this.durationTimer);\n if (this.pauseStartedAt) {\n this.pausedAccumMs += this.now() - this.pauseStartedAt;\n this.pauseStartedAt = 0;\n }\n running.delete(this.spec.name);\n }\n\n return {\n name: this.spec.name,\n elapsedMs: this.elapsed(),\n stopped,\n error,\n actions: this.actions,\n actionCount: this.actions.length,\n logs: this.logs,\n pausedMs: this.pausedAccumMs,\n dryRun: !!this.opts.dryRun,\n requiredWindow: this.everGatedWindow ? this.ctl.requiredWindow : undefined,\n ranWithoutWindowGate:\n !this.opts.dryRun &&\n !this.everGatedWindow &&\n this.actions.some((a) => !a.suppressed),\n };\n }\n}\n",
4
- "agentStatement": "The auto-correction badly scrambled these two functions. Let me rewrite lines 248-282 cleanly. Let me view starting at loadAutomationSafe definition.",
5
- "patch": "@@ -173,10 +173,74 @@ export function listRunning(): string[] {\n /** Persisted automation storage (git-trackable). */\n export function automationPath(name: string): string {\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n return path.join(STORE_DIR, `${safe}.ts`);\n }\n \n+/**\n+ * Extract the structured \"skill card\" from an automation script. We look for a\n+ * leading block comment (before any executable code) and read JSDoc-style tags:\n+ * @description one-liner of what it does\n+ * @useWhen the situation/trigger that should make an agent pick this\n+ * @startState what the screen must look like BEFORE running\n+ * @endState what the screen will look like AFTER it finishes\n+ * @window the required window (title/app) it operates on\n+ * @notes anything else worth knowing (limits, caveats)\n+ * Tag text may wrap onto continuation lines. Returns undefined when no\n+ * recognizable header is present.\n+ */\n+export function parseAutomationDoc(script: string): AutomationDoc | undefined {\n+ const block = script.match(/^\\s*\\/\\*\\*?([\\s\\S]*?)\\*\\//);\n+ if (!block) return undefined;\n+ // Strip leading \" * \" decoration from each comment line.\n+ const body = block[1]\n+ .split(\"\\n\")\n+ .map((l) => l.replace(/^\\s*\\*?\\s?/, \"\"))\n+ .join(\"\\n\");\n+\n+ const tags: Record<string, string> = {};\n+ let current: string | null = null;\n+ const known = new Set([\n+ \"description\",\n+ \"usewhen\",\n+ \"startstate\",\n+ \"endstate\",\n+ \"window\",\n+ \"notes\",\n+ ]);\n+ for (const rawLine of body.split(\"\\n\")) {\n+ const line = rawLine.trimEnd();\n+ const m = line.match(/^@(\\w+)\\s*(.*)$/);\n+ if (m && known.has(m[1].toLowerCase())) {\n+ current = m[1].toLowerCase();\n+ tags[current] = m[2].trim();\n+ } else if (current && line.trim()) {\n+ tags[current] = (tags[current] + \" \" + line.trim()).trim();\n+ }\n+ }\n+ if (!Object.keys(tags).length) return undefined;\n+ const doc: AutomationDoc = {\n+ description: tags[\"description\"],\n+ useWhen: tags[\"usewhen\"],\n+ startState: tags[\"startstate\"],\n+ endState: tags[\"endstate\"],\n+ window: tags[\"window\"],\n+ notes: tags[\"notes\"],\n+ };\n+ // Drop empty keys for a tidy summary.\n+ for (const k of Object.keys(doc) as (keyof AutomationDoc)[]) {\n+ if (!doc[k]) delete doc[k];\n+ }\n+ return Object.keys(doc).length ? doc : undefined;\n+}\n+\n export function saveAutomation(spec: AutomationSpec): AutomationSpec {\n fs.mkdirSync(STORE_DIR, { recursive: true });\n fs.writeFileSync(automationPath(spec.name), spec.script);\n- return spec;\n+ return { ...spec, doc: parseAutomationDoc(spec.script), filePath: automationPath(spec.name) };\n }\n \n@@ -191,14 +255,20 @@ export function loadAutomation(name: string): AutomationSpec {\n export function loadAutomationSafe(name: string): AutomationSpec | undefined {\n try {\n const p = automationPath(name);\n if (fs.existsSync(p)) {\n- return { name, script: fs.readFileSync(p, \"utf8\") };\n+ const script = fs.readFileSync(p, \"utf8\");\n+ return { name, script, doc: parseAutomationDoc(script), filePath: p };\n }\n // Read old files during migration, but all new writes use plain .ts files.\n const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n const legacy = path.join(STORE_DIR, `${safe}.automation.json`);\n if (!fs.existsSync(legacy)) return undefined;\n const parsed = JSON.parse(fs.readFileSync(legacy, \"utf8\"));\n- return { name, script: parsed.script };\n+ return {\n+ name,\n+ script: parsed.script,\n+ doc: parseAutomationDoc(parsed.script || \"\"),\n+ filePath: legacy,\n+ };\n } catch {\n return undefined;\n }\n }\n",
6
- "observedAfter": "250: const p = automationPath(name);\n251: if (fs.existsSync(p)) {\n252: return { name, script: fs.readFileSync(p, \"utf8\") };\n253: }\n254: // Read old files during migration, but all new writes use plain .ts files.\n255: const safe = name.replace(/[^a-zA-Z0-9_-]/g, \"_\");\n256: const legacy = path.join(STORE_DIR, `${safe}.automation.json`);\n257: if (!fs.existsSync(legacy)) return undefined;\n258: const parsed = JSON.parse(fs.readFileSync(legacy, \"utf8\"));\n259: const script = fs.readFileSync(p, \"utf8\");\n260: return { name, script, doc: parseAutomationDoc(script), filePath: p };\n261: } catch {\n262: return undefined;\n263: }\n264: }\n265: \n266: export function listAutomations(): AutomationSpec[] {\n267: return {\n268: name,\n269: script: parsed.script,\n270: doc: parseAutomationDoc(parsed.script || \"\"),\n271: filePath: legacy,\n272: };\n273: if (!fs.existsSync(STORE_DIR)) return [];\n274: return fs\n275: .readdirSync(STORE_DIR)\n276: .filter((f) => f.endsWith(\".ts\"))\n277: .map((f) => loadAutomationSafe(f.slice(0, -3)) || null)\n278: .filter((x): x is AutomationSpec => !!x);\n279: } catch {\n280: return [];\n281: }\n282: }\n283: \n284: export function deleteAutomation(name: string): boolean {\n285: const p = automationPath(name);\n286: let deleted = false;\n287: if (fs.existsSync(p)) {\n288: fs.unlinkSync(p);\n289: deleted = true;\n290: }",
7
- "sourceRevision": "30cdb6d",
8
- "sourcePath": "packages/knowhow-module-computer-use/src/automation.ts"
9
- }
@@ -1,8 +0,0 @@
1
- {
2
- "taskId": "1785784065-can-you-fix-then-think-you-fix-the-confirmed",
3
- "sourceBefore": "/**\n * @description Plays Fruit Ninja with one short predictive slash per stream-tracked fruit instead of chasing stale screenshot detections.\n * @window Fruit Ninja Benchmark — Google Chrome\n * @useWhen Chrome is showing Fruit Ninja and a human-like, visually precise alternative to fruitNinjaFull is desired.\n * @startState The Fruit Ninja tab is focused at the start screen, during a round, or on the completed results screen.\n * @endState The Game Over results remain visible. Play Again is never clicked.\n * @notes Uses sdk.trackObjects over a persistent 60 FPS stream. Stable track IDs guarantee at most one slash per tracked fruit; rising fruit are intercepted near their predicted apex and uncertain/descending fruit use a short latency-compensated intercept. Each slash is limited to roughly one fruit diameter.\n */\nimport { sdk } from '@tyvm/knowhow-module-computer-use';\n\nconst requiredWindow = { app: 'Google Chrome', titleIncludes: 'Fruit Ninja Benchmark' };\nconst slashedTrackIds = new Set();\nlet slashCount = 0;\nlet sawFruit = false;\nlet lastFruitAt = sdk.elapsed();\nlet lastLifecycleAt = -10000;\nlet tracker;\n\nasync function lifecyclePhase() {\n const elements = await sdk.accessibilityElements({ interactiveOnly: true });\n const button = elements.find((element) => {\n const text = `${element.title || ''} ${element.value || ''}`;\n return element.role === 'AXButton' && /Start Game|Play Again/i.test(text);\n });\n if (!button) return { phase: 'playing' };\n const text = `${button.title || ''} ${button.value || ''}`;\n return /Play Again/i.test(text) ? { phase: 'end' } : { phase: 'start', button };\n}\n\nasync function handleLifecycle() {\n lastLifecycleAt = sdk.elapsed();\n const lifecycle = await lifecyclePhase();\n if (lifecycle.phase === 'end') {\n sdk.log({ phase: 'end', slashCount, action: 'stop-with-results-visible' });\n sdk.ctl.stop();\n return false;\n }\n if (lifecycle.phase === 'start' && lifecycle.button?.bounds) {\n const bounds = lifecycle.button.bounds;\n await sdk.clickAt(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);\n sdk.log({ phase: 'start', action: 'click-start-game' });\n await sdk.sleep(150);\n }\n lastFruitAt = sdk.elapsed();\n return true;\n}\n\nasync function resolveArena(windowBounds) {\n const elements = await sdk.accessibilityElements({ interactiveOnly: false });\n const canvases = elements\n .filter((element) => element.role === 'AXCanvas' && element.bounds)\n .sort((a, b) => (b.bounds.width * b.bounds.height) - (a.bounds.width * a.bounds.height));\n if (canvases[0]) return canvases[0].bounds;\n\n const webAreas = elements\n .filter((element) => element.role === 'AXWebArea' && element.bounds)\n .sort((a, b) => (b.bounds.width * b.bounds.height) - (a.bounds.width * a.bounds.height));\n const page = webAreas[0]?.bounds || windowBounds;\n return {\n x: page.x,\n y: page.y + page.height * 0.06,\n width: page.width,\n height: page.height * 0.94,\n };\n}\n\nlet active = await sdk.activeWindow();\nwhile (!sdk.ctl.stopped && (active?.app !== requiredWindow.app\n || !active?.title?.includes(requiredWindow.titleIncludes))) {\n await sdk.sleep(50);\n active = await sdk.activeWindow();\n}\nif (!active?.bounds) throw new Error('The focused Fruit Ninja window has no usable bounds.');\n\nif (await handleLifecycle()) {\n const arena = await resolveArena(active.bounds);\n const expectedDiameter = arena.width * (70 / 1200);\n tracker = await sdk.trackObjects({\n region: arena,\n scale: 0.25,\n fps: 60,\n framesToKeep: 3,\n mode: 'foreground',\n minSize: Math.max(24, expectedDiameter * 0.55),\n maxSize: expectedDiameter * 1.45,\n minPixels: Math.max(250, expectedDiameter * expectedDiameter * 0.08),\n clusterGap: 4,\n dilate: 0,\n maxBoxes: 40,\n maxAssociationDistance: expectedDiameter * 2.2,\n historySize: 12,\n maxMissedFrames: 4,\n smoothing: 0.4,\n filter: (blob) => {\n const { width, height } = blob.bounds;\n const aspect = width / height;\n return aspect >= 0.72 && aspect <= 1.28\n && width >= expectedDiameter * 0.58 && width <= expectedDiameter * 1.45\n && height >= expectedDiameter * 0.58 && height <= expectedDiameter * 1.45;\n },\n });\n sdk.log({ phase: 'ready', perception: 'stream-tracker', arena, expectedDiameter,\n scale: 0.25, requestedFps: 60 });\n\n async function tick() {\n const observation = await tracker.nextFrame(250);\n const now = sdk.elapsed();\n if (!observation) {\n if (sawFruit && now - lastFruitAt > 4500 && now - lastLifecycleAt > 4500) {\n await handleLifecycle();\n }\n return;\n }\n const fruits = observation.objects.filter((object) => object.missedFrames === 0);\n if (fruits.length) {\n sawFruit = true;\n lastFruitAt = now;\n }\n\n for (const fruit of fruits) {\n if (slashedTrackIds.has(fruit.id) || fruit.ageFrames < 4) continue;\n\n // Wait for a trustworthy ballistic apex while the fruit is rising. If\n // acceleration has not stabilized after several frames, do not risk\n // waiting too long: intercept its latency-compensated future position.\n const speed = Math.hypot(fruit.velocity.x, fruit.velocity.y);\n const apexIsPlausible = fruit.apex\n && speed >= 120\n && fruit.velocity.y < -50\n && fruit.acceleration.y >= 300\n && fruit.acceleration.y <= 4000\n && fruit.apex.timeUntilMs > 0\n && fruit.apex.timeUntilMs < 1600\n && fruit.apex.point.x >= arena.x\n && fruit.apex.point.x <= arena.x + arena.width\n && fruit.apex.point.y >= arena.y\n && fruit.apex.point.y <= arena.y + arena.height;\n\n let target;\n let strategy;\n if (apexIsPlausible) {\n if (fruit.apex.timeUntilMs > 70) continue;\n target = fruit.apex.point;\n strategy = 'predicted-apex';\n } else if (speed >= 120 && (fruit.velocity.y >= -30 || fruit.ageFrames >= 10)) {\n target = fruit.predict(45);\n strategy = '45ms-intercept';\n } else {\n continue;\n }\n\n target = {\n x: Math.max(arena.x, Math.min(arena.x + arena.width, target.x)),\n y: Math.max(arena.y, Math.min(arena.y + arena.height, target.y)),\n };\n const radius = Math.max(fruit.bounds.width, fruit.bounds.height) / 2;\n const halfSlash = Math.min(expectedDiameter * 0.72, radius * 0.85);\n const x1 = Math.max(arena.x, target.x - halfSlash);\n const y1 = Math.min(arena.y + arena.height, target.y + halfSlash * 0.35);\n const x2 = Math.min(arena.x + arena.width, target.x + halfSlash);\n const y2 = Math.max(arena.y, target.y - halfSlash * 0.35);\n\n // Retire the stable object ID before awaiting input so no later frame can\n // schedule a second slash for the same moving fruit.\n slashedTrackIds.add(fruit.id);\n sdk.log({ phase: 'playing', trackId: fruit.id, strategy,\n ageFrames: fruit.ageFrames, confidence: +fruit.confidence.toFixed(2),\n observed: fruit.center, target,\n velocity: fruit.velocity, acceleration: fruit.acceleration,\n apexInMs: fruit.apex ? Math.round(fruit.apex.timeUntilMs) : null,\n detectionMs: observation.detectionMs, slash: { x1, y1, x2, y2 } });\n await sdk.dragMouse(x1, y1, x2, y2, { duration: 28 });\n slashCount++;\n }\n\n if (sawFruit && now - lastFruitAt > 4500 && now - lastLifecycleAt > 4500) {\n await handleLifecycle();\n }\n }\n\n await sdk.runEvery(tick, 20, { requiredWindow });\n}\n",
4
- "patch": "--- .knowhow/automations/fruitNinjaPrecision.ts\n+++ .knowhow/automations/fruitNinjaPrecision.ts\n@@ -3,14 +3,17 @@\n * @useWhen Chrome is showing Fruit Ninja and a human-like, visually precise alternative to fruitNinjaFull is desired.\n * @startState The Fruit Ninja tab is focused at the start screen, during a round, or on the completed results screen.\n * @endState The Game Over results remain visible. Play Again is never clicked.\n- * @notes Uses sdk.trackObjects over a persistent 60 FPS stream. Stable track IDs guarantee at most one slash per tracked fruit; rising fruit are intercepted near their predicted apex and uncertain/descending fruit use a short latency-compensated intercept. Each slash is limited to roughly one fruit diameter.\n+ * @notes Uses sdk.trackObjects over a persistent 60 FPS stream. A slash is confirmed when its stable track disappears; a still-visible track receives at most one corrective slash. Rising fruit are intercepted near their predicted apex and uncertain/descending fruit use a short latency-compensated intercept. Each slash is limited to roughly one fruit diameter.\n */\n import { sdk } from '@tyvm/knowhow-module-computer-use';\n \n const requiredWindow = { app: 'Google Chrome', titleIncludes: 'Fruit Ninja Benchmark' };\n-const slashedTrackIds = new Set();\n+const slashStates = new Map();\n+const FOLLOW_UP_DELAY_MS = 130;\n+const FOLLOW_UP_FRAMES = 3;\n+const CONFIRM_MISSED_FRAMES = 2;\n let slashCount = 0;\n let sawFruit = false;\n let lastFruitAt = sdk.elapsed();\n@@ -104,13 +107,35 @@\n }\n return;\n }\n+ for (const fruit of observation.objects) {\n+ const slashState = slashStates.get(fruit.id);\n+ if (slashState && !slashState.confirmed\n+ && fruit.missedFrames >= CONFIRM_MISSED_FRAMES) {\n+ slashState.confirmed = true;\n+ sdk.log({ phase: 'playing', trackId: fruit.id, action: 'slash-confirmed',\n+ attempts: slashState.attempts, missedFrames: fruit.missedFrames });\n+ }\n+ }\n const fruits = observation.objects.filter((object) => object.missedFrames === 0);\n if (fruits.length) {\n sawFruit = true;\n lastFruitAt = now;\n }\n \n for (const fruit of fruits) {\n- if (slashedTrackIds.has(fruit.id) || fruit.ageFrames < 4) continue;\n+ const slashState = slashStates.get(fruit.id);\n+ if (slashState?.confirmed || slashState?.attempts >= 2 || fruit.ageFrames < 4) continue;\n+\n+ const isFollowUp = slashState?.attempts === 1;\n+ if (isFollowUp && (now - slashState.lastAttemptAt < FOLLOW_UP_DELAY_MS\n+ || observation.frame.sequence - slashState.lastAttemptSequence < FOLLOW_UP_FRAMES)) {\n+ continue;\n+ }\n \n // Wait for a trustworthy ballistic apex while the fruit is rising. If\n // acceleration has not stabilized after several frames, do not risk\n@@ -131,7 +156,11 @@\n \n let target;\n let strategy;\n- if (apexIsPlausible) {\n+ if (isFollowUp) {\n+ target = fruit.predict(45);\n+ strategy = 'corrective-45ms-intercept';\n+ } else if (apexIsPlausible) {\n if (fruit.apex.timeUntilMs > 70) continue;\n target = fruit.apex.point;\n strategy = 'predicted-apex';\n@@ -153,10 +182,14 @@\n const x2 = Math.min(arena.x + arena.width, target.x + halfSlash);\n const y2 = Math.max(arena.y, target.y - halfSlash * 0.35);\n \n- // Retire the stable object ID before awaiting input so no later frame can\n- // schedule a second slash for the same moving fruit.\n- slashedTrackIds.add(fruit.id);\n+ // Record the attempt before awaiting input, but only retire the track\n+ // after it disappears. A fruit that remains visible gets one correction.\n+ const nextSlashState = slashState || { attempts: 0, confirmed: false };\n+ nextSlashState.attempts++;\n+ nextSlashState.lastAttemptAt = sdk.elapsed();\n+ nextSlashState.lastAttemptSequence = observation.frame.sequence;\n+ slashStates.set(fruit.id, nextSlashState);\n sdk.log({ phase: 'playing', trackId: fruit.id, strategy,\n+ attempt: nextSlashState.attempts,\n ageFrames: fruit.ageFrames, confidence: +fruit.confidence.toFixed(2),\n observed: fruit.center, target,\n velocity: fruit.velocity, acceleration: fruit.acceleration,\n",
5
- "expectedAfter": "/**\n * @description Plays Fruit Ninja with one short predictive slash per stream-tracked fruit instead of chasing stale screenshot detections.\n * @window Fruit Ninja Benchmark — Google Chrome\n * @useWhen Chrome is showing Fruit Ninja and a human-like, visually precise alternative to fruitNinjaFull is desired.\n * @startState The Fruit Ninja tab is focused at the start screen, during a round, or on the completed results screen.\n * @endState The Game Over results remain visible. Play Again is never clicked.\n * @notes Uses sdk.trackObjects over a persistent 60 FPS stream. A slash is confirmed when its stable track disappears; a still-visible track receives at most one corrective slash. Rising fruit are intercepted near their predicted apex and uncertain/descending fruit use a short latency-compensated intercept. Each slash is limited to roughly one fruit diameter.\n */\nimport { sdk } from '@tyvm/knowhow-module-computer-use';\n\nconst requiredWindow = { app: 'Google Chrome', titleIncludes: 'Fruit Ninja Benchmark' };\nconst slashStates = new Map();\nconst FOLLOW_UP_DELAY_MS = 130;\nconst FOLLOW_UP_FRAMES = 3;\nconst CONFIRM_MISSED_FRAMES = 2;\nlet slashCount = 0;\nlet sawFruit = false;\nlet lastFruitAt = sdk.elapsed();\nlet lastLifecycleAt = -10000;\nlet tracker;\n\nasync function lifecyclePhase() {\n const elements = await sdk.accessibilityElements({ interactiveOnly: true });\n const button = elements.find((element) => {\n const text = `${element.title || ''} ${element.value || ''}`;\n return element.role === 'AXButton' && /Start Game|Play Again/i.test(text);\n });\n if (!button) return { phase: 'playing' };\n const text = `${button.title || ''} ${button.value || ''}`;\n return /Play Again/i.test(text) ? { phase: 'end' } : { phase: 'start', button };\n}\n\nasync function handleLifecycle() {\n lastLifecycleAt = sdk.elapsed();\n const lifecycle = await lifecyclePhase();\n if (lifecycle.phase === 'end') {\n sdk.log({ phase: 'end', slashCount, action: 'stop-with-results-visible' });\n sdk.ctl.stop();\n return false;\n }\n if (lifecycle.phase === 'start' && lifecycle.button?.bounds) {\n const bounds = lifecycle.button.bounds;\n await sdk.clickAt(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);\n sdk.log({ phase: 'start', action: 'click-start-game' });\n await sdk.sleep(150);\n }\n lastFruitAt = sdk.elapsed();\n return true;\n}\n\nasync function resolveArena(windowBounds) {\n const elements = await sdk.accessibilityElements({ interactiveOnly: false });\n const canvases = elements\n .filter((element) => element.role === 'AXCanvas' && element.bounds)\n .sort((a, b) => (b.bounds.width * b.bounds.height) - (a.bounds.width * a.bounds.height));\n if (canvases[0]) return canvases[0].bounds;\n\n const webAreas = elements\n .filter((element) => element.role === 'AXWebArea' && element.bounds)\n .sort((a, b) => (b.bounds.width * b.bounds.height) - (a.bounds.width * a.bounds.height));\n const page = webAreas[0]?.bounds || windowBounds;\n return {\n x: page.x,\n y: page.y + page.height * 0.06,\n width: page.width,\n height: page.height * 0.94,\n };\n}\n\nlet active = await sdk.activeWindow();\nwhile (!sdk.ctl.stopped && (active?.app !== requiredWindow.app\n || !active?.title?.includes(requiredWindow.titleIncludes))) {\n await sdk.sleep(50);\n active = await sdk.activeWindow();\n}\nif (!active?.bounds) throw new Error('The focused Fruit Ninja window has no usable bounds.');\n\nif (await handleLifecycle()) {\n const arena = await resolveArena(active.bounds);\n const expectedDiameter = arena.width * (70 / 1200);\n tracker = await sdk.trackObjects({\n region: arena,\n scale: 0.25,\n fps: 60,\n framesToKeep: 3,\n mode: 'foreground',\n minSize: Math.max(24, expectedDiameter * 0.55),\n maxSize: expectedDiameter * 1.45,\n minPixels: Math.max(250, expectedDiameter * expectedDiameter * 0.08),\n clusterGap: 4,\n dilate: 0,\n maxBoxes: 40,\n maxAssociationDistance: expectedDiameter * 2.2,\n historySize: 12,\n maxMissedFrames: 4,\n smoothing: 0.4,\n filter: (blob) => {\n const { width, height } = blob.bounds;\n const aspect = width / height;\n return aspect >= 0.72 && aspect <= 1.28\n && width >= expectedDiameter * 0.58 && width <= expectedDiameter * 1.45\n && height >= expectedDiameter * 0.58 && height <= expectedDiameter * 1.45;\n },\n });\n sdk.log({ phase: 'ready', perception: 'stream-tracker', arena, expectedDiameter,\n scale: 0.25, requestedFps: 60 });\n\n async function tick() {\n const observation = await tracker.nextFrame(250);\n const now = sdk.elapsed();\n if (!observation) {\n if (sawFruit && now - lastFruitAt > 4500 && now - lastLifecycleAt > 4500) {\n await handleLifecycle();\n }\n return;\n }\n for (const fruit of observation.objects) {\n const slashState = slashStates.get(fruit.id);\n if (slashState && !slashState.confirmed\n && fruit.missedFrames >= CONFIRM_MISSED_FRAMES) {\n slashState.confirmed = true;\n sdk.log({ phase: 'playing', trackId: fruit.id, action: 'slash-confirmed',\n attempts: slashState.attempts, missedFrames: fruit.missedFrames });\n }\n }\n const fruits = observation.objects.filter((object) => object.missedFrames === 0);\n if (fruits.length) {\n sawFruit = true;\n lastFruitAt = now;\n }\n\n for (const fruit of fruits) {\n const slashState = slashStates.get(fruit.id);\n if (slashState?.confirmed || slashState?.attempts >= 2 || fruit.ageFrames < 4) continue;\n\n const isFollowUp = slashState?.attempts === 1;\n if (isFollowUp && (now - slashState.lastAttemptAt < FOLLOW_UP_DELAY_MS\n || observation.frame.sequence - slashState.lastAttemptSequence < FOLLOW_UP_FRAMES)) {\n continue;\n }\n\n // Wait for a trustworthy ballistic apex while the fruit is rising. If\n // acceleration has not stabilized after several frames, do not risk\n // waiting too long: intercept its latency-compensated future position.\n const speed = Math.hypot(fruit.velocity.x, fruit.velocity.y);\n const apexIsPlausible = fruit.apex\n && speed >= 120\n && fruit.velocity.y < -50\n && fruit.acceleration.y >= 300\n && fruit.acceleration.y <= 4000\n && fruit.apex.timeUntilMs > 0\n && fruit.apex.timeUntilMs < 1600\n && fruit.apex.point.x >= arena.x\n && fruit.apex.point.x <= arena.x + arena.width\n && fruit.apex.point.y >= arena.y\n && fruit.apex.point.y <= arena.y + arena.height;\n\n let target;\n let strategy;\n if (isFollowUp) {\n target = fruit.predict(45);\n strategy = 'corrective-45ms-intercept';\n } else if (apexIsPlausible) {\n if (fruit.apex.timeUntilMs > 70) continue;\n target = fruit.apex.point;\n strategy = 'predicted-apex';\n } else if (speed >= 120 && (fruit.velocity.y >= -30 || fruit.ageFrames >= 10)) {\n target = fruit.predict(45);\n strategy = '45ms-intercept';\n } else {\n continue;\n }\n\n target = {\n x: Math.max(arena.x, Math.min(arena.x + arena.width, target.x)),\n y: Math.max(arena.y, Math.min(arena.y + arena.height, target.y)),\n };\n const radius = Math.max(fruit.bounds.width, fruit.bounds.height) / 2;\n const halfSlash = Math.min(expectedDiameter * 0.72, radius * 0.85);\n const x1 = Math.max(arena.x, target.x - halfSlash);\n const y1 = Math.min(arena.y + arena.height, target.y + halfSlash * 0.35);\n const x2 = Math.min(arena.x + arena.width, target.x + halfSlash);\n const y2 = Math.max(arena.y, target.y - halfSlash * 0.35);\n\n // Record the attempt before awaiting input, but only retire the track\n // after it disappears. A fruit that remains visible gets one correction.\n const nextSlashState = slashState || { attempts: 0, confirmed: false };\n nextSlashState.attempts++;\n nextSlashState.lastAttemptAt = sdk.elapsed();\n nextSlashState.lastAttemptSequence = observation.frame.sequence;\n slashStates.set(fruit.id, nextSlashState);\n sdk.log({ phase: 'playing', trackId: fruit.id, strategy,\n attempt: nextSlashState.attempts,\n ageFrames: fruit.ageFrames, confidence: +fruit.confidence.toFixed(2),\n observed: fruit.center, target,\n velocity: fruit.velocity, acceleration: fruit.acceleration,\n apexInMs: fruit.apex ? Math.round(fruit.apex.timeUntilMs) : null,\n detectionMs: observation.detectionMs, slash: { x1, y1, x2, y2 } });\n await sdk.dragMouse(x1, y1, x2, y2, { duration: 28 });\n slashCount++;\n }\n\n if (sawFruit && now - lastFruitAt > 4500 && now - lastLifecycleAt > 4500) {\n await handleLifecycle();\n }\n }\n\n await sdk.runEvery(tick, 20, { requiredWindow });\n}\n",
6
- "observedAfter": "",
7
- "agentStatement": "The patch tool reported a clean application, but crossed the targeting and slash-state blocks and produced invalid TypeScript."
8
- }
@@ -1,11 +0,0 @@
1
- @@ -5,7 +6,7 @@
2
- import React from 'react';
3
- import { Col, Row } from 'react-bootstrap';
4
-
5
- -import { NameValueRow, NameValueRowWithBottomBorder } from '~/components/NameValueRow';
6
- +import { NameValueRow } from '~/components/NameValueRow';
7
- import { BOTTOM_BORDER_CONTAINER_STYLE } from '~/components/NameValueRow/NameValueRowWithBottomBorder';
8
- import { NotesPopoverWrapper } from '~/components/Notes';
9
- import { TokenAgreementRowAssetUnion, UpdateTokenAgreement, UpdateTokenAgreementVariables } from '~/generated/schema';
10
-
11
-
@@ -1,43 +0,0 @@
1
- import * as fs from "fs";
2
- import { parseHunks, fixPatch } from "../../src/agents/tools/patch";
3
- import { applyPatch } from "diff";
4
-
5
- describe("fixPatch", () => {
6
- it("should fix patch", async () => {
7
- const patch = fs.readFileSync(__dirname + "/imports.patch.txt").toString();
8
- const originalContent = fs
9
- .readFileSync(__dirname + "/imports.txt")
10
- .toString();
11
- const hunks = parseHunks(patch);
12
-
13
- console.log(hunks);
14
- expect(hunks.length).toBe(1);
15
-
16
- expect(hunks[0].newStartLine).toBe(6);
17
- expect(hunks[0].originalStartLine).toBe(5);
18
-
19
- const fixedPatch = await fixPatch(originalContent, patch);
20
- console.log(fixedPatch);
21
-
22
- const patched = applyPatch(originalContent, fixedPatch);
23
- console.log("PATCH OUTPUT");
24
- console.log(patched);
25
- });
26
-
27
- it("should patch interface.text", async () => {
28
- const patch = fs
29
- .readFileSync(__dirname + "/interface.patch.txt")
30
- .toString();
31
- const originalContent = fs
32
- .readFileSync(__dirname + "/interface.txt")
33
- .toString();
34
-
35
- const hunks = parseHunks(patch);
36
- const fixedPatch = await fixPatch(originalContent, patch);
37
- console.log(fixedPatch);
38
-
39
- const patched = applyPatch(originalContent, fixedPatch);
40
- console.log("PATCH OUTPUT");
41
- console.log(patched);
42
- });
43
- });
@@ -1,11 +0,0 @@
1
- import { gql, useMutation } from '@apollo/client';
2
- import React from 'react';
3
- import { Col, Row } from 'react-bootstrap';
4
-
5
- import InformationTooltip from '~/components/InformationTooltip';
6
- import Link from '~/components/Link';
7
- import { NameValueRow, NameValueRowWithBottomBorder } from '~/components/NameValueRow';
8
- import { BOTTOM_BORDER_CONTAINER_STYLE } from '~/components/NameValueRow/NameValueRowWithBottomBorder';
9
- import { NotesPopoverWrapper } from '~/components/Notes';
10
- import { TokenAgreementRowAssetUnion, UpdateTokenAgreement, UpdateTokenAgreementVariables } from '~/generated/schema';
11
-
@@ -1,15 +0,0 @@
1
- --- ./tests/patching/interface.txt
2
- +++ ./tests/patching/interface.txt
3
- @@ -3,8 +3,14 @@
4
- import { Message } from "../clients/types";
5
-
6
- export interface IAgent {
7
- + getModel(): string;
8
- + setModel(value: string): void;
9
- + getProvider(): string;
10
- + setProvider(value: string): void;
11
- name: string;
12
- description: string;
13
- - call: (userInput: string, messages?: Message[]) => Promise<string>;
14
- + call: (userInput: string, messages?: Message[]) => Promise<string>;
15
- }
@@ -1,7 +0,0 @@
1
- import { Message } from "../clients/types";
2
-
3
- export interface IAgent {
4
- name: string;
5
- description: string;
6
- call: (userInput: string, messages?: Message[]) => Promise<string>;
7
- }