@tyvm/knowhow 0.0.159 → 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.
- package/package.json +1 -1
- package/ts_build/package.json +1 -1
- package/ts_build/src/chat/CliChatService.d.ts +2 -1
- package/ts_build/src/chat/CliChatService.js +29 -3
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.js +21 -17
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/renderer/ConsoleRenderer.js +32 -25
- package/ts_build/src/chat/renderer/ConsoleRenderer.js.map +1 -1
- package/ts_build/src/logger.d.ts +1 -0
- package/ts_build/src/logger.js +13 -1
- package/ts_build/src/logger.js.map +1 -1
- package/ts_build/src/utils/InputQueueManager.d.ts +8 -1
- package/ts_build/src/utils/InputQueueManager.js +72 -2
- package/ts_build/src/utils/InputQueueManager.js.map +1 -1
- package/ts_build/src/utils/index.d.ts +3 -1
- package/ts_build/src/utils/index.js +11 -3
- package/ts_build/src/utils/index.js.map +1 -1
- package/CONFIG.md +0 -429
- package/PROCESSING.md +0 -450
- package/WORKER.md +0 -260
- package/autodoc/README.md +0 -324
- package/autodoc/chat-guide.md +0 -444
- package/autodoc/cli-reference.md +0 -720
- package/autodoc/config-reference.md +0 -642
- package/autodoc/embeddings-guide.md +0 -467
- package/autodoc/generate-guide.md +0 -437
- package/autodoc/language-plugin-guide.md +0 -417
- package/autodoc/modules-guide.md +0 -379
- package/autodoc/plugins-guide.md +0 -721
- package/autodoc/quickstart-guide.md +0 -126
- package/autodoc/skills-guide.md +0 -584
- package/autodoc/worker-guide.md +0 -519
- package/docs/input-queue-manager.md +0 -142
- package/docs/multi-worker-management.md +0 -142
- package/docs/shell-commands.md +0 -174
- package/jest.config.js +0 -19
- package/jest.manual.config.js +0 -19
- package/scripts/README.md +0 -119
- package/scripts/build-for-node.sh +0 -148
- package/scripts/cache-miss-debug.ts +0 -365
- package/scripts/check-isolated-deps.sh +0 -69
- package/scripts/check-model-pricing.ts +0 -509
- package/scripts/compare-openrouter-coverage.ts +0 -576
- package/scripts/migrate-usage-json.js +0 -147
- package/scripts/publish.sh +0 -86
- package/scripts/restore_keys.sh +0 -59
- package/scripts/test-repetition-hint.ts +0 -302
- package/scripts/unset_keys.sh +0 -60
- package/src/agents/base/base.ts +0 -1963
- package/src/agents/base/prompt.ts +0 -55
- package/src/agents/configurable/ConfigAgent.ts +0 -24
- package/src/agents/developer/developer.ts +0 -76
- package/src/agents/historyRollback.ts +0 -36
- package/src/agents/index.ts +0 -52
- package/src/agents/interface.ts +0 -11
- package/src/agents/patcher/codebase.md +0 -27
- package/src/agents/patcher/patcher.ts +0 -131
- package/src/agents/researcher/researcher.ts +0 -115
- package/src/agents/setup/setup.ts +0 -63
- package/src/agents/tools/addInternalTools.ts +0 -21
- package/src/agents/tools/agentCall.ts +0 -34
- package/src/agents/tools/aiClient.ts +0 -178
- package/src/agents/tools/askHuman.ts +0 -10
- package/src/agents/tools/callPlugin.ts +0 -10
- package/src/agents/tools/connectAgent.ts +0 -355
- package/src/agents/tools/embeddingSearch.ts +0 -6
- package/src/agents/tools/execCommand.ts +0 -162
- package/src/agents/tools/fileSearch.ts +0 -35
- package/src/agents/tools/finalAnswer.ts +0 -4
- package/src/agents/tools/googleSearch.ts +0 -243
- package/src/agents/tools/index.ts +0 -33
- package/src/agents/tools/language/definitions.ts +0 -105
- package/src/agents/tools/language/index.ts +0 -20
- package/src/agents/tools/lazy/definitions.ts +0 -72
- package/src/agents/tools/lazy/disableTools.ts +0 -16
- package/src/agents/tools/lazy/enableTools.ts +0 -16
- package/src/agents/tools/lazy/index.ts +0 -3
- package/src/agents/tools/lazy/listAvailableTools.ts +0 -17
- package/src/agents/tools/lintFile.ts +0 -19
- package/src/agents/tools/list.ts +0 -739
- package/src/agents/tools/loadImageAsBase64.ts +0 -83
- package/src/agents/tools/loadWebpage.ts +0 -19
- package/src/agents/tools/mcp/connectMcpServer.ts +0 -40
- package/src/agents/tools/mcp/definitions.ts +0 -67
- package/src/agents/tools/mcp/disconnectMcpServer.ts +0 -40
- package/src/agents/tools/mcp/index.ts +0 -3
- package/src/agents/tools/mcp/listAvailableMcpServers.ts +0 -28
- package/src/agents/tools/minimal/callTool.ts +0 -45
- package/src/agents/tools/minimal/definitions.ts +0 -50
- package/src/agents/tools/minimal/index.ts +0 -3
- package/src/agents/tools/minimal/inspectTools.ts +0 -27
- package/src/agents/tools/modifyFile.ts +0 -53
- package/src/agents/tools/observe.ts +0 -247
- package/src/agents/tools/patch.ts +0 -1287
- package/src/agents/tools/readBlocks.ts +0 -83
- package/src/agents/tools/readFile.ts +0 -105
- package/src/agents/tools/replyToParent.ts +0 -123
- package/src/agents/tools/runGenerate.ts +0 -210
- package/src/agents/tools/scanFile.ts +0 -16
- package/src/agents/tools/sendAgentMessage.ts +0 -139
- package/src/agents/tools/skills.ts +0 -79
- package/src/agents/tools/startAgentTask.ts +0 -393
- package/src/agents/tools/stringReplace.ts +0 -105
- package/src/agents/tools/textSearch.ts +0 -128
- package/src/agents/tools/types/fileblock.ts +0 -5
- package/src/agents/tools/visionTool.ts +0 -35
- package/src/agents/tools/waitForAgentCompleted.ts +0 -270
- package/src/agents/tools/writeFile.ts +0 -106
- package/src/agents/tools/ycmd/client.ts +0 -608
- package/src/agents/tools/ycmd/definitions.ts +0 -294
- package/src/agents/tools/ycmd/detection.ts +0 -211
- package/src/agents/tools/ycmd/index.ts +0 -11
- package/src/agents/tools/ycmd/installer.ts +0 -251
- package/src/agents/tools/ycmd/server.ts +0 -545
- package/src/agents/tools/ycmd/serverManager.ts +0 -316
- package/src/agents/tools/ycmd/tools/completion.ts +0 -113
- package/src/agents/tools/ycmd/tools/diagnostics.ts +0 -166
- package/src/agents/tools/ycmd/tools/getLocations.ts +0 -173
- package/src/agents/tools/ycmd/tools/goto.ts +0 -169
- package/src/agents/tools/ycmd/tools/refactor.ts +0 -204
- package/src/agents/tools/ycmd/tools/signature.ts +0 -174
- package/src/agents/tools/ycmd/tools/start.ts +0 -95
- package/src/agents/tools/ycmd/utils/pathUtils.ts +0 -59
- package/src/ai.ts +0 -306
- package/src/auth/browserLogin.ts +0 -406
- package/src/auth/environmentAuth.ts +0 -51
- package/src/auth/errors.ts +0 -6
- package/src/auth/jwtStore.ts +0 -70
- package/src/auth/keyAuth.ts +0 -142
- package/src/auth/keyManager.ts +0 -331
- package/src/auth/registerIdentity.ts +0 -67
- package/src/auth/spinner.ts +0 -23
- package/src/chat/CliChatService.ts +0 -438
- package/src/chat/modules/AgentModule.ts +0 -1664
- package/src/chat/modules/AskModule.ts +0 -98
- package/src/chat/modules/BaseChatModule.ts +0 -65
- package/src/chat/modules/ClipboardImageModule.ts +0 -136
- package/src/chat/modules/CustomCommandsModule.ts +0 -80
- package/src/chat/modules/InternalChatModule.ts +0 -216
- package/src/chat/modules/RemoteSyncModule.ts +0 -482
- package/src/chat/modules/RendererModule.ts +0 -139
- package/src/chat/modules/SearchModule.ts +0 -168
- package/src/chat/modules/SessionsModule.ts +0 -969
- package/src/chat/modules/SetupModule.ts +0 -185
- package/src/chat/modules/ShellCommandModule.ts +0 -98
- package/src/chat/modules/SystemModule.ts +0 -161
- package/src/chat/modules/ToolCommandModule.ts +0 -102
- package/src/chat/modules/VoiceModule.ts +0 -70
- package/src/chat/modules/index.ts +0 -8
- package/src/chat/renderer/CompactRenderer.ts +0 -229
- package/src/chat/renderer/ConsoleRenderer.ts +0 -160
- package/src/chat/renderer/FancyRenderer.ts +0 -440
- package/src/chat/renderer/PlainRenderer.ts +0 -218
- package/src/chat/renderer/index.ts +0 -6
- package/src/chat/renderer/loadRenderer.ts +0 -316
- package/src/chat/renderer/messagesToRenderEvents.ts +0 -96
- package/src/chat/renderer/types.ts +0 -99
- package/src/chat/types.ts +0 -146
- package/src/chat.ts +0 -140
- package/src/cli.ts +0 -180
- package/src/clients/anthropic.ts +0 -772
- package/src/clients/attribution.ts +0 -53
- package/src/clients/cerebras.ts +0 -10
- package/src/clients/contextLimits.ts +0 -263
- package/src/clients/copilot.ts +0 -23
- package/src/clients/deepseek.ts +0 -16
- package/src/clients/fireworks.ts +0 -71
- package/src/clients/gemini.ts +0 -1169
- package/src/clients/github.ts +0 -16
- package/src/clients/groq.ts +0 -15
- package/src/clients/http.ts +0 -719
- package/src/clients/index.ts +0 -1153
- package/src/clients/knowhow.ts +0 -130
- package/src/clients/knowhowMcp.ts +0 -118
- package/src/clients/llama.ts +0 -16
- package/src/clients/meta.ts +0 -27
- package/src/clients/mistral.ts +0 -16
- package/src/clients/nvidia.ts +0 -16
- package/src/clients/openai.ts +0 -1186
- package/src/clients/openrouter.ts +0 -24
- package/src/clients/pricing/anthropic.ts +0 -149
- package/src/clients/pricing/cerebras.ts +0 -11
- package/src/clients/pricing/copilot.ts +0 -60
- package/src/clients/pricing/deepseek.ts +0 -15
- package/src/clients/pricing/fireworks.ts +0 -182
- package/src/clients/pricing/github.ts +0 -69
- package/src/clients/pricing/google.ts +0 -385
- package/src/clients/pricing/groq.ts +0 -56
- package/src/clients/pricing/index.ts +0 -44
- package/src/clients/pricing/llama.ts +0 -18
- package/src/clients/pricing/meta.ts +0 -12
- package/src/clients/pricing/mistral.ts +0 -34
- package/src/clients/pricing/models.ts +0 -25
- package/src/clients/pricing/nvidia.ts +0 -102
- package/src/clients/pricing/openai.ts +0 -409
- package/src/clients/pricing/openrouter.ts +0 -36
- package/src/clients/pricing/qwen.ts +0 -80
- package/src/clients/pricing/types.ts +0 -125
- package/src/clients/pricing/xai.ts +0 -137
- package/src/clients/qwen.ts +0 -16
- package/src/clients/responseMetadata.ts +0 -221
- package/src/clients/types.ts +0 -531
- package/src/clients/withRetry.ts +0 -89
- package/src/clients/xai.ts +0 -693
- package/src/cloudWorker.ts +0 -394
- package/src/commands/agent.ts +0 -342
- package/src/commands/agents.ts +0 -1037
- package/src/commands/behaviors.ts +0 -47
- package/src/commands/convert.ts +0 -291
- package/src/commands/hash.ts +0 -179
- package/src/commands/mcp.ts +0 -743
- package/src/commands/misc.ts +0 -373
- package/src/commands/modules.ts +0 -704
- package/src/commands/processes.ts +0 -248
- package/src/commands/remote.ts +0 -77
- package/src/commands/replay.ts +0 -503
- package/src/commands/sandbox.ts +0 -566
- package/src/commands/services.ts +0 -168
- package/src/commands/skills.ts +0 -107
- package/src/commands/workers.ts +0 -168
- package/src/config.ts +0 -468
- package/src/conversion.ts +0 -69
- package/src/dataset/diffs/README.md +0 -12
- package/src/dataset/diffs/debug-errors.ts +0 -29
- package/src/dataset/diffs/debug.ts +0 -64
- package/src/dataset/diffs/generate.ts +0 -71
- package/src/dataset/diffs/jsonl.ts +0 -53
- package/src/dataset/diffs/test.ts +0 -194
- package/src/embeddings.ts +0 -494
- package/src/fileSync.ts +0 -369
- package/src/generate.ts +0 -529
- package/src/hashes.ts +0 -180
- package/src/index.ts +0 -261
- package/src/logger.ts +0 -197
- package/src/login.ts +0 -209
- package/src/microphone.ts +0 -141
- package/src/migrations.ts +0 -151
- package/src/plugins/AgentsMdPlugin.ts +0 -118
- package/src/plugins/GitPlugin.ts +0 -598
- package/src/plugins/LinterPlugin.ts +0 -214
- package/src/plugins/PluginBase.ts +0 -70
- package/src/plugins/SkillsPlugin.ts +0 -37
- package/src/plugins/embedding.ts +0 -82
- package/src/plugins/exec.ts +0 -70
- package/src/plugins/language.ts +0 -290
- package/src/plugins/plugins.ts +0 -175
- package/src/plugins/tmux.ts +0 -132
- package/src/plugins/types.ts +0 -36
- package/src/plugins/url.ts +0 -101
- package/src/plugins/vim.ts +0 -89
- package/src/processes/ProcessManager.ts +0 -96
- package/src/processes/managedProcessShim.ts +0 -138
- package/src/processors/Base64ImageDetector.ts +0 -502
- package/src/processors/CustomVariables.ts +0 -693
- package/src/processors/GemmaToolProcessor.ts +0 -163
- package/src/processors/HarmonyToolProcessor.ts +0 -264
- package/src/processors/JsonCompressor.ts +0 -510
- package/src/processors/MinimalToolsMessageProcessor.ts +0 -113
- package/src/processors/TokenCompressor.ts +0 -620
- package/src/processors/ToolResponseCache.ts +0 -322
- package/src/processors/XmlToolCallProcessor.ts +0 -533
- package/src/processors/index.ts +0 -14
- package/src/processors/tools/boundedToolResponse.ts +0 -49
- package/src/processors/tools/grepToolResponse.ts +0 -230
- package/src/processors/tools/index.ts +0 -23
- package/src/processors/tools/jqToolResponse.ts +0 -159
- package/src/processors/tools/listStoredToolResponses.ts +0 -124
- package/src/processors/tools/tailToolResponse.ts +0 -148
- package/src/prompts/BasicCodeDocumenter.ts +0 -1
- package/src/prompts/BasicProjectDocumenter.ts +0 -1
- package/src/prompts/EmbeddingSeachHelper.ts +0 -1
- package/src/prompts/KnowhowConfigExamples.ts +0 -376
- package/src/prompts/index.ts +0 -9
- package/src/remotes.ts +0 -110
- package/src/server/index.ts +0 -16
- package/src/services/AgentService.ts +0 -134
- package/src/services/AgentSyncFs.ts +0 -775
- package/src/services/AgentSyncKnowhowWeb.ts +0 -389
- package/src/services/BehaviorsService.ts +0 -466
- package/src/services/DockerService.ts +0 -511
- package/src/services/EmbeddingService.ts +0 -427
- package/src/services/EmbeddingsService.ts +0 -73
- package/src/services/EventService.ts +0 -279
- package/src/services/ExtensionsService.ts +0 -25
- package/src/services/KnowhowClient.ts +0 -928
- package/src/services/LazyToolsService.ts +0 -210
- package/src/services/Mcp.ts +0 -727
- package/src/services/McpServer.ts +0 -155
- package/src/services/McpWebsocketTransport.ts +0 -87
- package/src/services/MediaProcessorService.ts +0 -669
- package/src/services/MessageProcessor.ts +0 -114
- package/src/services/MinimalToolsService.ts +0 -177
- package/src/services/RuntimeReloadService.ts +0 -31
- package/src/services/S3.ts +0 -61
- package/src/services/SessionManager.ts +0 -358
- package/src/services/SkillsService.ts +0 -822
- package/src/services/SyncedAgentWatcher.ts +0 -124
- package/src/services/SyncerService.ts +0 -191
- package/src/services/TaskRegistry.ts +0 -110
- package/src/services/Tools.ts +0 -580
- package/src/services/TracingService.ts +0 -116
- package/src/services/conversion/ConversionService.ts +0 -757
- package/src/services/conversion/index.ts +0 -2
- package/src/services/conversion/types.ts +0 -87
- package/src/services/flags.ts +0 -51
- package/src/services/index.ts +0 -117
- package/src/services/modules/computerUse.ts +0 -218
- package/src/services/modules/index.ts +0 -314
- package/src/services/modules/types.ts +0 -109
- package/src/services/types.ts +0 -60
- package/src/services/watchers/FsSyncer.ts +0 -199
- package/src/services/watchers/RemoteSyncer.ts +0 -196
- package/src/services/watchers/index.ts +0 -2
- package/src/tunnel.ts +0 -243
- package/src/types.ts +0 -282
- package/src/util/Trace.ts +0 -236
- package/src/utils/InputQueueManager.ts +0 -493
- package/src/utils/errors.ts +0 -0
- package/src/utils/http.ts +0 -150
- package/src/utils/index.ts +0 -111
- package/src/worker.ts +0 -696
- package/src/workerRegistry.ts +0 -152
- package/src/workers/auth/PasskeySetup.ts +0 -181
- package/src/workers/auth/WorkerPasskeyAuth.ts +0 -190
- package/src/workers/auth/WsMiddleware.ts +0 -99
- package/src/workers/auth/authMiddleware.ts +0 -104
- package/src/workers/auth/types.ts +0 -70
- package/src/workers/tools/getChallenge.ts +0 -33
- package/src/workers/tools/index.ts +0 -20
- package/src/workers/tools/listAllowedPorts.ts +0 -30
- package/src/workers/tools/lock.ts +0 -31
- package/src/workers/tools/reloadConfig.ts +0 -84
- package/src/workers/tools/unlock.ts +0 -116
- package/tests/XmlToolCallProcessor.test.ts +0 -468
- package/tests/agents/interrupt.test.ts +0 -200
- package/tests/agents/observe-base.test.ts +0 -183
- package/tests/agents/tools/connectAgent.test.ts +0 -138
- package/tests/agents/tools/observe.test.ts +0 -179
- package/tests/agents/tools/readFile.test.ts +0 -88
- package/tests/agents/tools/replyToParent.test.ts +0 -125
- package/tests/agents/tools/sendAgentMessage.test.ts +0 -99
- package/tests/agents/tools/waitForAgentCompleted.test.ts +0 -147
- package/tests/chat/detach-attach-rendering.test.ts +0 -315
- package/tests/clients/AIClient.test.ts +0 -668
- package/tests/clients/anthropic.test.ts +0 -202
- package/tests/clients/contextLimits.test.ts +0 -97
- package/tests/clients/fireworks.test.ts +0 -65
- package/tests/clients/openai.images.test.ts +0 -105
- package/tests/clients/pricing.test.ts +0 -206
- package/tests/clients/reasoningEffort.test.ts +0 -140
- package/tests/compressor/bigstring.test.ts +0 -450
- package/tests/compressor/bigstring.txt +0 -1
- package/tests/compressor/githubjson.txt +0 -1
- package/tests/compressor/toolResponseCache.test.ts +0 -304
- package/tests/compressor/usageBase64.json +0 -159
- package/tests/compressor/usageBase64.test.ts +0 -175
- package/tests/fixtures/fake-secret.txt +0 -1
- package/tests/manual/agent-events/run-test.ts +0 -203
- package/tests/manual/browser-login/README.md +0 -189
- package/tests/manual/browser-login/test_browser_login_basic.ts +0 -115
- package/tests/manual/browser-login/test_cli_integration.ts +0 -169
- package/tests/manual/browser-login/test_cross_platform_browser.ts +0 -186
- package/tests/manual/browser-login/test_error_scenarios.ts +0 -223
- package/tests/manual/cli/no-env.sh +0 -274
- package/tests/manual/clients/completions.json +0 -1151
- package/tests/manual/clients/completions.test.ts +0 -198
- package/tests/manual/file-edits/figma.test.ts +0 -3
- package/tests/manual/file-edits/fileblocks/readwrite.test.ts +0 -100
- package/tests/manual/file-edits/patching/input.txt +0 -145
- package/tests/manual/file-edits/patching/output.txt +0 -145
- package/tests/manual/file-edits/patching/patch.txt +0 -15
- package/tests/manual/file-edits/patching/unseen.txt +0 -80
- package/tests/manual/file-edits/patching.test.ts +0 -139
- package/tests/manual/modalities/README.md +0 -157
- package/tests/manual/modalities/google.modalities.test.ts +0 -335
- package/tests/manual/modalities/openai.modalities.test.ts +0 -329
- package/tests/manual/modalities/streaming.test.ts +0 -260
- package/tests/manual/modalities/xai.modalities.test.ts +0 -294
- package/tests/manual/test-concurrent-ask.ts +0 -43
- package/tests/manual/ycmd/debug_diagnostics_test.ts +0 -127
- package/tests/manual/ycmd/fixtures/debug_diagnostics.ts +0 -26
- package/tests/manual/ycmd/fixtures/file_change_test.ts +0 -17
- package/tests/manual/ycmd/minimal_advanced_test.ts +0 -108
- package/tests/manual/ycmd/simple_diagnostics_test.ts +0 -61
- package/tests/manual/ycmd/simple_test.ts +0 -74
- package/tests/manual/ycmd/test-typescript-sample.ts +0 -34
- package/tests/manual/ycmd/test_advanced_features.ts +0 -407
- package/tests/manual/ycmd/test_advanced_with_tools.ts +0 -320
- package/tests/manual/ycmd/test_comprehensive_typescript.ts +0 -179
- package/tests/manual/ycmd/test_diagnostics_file_changes.ts +0 -249
- package/tests/manual/ycmd/test_diagnostics_fix.ts +0 -99
- package/tests/manual/ycmd/test_diagnostics_simple.ts +0 -100
- package/tests/manual/ycmd/test_diagnostics_timing.ts +0 -120
- package/tests/manual/ycmd/test_discover_commands.ts +0 -310
- package/tests/manual/ycmd/test_endpoints.ts +0 -115
- package/tests/manual/ycmd/test_final_comprehensive.ts +0 -218
- package/tests/manual/ycmd/test_final_validation.ts +0 -150
- package/tests/manual/ycmd/test_implementation.js +0 -42
- package/tests/manual/ycmd/test_individual_ycmd_tool.ts +0 -39
- package/tests/manual/ycmd/test_server_manager.ts +0 -52
- package/tests/manual/ycmd/test_simple_debug.ts +0 -86
- package/tests/manual/ycmd/test_tsserver_workflow.js +0 -83
- package/tests/manual/ycmd/test_tsserver_workflow.ts +0 -122
- package/tests/manual/ycmd/test_typescript_simple.ts +0 -48
- package/tests/manual/ycmd/test_typescript_ycmd.ts +0 -105
- package/tests/manual/ycmd/test_workspace_config.ts +0 -90
- package/tests/manual/ycmd/test_ycmd_auto_start.ts +0 -137
- package/tests/manual/ycmd/test_ycmd_comprehensive.ts +0 -73
- package/tests/manual/ycmd/test_ycmd_connection.py +0 -10
- package/tests/manual/ycmd/test_ycmd_direct.ts +0 -142
- package/tests/manual/ycmd/test_ycmd_experiment.ts +0 -48
- package/tests/manual/ycmd/test_ycmd_final.ts +0 -200
- package/tests/manual/ycmd/test_ycmd_fixed.py +0 -18
- package/tests/manual/ycmd/test_ycmd_integration.ts +0 -112
- package/tests/manual/ycmd/test_ycmd_simple.ts +0 -45
- package/tests/manual/ycmd/test_ycmd_usage.py +0 -27
- package/tests/manual/ycmd/working_simple_test.ts +0 -134
- package/tests/patching/corrupted.test.ts +0 -78
- package/tests/patching/fixtures/transcript-mangles/agent-sync-fs-nested-catch.json +0 -9
- package/tests/patching/fixtures/transcript-mangles/automation-functions-crossed.json +0 -9
- package/tests/patching/fixtures/transcript-mangles/fruit-ninja-confirmed-retirement.json +0 -8
- package/tests/patching/imports.patch.txt +0 -11
- package/tests/patching/imports.test.ts +0 -43
- package/tests/patching/imports.txt +0 -11
- package/tests/patching/interface.patch.txt +0 -15
- package/tests/patching/interface.txt +0 -7
- package/tests/patching/patchFileOutput.test.ts +0 -328
- package/tests/patching/regression-2026.test.ts +0 -752
- package/tests/patching/transcriptMangleRegression.test.ts +0 -125
- package/tests/plugins/language/languagePlugin-content-triggers.test.ts +0 -346
- package/tests/plugins/language/languagePlugin-integration.test.ts +0 -471
- package/tests/plugins/language/languagePlugin.test.ts +0 -385
- package/tests/processes/managedProcessShim.test.ts +0 -59
- package/tests/processors/Base64ImageDetector.test.ts +0 -979
- package/tests/processors/CustomVariables.test.ts +0 -981
- package/tests/processors/CustomVariablesBenchmark.test.ts +0 -237
- package/tests/processors/HarmonyToolProcessor.test.ts +0 -490
- package/tests/processors/TokenCompressor.test.ts +0 -674
- package/tests/processors/ToolResponseCache.test.ts +0 -864
- package/tests/processors/tools/boundedRetrievalTools.test.ts +0 -68
- package/tests/processors/tools/grepToolResponse.test.ts +0 -159
- package/tests/services/ConversionService.test.ts +0 -154
- package/tests/services/DockerService.test.ts +0 -24
- package/tests/services/Tools.test.ts +0 -1738
- package/tests/services/ToolsService.setFunction.test.ts +0 -68
- package/tests/services/WorkerReloadConfig.test.ts +0 -141
- package/tests/test.spec.ts +0 -163
- package/tests/unit/InputQueueManager.test.ts +0 -174
- package/tests/unit/McpWebsocketTransport.test.ts +0 -56
- package/tests/unit/agents/historyRollback.test.ts +0 -53
- package/tests/unit/agents/tools/loadImageAsBase64.test.ts +0 -44
- package/tests/unit/auth/jwtStore.test.ts +0 -55
- package/tests/unit/auth/keyAuth.test.ts +0 -152
- package/tests/unit/auth/keyManager.test.ts +0 -130
- package/tests/unit/auth/registerIdentity.test.ts +0 -99
- package/tests/unit/chat/ToolCommandModule.test.ts +0 -71
- package/tests/unit/chat/historyCommandArgs.test.ts +0 -37
- package/tests/unit/clients/AIClient.test.ts +0 -454
- package/tests/unit/clients/anthropic.responseMetadata.test.ts +0 -81
- package/tests/unit/clients/attribution.test.ts +0 -185
- package/tests/unit/clients/http.responseMetadata.test.ts +0 -86
- package/tests/unit/clients/openai.responseMetadata.test.ts +0 -90
- package/tests/unit/clients/responseMetadata.test.ts +0 -123
- package/tests/unit/clients/withRetry.test.ts +0 -319
- package/tests/unit/commands/agents.test.ts +0 -111
- package/tests/unit/commands/github-credentials.test.ts +0 -210
- package/tests/unit/commands/misc.test.ts +0 -85
- package/tests/unit/commands/remote.test.ts +0 -79
- package/tests/unit/commands/sandbox.test.ts +0 -350
- package/tests/unit/hashes.test.ts +0 -23
- package/tests/unit/input-queue.test.ts +0 -80
- package/tests/unit/login.test.ts +0 -218
- package/tests/unit/modules/moduleLoading.test.ts +0 -305
- package/tests/unit/plugins/pluginLoading.test.ts +0 -97
- package/tests/unit/services/AgentSyncKnowhowWeb.test.ts +0 -38
- package/tests/unit/services/KnowhowClient.test.ts +0 -84
- package/tests/unit/services/LazyToolsService.test.ts +0 -53
- package/tests/unit/services/Mcp.test.ts +0 -56
- package/tests/unit/services/MinimalToolsService.test.ts +0 -424
- package/tests/unit/services/RuntimeReloadService.test.ts +0 -29
- package/tests/unit/services/SessionManager.test.ts +0 -43
- package/tests/unit/services/SyncedAgentWatcher.test.ts +0 -89
- package/tests/unit/services/SyncerService.test.ts +0 -45
- package/tests/unit/tunnel.test.ts +0 -51
- package/tests/unit/util/Trace.test.ts +0 -119
- package/tests/unit/utils/http.test.ts +0 -43
- package/ts_build/tests/XmlToolCallProcessor.test.d.ts +0 -1
- package/ts_build/tests/XmlToolCallProcessor.test.js +0 -376
- package/ts_build/tests/XmlToolCallProcessor.test.js.map +0 -1
- package/ts_build/tests/agents/interrupt.test.d.ts +0 -14
- package/ts_build/tests/agents/interrupt.test.js +0 -136
- package/ts_build/tests/agents/interrupt.test.js.map +0 -1
- package/ts_build/tests/agents/observe-base.test.d.ts +0 -1
- package/ts_build/tests/agents/observe-base.test.js +0 -149
- package/ts_build/tests/agents/observe-base.test.js.map +0 -1
- package/ts_build/tests/agents/tools/connectAgent.test.d.ts +0 -1
- package/ts_build/tests/agents/tools/connectAgent.test.js +0 -142
- package/ts_build/tests/agents/tools/connectAgent.test.js.map +0 -1
- package/ts_build/tests/agents/tools/observe.test.d.ts +0 -1
- package/ts_build/tests/agents/tools/observe.test.js +0 -148
- package/ts_build/tests/agents/tools/observe.test.js.map +0 -1
- package/ts_build/tests/agents/tools/readFile.test.d.ts +0 -1
- package/ts_build/tests/agents/tools/readFile.test.js +0 -90
- package/ts_build/tests/agents/tools/readFile.test.js.map +0 -1
- package/ts_build/tests/agents/tools/replyToParent.test.d.ts +0 -1
- package/ts_build/tests/agents/tools/replyToParent.test.js +0 -116
- package/ts_build/tests/agents/tools/replyToParent.test.js.map +0 -1
- package/ts_build/tests/agents/tools/sendAgentMessage.test.d.ts +0 -1
- package/ts_build/tests/agents/tools/sendAgentMessage.test.js +0 -112
- package/ts_build/tests/agents/tools/sendAgentMessage.test.js.map +0 -1
- package/ts_build/tests/agents/tools/waitForAgentCompleted.test.d.ts +0 -1
- package/ts_build/tests/agents/tools/waitForAgentCompleted.test.js +0 -147
- package/ts_build/tests/agents/tools/waitForAgentCompleted.test.js.map +0 -1
- package/ts_build/tests/chat/detach-attach-rendering.test.d.ts +0 -1
- package/ts_build/tests/chat/detach-attach-rendering.test.js +0 -168
- package/ts_build/tests/chat/detach-attach-rendering.test.js.map +0 -1
- package/ts_build/tests/clients/AIClient.test.d.ts +0 -1
- package/ts_build/tests/clients/AIClient.test.js +0 -483
- package/ts_build/tests/clients/AIClient.test.js.map +0 -1
- package/ts_build/tests/clients/anthropic.test.d.ts +0 -1
- package/ts_build/tests/clients/anthropic.test.js +0 -159
- package/ts_build/tests/clients/anthropic.test.js.map +0 -1
- package/ts_build/tests/clients/contextLimits.test.d.ts +0 -1
- package/ts_build/tests/clients/contextLimits.test.js +0 -69
- package/ts_build/tests/clients/contextLimits.test.js.map +0 -1
- package/ts_build/tests/clients/fireworks.test.d.ts +0 -1
- package/ts_build/tests/clients/fireworks.test.js +0 -65
- package/ts_build/tests/clients/fireworks.test.js.map +0 -1
- package/ts_build/tests/clients/openai.images.test.d.ts +0 -1
- package/ts_build/tests/clients/openai.images.test.js +0 -94
- package/ts_build/tests/clients/openai.images.test.js.map +0 -1
- package/ts_build/tests/clients/pricing.test.d.ts +0 -1
- package/ts_build/tests/clients/pricing.test.js +0 -124
- package/ts_build/tests/clients/pricing.test.js.map +0 -1
- package/ts_build/tests/clients/reasoningEffort.test.d.ts +0 -1
- package/ts_build/tests/clients/reasoningEffort.test.js +0 -116
- package/ts_build/tests/clients/reasoningEffort.test.js.map +0 -1
- package/ts_build/tests/compressor/bigstring.test.d.ts +0 -1
- package/ts_build/tests/compressor/bigstring.test.js +0 -275
- package/ts_build/tests/compressor/bigstring.test.js.map +0 -1
- package/ts_build/tests/compressor/toolResponseCache.test.d.ts +0 -1
- package/ts_build/tests/compressor/toolResponseCache.test.js +0 -250
- package/ts_build/tests/compressor/toolResponseCache.test.js.map +0 -1
- package/ts_build/tests/compressor/usageBase64.test.d.ts +0 -1
- package/ts_build/tests/compressor/usageBase64.test.js +0 -109
- package/ts_build/tests/compressor/usageBase64.test.js.map +0 -1
- package/ts_build/tests/manual/agent-events/run-test.d.ts +0 -2
- package/ts_build/tests/manual/agent-events/run-test.js +0 -148
- package/ts_build/tests/manual/agent-events/run-test.js.map +0 -1
- package/ts_build/tests/manual/browser-login/test_browser_login_basic.d.ts +0 -2
- package/ts_build/tests/manual/browser-login/test_browser_login_basic.js +0 -118
- package/ts_build/tests/manual/browser-login/test_browser_login_basic.js.map +0 -1
- package/ts_build/tests/manual/browser-login/test_cli_integration.d.ts +0 -2
- package/ts_build/tests/manual/browser-login/test_cli_integration.js +0 -163
- package/ts_build/tests/manual/browser-login/test_cli_integration.js.map +0 -1
- package/ts_build/tests/manual/browser-login/test_cross_platform_browser.d.ts +0 -2
- package/ts_build/tests/manual/browser-login/test_cross_platform_browser.js +0 -169
- package/ts_build/tests/manual/browser-login/test_cross_platform_browser.js.map +0 -1
- package/ts_build/tests/manual/browser-login/test_error_scenarios.d.ts +0 -2
- package/ts_build/tests/manual/browser-login/test_error_scenarios.js +0 -207
- package/ts_build/tests/manual/browser-login/test_error_scenarios.js.map +0 -1
- package/ts_build/tests/manual/clients/completions.test.d.ts +0 -1
- package/ts_build/tests/manual/clients/completions.test.js +0 -151
- package/ts_build/tests/manual/clients/completions.test.js.map +0 -1
- package/ts_build/tests/manual/file-edits/figma.test.d.ts +0 -0
- package/ts_build/tests/manual/file-edits/figma.test.js +0 -2
- package/ts_build/tests/manual/file-edits/figma.test.js.map +0 -1
- package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.d.ts +0 -1
- package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js +0 -110
- package/ts_build/tests/manual/file-edits/fileblocks/readwrite.test.js.map +0 -1
- package/ts_build/tests/manual/file-edits/patching.test.d.ts +0 -1
- package/ts_build/tests/manual/file-edits/patching.test.js +0 -129
- package/ts_build/tests/manual/file-edits/patching.test.js.map +0 -1
- package/ts_build/tests/manual/modalities/google.modalities.test.d.ts +0 -1
- package/ts_build/tests/manual/modalities/google.modalities.test.js +0 -262
- package/ts_build/tests/manual/modalities/google.modalities.test.js.map +0 -1
- package/ts_build/tests/manual/modalities/openai.modalities.test.d.ts +0 -1
- package/ts_build/tests/manual/modalities/openai.modalities.test.js +0 -262
- package/ts_build/tests/manual/modalities/openai.modalities.test.js.map +0 -1
- package/ts_build/tests/manual/modalities/streaming.test.d.ts +0 -1
- package/ts_build/tests/manual/modalities/streaming.test.js +0 -216
- package/ts_build/tests/manual/modalities/streaming.test.js.map +0 -1
- package/ts_build/tests/manual/modalities/xai.modalities.test.d.ts +0 -1
- package/ts_build/tests/manual/modalities/xai.modalities.test.js +0 -219
- package/ts_build/tests/manual/modalities/xai.modalities.test.js.map +0 -1
- package/ts_build/tests/manual/test-concurrent-ask.d.ts +0 -1
- package/ts_build/tests/manual/test-concurrent-ask.js +0 -22
- package/ts_build/tests/manual/test-concurrent-ask.js.map +0 -1
- package/ts_build/tests/manual/ycmd/debug_diagnostics_test.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js +0 -124
- package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js.map +0 -1
- package/ts_build/tests/manual/ycmd/minimal_advanced_test.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/minimal_advanced_test.js +0 -114
- package/ts_build/tests/manual/ycmd/minimal_advanced_test.js.map +0 -1
- package/ts_build/tests/manual/ycmd/simple_diagnostics_test.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js +0 -84
- package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js.map +0 -1
- package/ts_build/tests/manual/ycmd/simple_test.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/simple_test.js +0 -92
- package/ts_build/tests/manual/ycmd/simple_test.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test-typescript-sample.d.ts +0 -14
- package/ts_build/tests/manual/ycmd/test-typescript-sample.js +0 -20
- package/ts_build/tests/manual/ycmd/test-typescript-sample.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_advanced_features.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_advanced_features.js +0 -306
- package/ts_build/tests/manual/ycmd/test_advanced_features.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_advanced_with_tools.d.ts +0 -3
- package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js +0 -271
- package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js +0 -196
- package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js +0 -184
- package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_diagnostics_fix.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js +0 -116
- package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_diagnostics_simple.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js +0 -114
- package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_diagnostics_timing.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js +0 -129
- package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_discover_commands.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_discover_commands.js +0 -252
- package/ts_build/tests/manual/ycmd/test_discover_commands.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_endpoints.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_endpoints.js +0 -130
- package/ts_build/tests/manual/ycmd/test_endpoints.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_final_comprehensive.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_final_comprehensive.js +0 -231
- package/ts_build/tests/manual/ycmd/test_final_comprehensive.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_final_validation.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_final_validation.js +0 -170
- package/ts_build/tests/manual/ycmd/test_final_validation.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js +0 -37
- package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_server_manager.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_server_manager.js +0 -38
- package/ts_build/tests/manual/ycmd/test_server_manager.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_simple_debug.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_simple_debug.js +0 -109
- package/ts_build/tests/manual/ycmd/test_simple_debug.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_tsserver_workflow.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js +0 -138
- package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_typescript_simple.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_typescript_simple.js +0 -76
- package/ts_build/tests/manual/ycmd/test_typescript_simple.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_typescript_ycmd.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js +0 -115
- package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_workspace_config.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_workspace_config.js +0 -99
- package/ts_build/tests/manual/ycmd/test_workspace_config.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js +0 -140
- package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.d.ts +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js +0 -93
- package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_direct.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_ycmd_direct.js +0 -159
- package/ts_build/tests/manual/ycmd/test_ycmd_direct.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_experiment.d.ts +0 -15
- package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js +0 -68
- package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_final.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_ycmd_final.js +0 -205
- package/ts_build/tests/manual/ycmd/test_ycmd_final.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_integration.d.ts +0 -3
- package/ts_build/tests/manual/ycmd/test_ycmd_integration.js +0 -119
- package/ts_build/tests/manual/ycmd/test_ycmd_integration.js.map +0 -1
- package/ts_build/tests/manual/ycmd/test_ycmd_simple.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/test_ycmd_simple.js +0 -36
- package/ts_build/tests/manual/ycmd/test_ycmd_simple.js.map +0 -1
- package/ts_build/tests/manual/ycmd/working_simple_test.d.ts +0 -2
- package/ts_build/tests/manual/ycmd/working_simple_test.js +0 -144
- package/ts_build/tests/manual/ycmd/working_simple_test.js.map +0 -1
- package/ts_build/tests/patching/corrupted.test.d.ts +0 -1
- package/ts_build/tests/patching/corrupted.test.js +0 -53
- package/ts_build/tests/patching/corrupted.test.js.map +0 -1
- package/ts_build/tests/patching/imports.test.d.ts +0 -1
- package/ts_build/tests/patching/imports.test.js +0 -71
- package/ts_build/tests/patching/imports.test.js.map +0 -1
- package/ts_build/tests/patching/patchFileOutput.test.d.ts +0 -1
- package/ts_build/tests/patching/patchFileOutput.test.js +0 -269
- package/ts_build/tests/patching/patchFileOutput.test.js.map +0 -1
- package/ts_build/tests/patching/regression-2026.test.d.ts +0 -1
- package/ts_build/tests/patching/regression-2026.test.js +0 -528
- package/ts_build/tests/patching/regression-2026.test.js.map +0 -1
- package/ts_build/tests/patching/transcriptMangleRegression.test.d.ts +0 -1
- package/ts_build/tests/patching/transcriptMangleRegression.test.js +0 -104
- package/ts_build/tests/patching/transcriptMangleRegression.test.js.map +0 -1
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.d.ts +0 -1
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +0 -294
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +0 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.d.ts +0 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +0 -343
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +0 -1
- package/ts_build/tests/plugins/language/languagePlugin.test.d.ts +0 -1
- package/ts_build/tests/plugins/language/languagePlugin.test.js +0 -315
- package/ts_build/tests/plugins/language/languagePlugin.test.js.map +0 -1
- package/ts_build/tests/processes/managedProcessShim.test.d.ts +0 -1
- package/ts_build/tests/processes/managedProcessShim.test.js +0 -92
- package/ts_build/tests/processes/managedProcessShim.test.js.map +0 -1
- package/ts_build/tests/processors/Base64ImageDetector.test.d.ts +0 -1
- package/ts_build/tests/processors/Base64ImageDetector.test.js +0 -792
- package/ts_build/tests/processors/Base64ImageDetector.test.js.map +0 -1
- package/ts_build/tests/processors/CustomVariables.test.d.ts +0 -1
- package/ts_build/tests/processors/CustomVariables.test.js +0 -764
- package/ts_build/tests/processors/CustomVariables.test.js.map +0 -1
- package/ts_build/tests/processors/CustomVariablesBenchmark.test.d.ts +0 -1
- package/ts_build/tests/processors/CustomVariablesBenchmark.test.js +0 -179
- package/ts_build/tests/processors/CustomVariablesBenchmark.test.js.map +0 -1
- package/ts_build/tests/processors/HarmonyToolProcessor.test.d.ts +0 -1
- package/ts_build/tests/processors/HarmonyToolProcessor.test.js +0 -382
- package/ts_build/tests/processors/HarmonyToolProcessor.test.js.map +0 -1
- package/ts_build/tests/processors/TokenCompressor.test.d.ts +0 -1
- package/ts_build/tests/processors/TokenCompressor.test.js +0 -473
- package/ts_build/tests/processors/TokenCompressor.test.js.map +0 -1
- package/ts_build/tests/processors/ToolResponseCache.test.d.ts +0 -1
- package/ts_build/tests/processors/ToolResponseCache.test.js +0 -657
- package/ts_build/tests/processors/ToolResponseCache.test.js.map +0 -1
- package/ts_build/tests/processors/tools/boundedRetrievalTools.test.d.ts +0 -1
- package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js +0 -57
- package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js.map +0 -1
- package/ts_build/tests/processors/tools/grepToolResponse.test.d.ts +0 -1
- package/ts_build/tests/processors/tools/grepToolResponse.test.js +0 -77
- package/ts_build/tests/processors/tools/grepToolResponse.test.js.map +0 -1
- package/ts_build/tests/services/ConversionService.test.d.ts +0 -1
- package/ts_build/tests/services/ConversionService.test.js +0 -154
- package/ts_build/tests/services/ConversionService.test.js.map +0 -1
- package/ts_build/tests/services/DockerService.test.d.ts +0 -1
- package/ts_build/tests/services/DockerService.test.js +0 -22
- package/ts_build/tests/services/DockerService.test.js.map +0 -1
- package/ts_build/tests/services/Tools.test.d.ts +0 -1
- package/ts_build/tests/services/Tools.test.js +0 -1365
- package/ts_build/tests/services/Tools.test.js.map +0 -1
- package/ts_build/tests/services/ToolsService.setFunction.test.d.ts +0 -1
- package/ts_build/tests/services/ToolsService.setFunction.test.js +0 -51
- package/ts_build/tests/services/ToolsService.setFunction.test.js.map +0 -1
- package/ts_build/tests/services/WorkerReloadConfig.test.d.ts +0 -1
- package/ts_build/tests/services/WorkerReloadConfig.test.js +0 -86
- package/ts_build/tests/services/WorkerReloadConfig.test.js.map +0 -1
- package/ts_build/tests/test.spec.d.ts +0 -1
- package/ts_build/tests/test.spec.js +0 -139
- package/ts_build/tests/test.spec.js.map +0 -1
- package/ts_build/tests/unit/InputQueueManager.test.d.ts +0 -1
- package/ts_build/tests/unit/InputQueueManager.test.js +0 -104
- package/ts_build/tests/unit/InputQueueManager.test.js.map +0 -1
- package/ts_build/tests/unit/McpWebsocketTransport.test.d.ts +0 -1
- package/ts_build/tests/unit/McpWebsocketTransport.test.js +0 -47
- package/ts_build/tests/unit/McpWebsocketTransport.test.js.map +0 -1
- package/ts_build/tests/unit/agents/historyRollback.test.d.ts +0 -1
- package/ts_build/tests/unit/agents/historyRollback.test.js +0 -42
- package/ts_build/tests/unit/agents/historyRollback.test.js.map +0 -1
- package/ts_build/tests/unit/agents/tools/loadImageAsBase64.test.d.ts +0 -1
- package/ts_build/tests/unit/agents/tools/loadImageAsBase64.test.js +0 -67
- package/ts_build/tests/unit/agents/tools/loadImageAsBase64.test.js.map +0 -1
- package/ts_build/tests/unit/auth/jwtStore.test.d.ts +0 -1
- package/ts_build/tests/unit/auth/jwtStore.test.js +0 -46
- package/ts_build/tests/unit/auth/jwtStore.test.js.map +0 -1
- package/ts_build/tests/unit/auth/keyAuth.test.d.ts +0 -1
- package/ts_build/tests/unit/auth/keyAuth.test.js +0 -118
- package/ts_build/tests/unit/auth/keyAuth.test.js.map +0 -1
- package/ts_build/tests/unit/auth/keyManager.test.d.ts +0 -1
- package/ts_build/tests/unit/auth/keyManager.test.js +0 -96
- package/ts_build/tests/unit/auth/keyManager.test.js.map +0 -1
- package/ts_build/tests/unit/auth/registerIdentity.test.d.ts +0 -1
- package/ts_build/tests/unit/auth/registerIdentity.test.js +0 -92
- package/ts_build/tests/unit/auth/registerIdentity.test.js.map +0 -1
- package/ts_build/tests/unit/chat/ToolCommandModule.test.d.ts +0 -1
- package/ts_build/tests/unit/chat/ToolCommandModule.test.js +0 -61
- package/ts_build/tests/unit/chat/ToolCommandModule.test.js.map +0 -1
- package/ts_build/tests/unit/chat/historyCommandArgs.test.d.ts +0 -1
- package/ts_build/tests/unit/chat/historyCommandArgs.test.js +0 -29
- package/ts_build/tests/unit/chat/historyCommandArgs.test.js.map +0 -1
- package/ts_build/tests/unit/clients/AIClient.test.d.ts +0 -1
- package/ts_build/tests/unit/clients/AIClient.test.js +0 -342
- package/ts_build/tests/unit/clients/AIClient.test.js.map +0 -1
- package/ts_build/tests/unit/clients/anthropic.responseMetadata.test.d.ts +0 -1
- package/ts_build/tests/unit/clients/anthropic.responseMetadata.test.js +0 -77
- package/ts_build/tests/unit/clients/anthropic.responseMetadata.test.js.map +0 -1
- package/ts_build/tests/unit/clients/attribution.test.d.ts +0 -1
- package/ts_build/tests/unit/clients/attribution.test.js +0 -153
- package/ts_build/tests/unit/clients/attribution.test.js.map +0 -1
- package/ts_build/tests/unit/clients/http.responseMetadata.test.d.ts +0 -1
- package/ts_build/tests/unit/clients/http.responseMetadata.test.js +0 -77
- package/ts_build/tests/unit/clients/http.responseMetadata.test.js.map +0 -1
- package/ts_build/tests/unit/clients/openai.responseMetadata.test.d.ts +0 -1
- package/ts_build/tests/unit/clients/openai.responseMetadata.test.js +0 -86
- package/ts_build/tests/unit/clients/openai.responseMetadata.test.js.map +0 -1
- package/ts_build/tests/unit/clients/responseMetadata.test.d.ts +0 -1
- package/ts_build/tests/unit/clients/responseMetadata.test.js +0 -96
- package/ts_build/tests/unit/clients/responseMetadata.test.js.map +0 -1
- package/ts_build/tests/unit/clients/withRetry.test.d.ts +0 -1
- package/ts_build/tests/unit/clients/withRetry.test.js +0 -225
- package/ts_build/tests/unit/clients/withRetry.test.js.map +0 -1
- package/ts_build/tests/unit/commands/agents.test.d.ts +0 -1
- package/ts_build/tests/unit/commands/agents.test.js +0 -119
- package/ts_build/tests/unit/commands/agents.test.js.map +0 -1
- package/ts_build/tests/unit/commands/github-credentials.test.d.ts +0 -1
- package/ts_build/tests/unit/commands/github-credentials.test.js +0 -145
- package/ts_build/tests/unit/commands/github-credentials.test.js.map +0 -1
- package/ts_build/tests/unit/commands/misc.test.d.ts +0 -1
- package/ts_build/tests/unit/commands/misc.test.js +0 -70
- package/ts_build/tests/unit/commands/misc.test.js.map +0 -1
- package/ts_build/tests/unit/commands/remote.test.d.ts +0 -1
- package/ts_build/tests/unit/commands/remote.test.js +0 -70
- package/ts_build/tests/unit/commands/remote.test.js.map +0 -1
- package/ts_build/tests/unit/commands/sandbox.test.d.ts +0 -1
- package/ts_build/tests/unit/commands/sandbox.test.js +0 -258
- package/ts_build/tests/unit/commands/sandbox.test.js.map +0 -1
- package/ts_build/tests/unit/hashes.test.d.ts +0 -1
- package/ts_build/tests/unit/hashes.test.js +0 -25
- package/ts_build/tests/unit/hashes.test.js.map +0 -1
- package/ts_build/tests/unit/input-queue.test.d.ts +0 -1
- package/ts_build/tests/unit/input-queue.test.js +0 -32
- package/ts_build/tests/unit/input-queue.test.js.map +0 -1
- package/ts_build/tests/unit/login.test.d.ts +0 -1
- package/ts_build/tests/unit/login.test.js +0 -166
- package/ts_build/tests/unit/login.test.js.map +0 -1
- package/ts_build/tests/unit/modules/moduleLoading.test.d.ts +0 -1
- package/ts_build/tests/unit/modules/moduleLoading.test.js +0 -272
- package/ts_build/tests/unit/modules/moduleLoading.test.js.map +0 -1
- package/ts_build/tests/unit/plugins/pluginLoading.test.d.ts +0 -1
- package/ts_build/tests/unit/plugins/pluginLoading.test.js +0 -117
- package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +0 -1
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.d.ts +0 -1
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js +0 -32
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js.map +0 -1
- package/ts_build/tests/unit/services/KnowhowClient.test.d.ts +0 -1
- package/ts_build/tests/unit/services/KnowhowClient.test.js +0 -69
- package/ts_build/tests/unit/services/KnowhowClient.test.js.map +0 -1
- package/ts_build/tests/unit/services/LazyToolsService.test.d.ts +0 -1
- package/ts_build/tests/unit/services/LazyToolsService.test.js +0 -47
- package/ts_build/tests/unit/services/LazyToolsService.test.js.map +0 -1
- package/ts_build/tests/unit/services/Mcp.test.d.ts +0 -1
- package/ts_build/tests/unit/services/Mcp.test.js +0 -45
- package/ts_build/tests/unit/services/Mcp.test.js.map +0 -1
- package/ts_build/tests/unit/services/MinimalToolsService.test.d.ts +0 -1
- package/ts_build/tests/unit/services/MinimalToolsService.test.js +0 -320
- package/ts_build/tests/unit/services/MinimalToolsService.test.js.map +0 -1
- package/ts_build/tests/unit/services/RuntimeReloadService.test.d.ts +0 -1
- package/ts_build/tests/unit/services/RuntimeReloadService.test.js +0 -26
- package/ts_build/tests/unit/services/RuntimeReloadService.test.js.map +0 -1
- package/ts_build/tests/unit/services/SessionManager.test.d.ts +0 -1
- package/ts_build/tests/unit/services/SessionManager.test.js +0 -72
- package/ts_build/tests/unit/services/SessionManager.test.js.map +0 -1
- package/ts_build/tests/unit/services/SyncedAgentWatcher.test.d.ts +0 -1
- package/ts_build/tests/unit/services/SyncedAgentWatcher.test.js +0 -78
- package/ts_build/tests/unit/services/SyncedAgentWatcher.test.js.map +0 -1
- package/ts_build/tests/unit/services/SyncerService.test.d.ts +0 -1
- package/ts_build/tests/unit/services/SyncerService.test.js +0 -40
- package/ts_build/tests/unit/services/SyncerService.test.js.map +0 -1
- package/ts_build/tests/unit/tunnel.test.d.ts +0 -1
- package/ts_build/tests/unit/tunnel.test.js +0 -47
- package/ts_build/tests/unit/tunnel.test.js.map +0 -1
- package/ts_build/tests/unit/util/Trace.test.d.ts +0 -1
- package/ts_build/tests/unit/util/Trace.test.js +0 -107
- package/ts_build/tests/unit/util/Trace.test.js.map +0 -1
- package/ts_build/tests/unit/utils/http.test.d.ts +0 -1
- package/ts_build/tests/unit/utils/http.test.js +0 -69
- package/ts_build/tests/unit/utils/http.test.js.map +0 -1
- package/tsconfig.json +0 -34
- 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
|
-
}
|