explorbot 0.0.1 → 0.0.5
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/README.md +80 -26
- package/bin/explorbot-cli.ts +679 -0
- package/boat/api-tester/src/ai/chief/styles.ts +15 -0
- package/boat/api-tester/src/ai/chief.ts +335 -0
- package/boat/api-tester/src/ai/curler-tools.ts +278 -0
- package/boat/api-tester/src/ai/curler.ts +306 -0
- package/boat/api-tester/src/api-client.ts +28 -0
- package/boat/api-tester/src/apibot.ts +203 -0
- package/boat/api-tester/src/cli.ts +301 -0
- package/boat/api-tester/src/config.ts +190 -0
- package/dist/bin/explorbot-cli.js +19 -98
- package/dist/boat/api-tester/bin/apibot-cli.js +0 -1
- package/dist/boat/api-tester/src/ai/chief/styles.js +0 -1
- package/dist/boat/api-tester/src/ai/chief.js +0 -1
- package/dist/boat/api-tester/src/ai/curler-tools.js +0 -1
- package/dist/boat/api-tester/src/ai/curler.js +0 -1
- package/dist/boat/api-tester/src/api-client.js +0 -1
- package/dist/boat/api-tester/src/apibot.js +0 -1
- package/dist/boat/api-tester/src/cli.js +0 -1
- package/dist/boat/api-tester/src/config.js +0 -1
- package/dist/src/action-result.js +0 -1
- package/dist/src/action.js +0 -1
- package/dist/src/activity.js +0 -1
- package/dist/src/ai/agent.js +0 -1
- package/dist/src/ai/bosun.js +0 -1
- package/dist/src/ai/captain/idle-mode.js +0 -1
- package/dist/src/ai/captain/mixin.js +0 -1
- package/dist/src/ai/captain/test-mode.js +0 -1
- package/dist/src/ai/captain/web-mode.js +0 -1
- package/dist/src/ai/captain.js +0 -1
- package/dist/src/ai/conversation.js +0 -1
- package/dist/src/ai/experience-compactor.js +0 -1
- package/dist/src/ai/fisherman-tools.js +0 -1
- package/dist/src/ai/fisherman.js +0 -1
- package/dist/src/ai/historian.js +0 -1
- package/dist/src/ai/navigator.js +0 -1
- package/dist/src/ai/pilot.js +0 -1
- package/dist/src/ai/planner/session-dedup.js +0 -1
- package/dist/src/ai/planner/styles.js +0 -1
- package/dist/src/ai/planner/subpages.js +0 -1
- package/dist/src/ai/planner.js +0 -1
- package/dist/src/ai/provider.js +0 -1
- package/dist/src/ai/quartermaster.js +0 -1
- package/dist/src/ai/researcher/cache.js +0 -1
- package/dist/src/ai/researcher/coordinates.js +0 -1
- package/dist/src/ai/researcher/deep-analysis.js +0 -1
- package/dist/src/ai/researcher/fingerprint-worker.js +0 -1
- package/dist/src/ai/researcher/focus.js +0 -1
- package/dist/src/ai/researcher/locators.js +0 -1
- package/dist/src/ai/researcher/mixin.js +0 -1
- package/dist/src/ai/researcher/parser.js +0 -1
- package/dist/src/ai/researcher/research-result.js +0 -1
- package/dist/src/ai/researcher.js +0 -1
- package/dist/src/ai/rules.js +0 -1
- package/dist/src/ai/task-agent.js +0 -1
- package/dist/src/ai/tester.js +0 -1
- package/dist/src/ai/tools.js +0 -1
- package/dist/src/api/api-client.js +0 -1
- package/dist/src/api/request-result.js +0 -1
- package/dist/src/api/request-store.js +0 -1
- package/dist/src/api/spec-reader.js +0 -1
- package/dist/src/api/xhr-capture.js +0 -1
- package/dist/src/browser-server.js +0 -1
- package/dist/src/command-handler.js +0 -1
- package/dist/src/commands/add-rule-command.js +0 -1
- package/dist/src/commands/base-command.js +0 -1
- package/dist/src/commands/clean-command.js +0 -1
- package/dist/src/commands/context-aria-command.js +0 -1
- package/dist/src/commands/context-command.js +0 -1
- package/dist/src/commands/context-data-command.js +0 -1
- package/dist/src/commands/context-experience-command.js +0 -1
- package/dist/src/commands/context-html-command.js +0 -1
- package/dist/src/commands/context-knowledge-command.js +0 -1
- package/dist/src/commands/debug-command.js +0 -1
- package/dist/src/commands/drill-command.js +0 -1
- package/dist/src/commands/exit-command.js +0 -1
- package/dist/src/commands/explore-command.js +2 -2
- package/dist/src/commands/freesail-command.js +0 -1
- package/dist/src/commands/help-command.js +0 -1
- package/dist/src/commands/index.js +0 -1
- package/dist/src/commands/init-command.js +115 -0
- package/dist/src/commands/knows-command.js +0 -1
- package/dist/src/commands/learn-command.js +0 -1
- package/dist/src/commands/navigate-command.js +0 -1
- package/dist/src/commands/path-command.js +0 -1
- package/dist/src/commands/plan-clear-command.js +0 -1
- package/dist/src/commands/plan-command.js +0 -1
- package/dist/src/commands/plan-edit-command.js +0 -1
- package/dist/src/commands/plan-load-command.js +0 -1
- package/dist/src/commands/plan-reload-command.js +0 -1
- package/dist/src/commands/plan-save-command.js +0 -1
- package/dist/src/commands/research-command.js +0 -1
- package/dist/src/commands/start-command.js +0 -1
- package/dist/src/commands/status-command.js +0 -1
- package/dist/src/commands/test-command.js +0 -1
- package/dist/src/components/ActivityPane.js +0 -1
- package/dist/src/components/AddKnowledge.js +0 -1
- package/dist/src/components/AddRule.js +0 -1
- package/dist/src/components/App.js +0 -1
- package/dist/src/components/Autocomplete.js +0 -1
- package/dist/src/components/InputPane.js +0 -1
- package/dist/src/components/InputReadline.js +0 -1
- package/dist/src/components/LogPane.js +0 -1
- package/dist/src/components/PlanEditor.js +0 -1
- package/dist/src/components/PlanPane.js +0 -1
- package/dist/src/components/SessionTimer.js +0 -1
- package/dist/src/components/StateTransitionPane.js +0 -1
- package/dist/src/components/StatusPane.js +0 -1
- package/dist/src/components/TaskPane.js +0 -1
- package/dist/src/components/Welcome.js +0 -1
- package/dist/src/components/WelcomeChecklist.js +0 -1
- package/dist/src/components/WelcomeCommands.js +0 -1
- package/dist/src/components/autocomplete-store.js +0 -1
- package/dist/src/components/parse-keypress.js +0 -1
- package/dist/src/config.js +0 -1
- package/dist/src/execution-controller.js +0 -1
- package/dist/src/experience-tracker.js +0 -1
- package/dist/src/explorbot.js +0 -1
- package/dist/src/explorer.js +0 -1
- package/dist/src/index.js +0 -1
- package/dist/src/knowledge-tracker.js +2 -2
- package/dist/src/observability.js +0 -1
- package/dist/src/reporter.js +0 -1
- package/dist/src/state-manager.js +0 -1
- package/dist/src/stats.js +0 -1
- package/dist/src/test-plan.js +0 -1
- package/dist/src/utils/aria.js +0 -1
- package/dist/src/utils/cli-name.js +16 -0
- package/dist/src/utils/code-extractor.js +0 -1
- package/dist/src/utils/context-formatter.js +0 -1
- package/dist/src/utils/error-page.js +0 -1
- package/dist/src/utils/expandable.js +0 -1
- package/dist/src/utils/hooks-runner.js +0 -1
- package/dist/src/utils/html-diff.js +0 -1
- package/dist/src/utils/html.js +0 -1
- package/dist/src/utils/logger.js +0 -1
- package/dist/src/utils/loop.js +0 -1
- package/dist/src/utils/markdown-parser.js +0 -1
- package/dist/src/utils/markdown-query.js +0 -1
- package/dist/src/utils/markdown-terminal.js +0 -1
- package/dist/src/utils/research-parser.js +0 -1
- package/dist/src/utils/retry.js +0 -1
- package/dist/src/utils/rules-loader.js +0 -1
- package/dist/src/utils/strings.js +0 -1
- package/dist/src/utils/test-plan-markdown.js +0 -1
- package/dist/src/utils/throttle.js +0 -1
- package/dist/src/utils/unique-names.js +0 -1
- package/dist/src/utils/url-matcher.js +0 -1
- package/dist/src/utils/web-element.js +0 -1
- package/dist/src/utils/xpath.js +0 -1
- package/package.json +27 -3
- package/src/action-result.ts +694 -0
- package/src/action.ts +445 -0
- package/src/activity.ts +111 -0
- package/src/ai/agent.ts +3 -0
- package/src/ai/bosun.ts +557 -0
- package/src/ai/captain/idle-mode.ts +116 -0
- package/src/ai/captain/mixin.ts +22 -0
- package/src/ai/captain/test-mode.ts +262 -0
- package/src/ai/captain/web-mode.ts +136 -0
- package/src/ai/captain.ts +504 -0
- package/src/ai/conversation.ts +205 -0
- package/src/ai/experience-compactor.ts +284 -0
- package/src/ai/fisherman-tools.ts +181 -0
- package/src/ai/fisherman.ts +223 -0
- package/src/ai/historian.ts +457 -0
- package/src/ai/navigator.ts +572 -0
- package/src/ai/pilot.ts +776 -0
- package/src/ai/planner/session-dedup.ts +35 -0
- package/src/ai/planner/styles.ts +17 -0
- package/src/ai/planner/subpages.ts +141 -0
- package/src/ai/planner.ts +536 -0
- package/src/ai/provider.ts +613 -0
- package/src/ai/quartermaster.ts +286 -0
- package/src/ai/researcher/cache.ts +103 -0
- package/src/ai/researcher/coordinates.ts +238 -0
- package/src/ai/researcher/deep-analysis.ts +415 -0
- package/src/ai/researcher/fingerprint-worker.ts +59 -0
- package/src/ai/researcher/focus.ts +42 -0
- package/src/ai/researcher/locators.ts +282 -0
- package/src/ai/researcher/mixin.ts +4 -0
- package/src/ai/researcher/parser.ts +186 -0
- package/src/ai/researcher/research-result.ts +115 -0
- package/src/ai/researcher.ts +857 -0
- package/src/ai/rules.ts +376 -0
- package/src/ai/task-agent.ts +141 -0
- package/src/ai/tester.ts +939 -0
- package/src/ai/tools.ts +1117 -0
- package/src/api/api-client.ts +109 -0
- package/src/api/request-result.ts +212 -0
- package/src/api/request-store.ts +130 -0
- package/src/api/spec-reader.ts +174 -0
- package/src/api/xhr-capture.ts +100 -0
- package/src/browser-server.ts +74 -0
- package/src/command-handler.ts +454 -0
- package/src/commands/add-rule-command.ts +63 -0
- package/src/commands/base-command.ts +27 -0
- package/src/commands/clean-command.ts +73 -0
- package/src/commands/context-aria-command.ts +22 -0
- package/src/commands/context-command.ts +67 -0
- package/src/commands/context-data-command.ts +30 -0
- package/src/commands/context-experience-command.ts +48 -0
- package/src/commands/context-html-command.ts +33 -0
- package/src/commands/context-knowledge-command.ts +43 -0
- package/src/commands/debug-command.ts +13 -0
- package/src/commands/drill-command.ts +34 -0
- package/src/commands/exit-command.ts +32 -0
- package/src/commands/explore-command.ts +129 -0
- package/src/commands/freesail-command.ts +95 -0
- package/src/commands/help-command.ts +8 -0
- package/src/commands/index.ts +69 -0
- package/src/commands/init-command.ts +128 -0
- package/src/commands/knows-command.ts +68 -0
- package/src/commands/learn-command.ts +44 -0
- package/src/commands/navigate-command.ts +18 -0
- package/src/commands/path-command.ts +83 -0
- package/src/commands/plan-clear-command.ts +14 -0
- package/src/commands/plan-command.ts +41 -0
- package/src/commands/plan-edit-command.ts +9 -0
- package/src/commands/plan-load-command.ts +18 -0
- package/src/commands/plan-reload-command.ts +28 -0
- package/src/commands/plan-save-command.ts +25 -0
- package/src/commands/research-command.ts +45 -0
- package/src/commands/start-command.ts +13 -0
- package/src/commands/status-command.tsx +23 -0
- package/src/commands/test-command.ts +84 -0
- package/src/components/ActivityPane.tsx +80 -0
- package/src/components/AddKnowledge.tsx +169 -0
- package/src/components/AddRule.tsx +174 -0
- package/src/components/App.tsx +377 -0
- package/src/components/Autocomplete.tsx +63 -0
- package/src/components/InputPane.tsx +259 -0
- package/src/components/InputReadline.tsx +704 -0
- package/src/components/LogPane.tsx +187 -0
- package/src/components/PlanEditor.tsx +150 -0
- package/src/components/PlanPane.tsx +71 -0
- package/src/components/SessionTimer.tsx +35 -0
- package/src/components/StateTransitionPane.tsx +149 -0
- package/src/components/StatusPane.tsx +62 -0
- package/src/components/TaskPane.tsx +119 -0
- package/src/components/Welcome.tsx +83 -0
- package/src/components/WelcomeChecklist.tsx +118 -0
- package/src/components/WelcomeCommands.tsx +102 -0
- package/src/components/autocomplete-store.ts +35 -0
- package/src/components/parse-keypress.ts +170 -0
- package/src/config.ts +490 -0
- package/src/execution-controller.ts +109 -0
- package/src/experience-tracker.ts +350 -0
- package/src/explorbot.ts +405 -0
- package/src/explorer.ts +713 -0
- package/src/index.tsx +62 -0
- package/src/knowledge-tracker.ts +230 -0
- package/src/observability.ts +150 -0
- package/src/reporter.ts +224 -0
- package/src/state-manager.ts +556 -0
- package/src/stats.ts +53 -0
- package/src/test-plan.ts +432 -0
- package/src/utils/aria.ts +629 -0
- package/src/utils/cli-name.ts +13 -0
- package/src/utils/code-extractor.ts +22 -0
- package/src/utils/context-formatter.ts +239 -0
- package/src/utils/error-page.ts +23 -0
- package/src/utils/expandable.ts +38 -0
- package/src/utils/hooks-runner.ts +79 -0
- package/src/utils/html-diff.ts +918 -0
- package/src/utils/html.ts +1316 -0
- package/src/utils/logger.ts +534 -0
- package/src/utils/loop.ts +176 -0
- package/src/utils/markdown-parser.ts +127 -0
- package/src/utils/markdown-query.ts +466 -0
- package/src/utils/markdown-terminal.ts +43 -0
- package/src/utils/research-parser.ts +11 -0
- package/src/utils/retry.ts +73 -0
- package/src/utils/rules-loader.ts +118 -0
- package/src/utils/strings.ts +13 -0
- package/src/utils/test-plan-markdown.ts +332 -0
- package/src/utils/throttle.ts +18 -0
- package/src/utils/unique-names.ts +14 -0
- package/src/utils/url-matcher.ts +45 -0
- package/src/utils/web-element.ts +145 -0
- package/src/utils/xpath.ts +129 -0
- package/dist/bin/explorbot-cli.js.map +0 -1
- package/dist/boat/api-tester/bin/apibot-cli.js.map +0 -1
- package/dist/boat/api-tester/example/apibot.config.js +0 -31
- package/dist/boat/api-tester/example/apibot.config.js.map +0 -1
- package/dist/boat/api-tester/src/ai/chief/styles.js.map +0 -1
- package/dist/boat/api-tester/src/ai/chief.js.map +0 -1
- package/dist/boat/api-tester/src/ai/curler-tools.js.map +0 -1
- package/dist/boat/api-tester/src/ai/curler.js.map +0 -1
- package/dist/boat/api-tester/src/api-client.js.map +0 -1
- package/dist/boat/api-tester/src/apibot.js.map +0 -1
- package/dist/boat/api-tester/src/cli.js.map +0 -1
- package/dist/boat/api-tester/src/config.js.map +0 -1
- package/dist/prompts/audit-rules.md +0 -124
- package/dist/src/action-result.js.map +0 -1
- package/dist/src/action.js.map +0 -1
- package/dist/src/activity.js.map +0 -1
- package/dist/src/ai/agent.js.map +0 -1
- package/dist/src/ai/bosun.js.map +0 -1
- package/dist/src/ai/captain/idle-mode.js.map +0 -1
- package/dist/src/ai/captain/mixin.js.map +0 -1
- package/dist/src/ai/captain/test-mode.js.map +0 -1
- package/dist/src/ai/captain/web-mode.js.map +0 -1
- package/dist/src/ai/captain.js.map +0 -1
- package/dist/src/ai/conversation.js.map +0 -1
- package/dist/src/ai/experience-compactor.js.map +0 -1
- package/dist/src/ai/fisherman-tools.js.map +0 -1
- package/dist/src/ai/fisherman.js.map +0 -1
- package/dist/src/ai/historian.js.map +0 -1
- package/dist/src/ai/navigator.js.map +0 -1
- package/dist/src/ai/pilot.js.map +0 -1
- package/dist/src/ai/planner/session-dedup.js.map +0 -1
- package/dist/src/ai/planner/styles.js.map +0 -1
- package/dist/src/ai/planner/subpages.js.map +0 -1
- package/dist/src/ai/planner.js.map +0 -1
- package/dist/src/ai/provider.js.map +0 -1
- package/dist/src/ai/quartermaster.js.map +0 -1
- package/dist/src/ai/researcher/cache.js.map +0 -1
- package/dist/src/ai/researcher/coordinates.js.map +0 -1
- package/dist/src/ai/researcher/deep-analysis.js.map +0 -1
- package/dist/src/ai/researcher/fingerprint-worker.js.map +0 -1
- package/dist/src/ai/researcher/focus.js.map +0 -1
- package/dist/src/ai/researcher/locators.js.map +0 -1
- package/dist/src/ai/researcher/mixin.js.map +0 -1
- package/dist/src/ai/researcher/parser.js.map +0 -1
- package/dist/src/ai/researcher/research-result.js.map +0 -1
- package/dist/src/ai/researcher.js.map +0 -1
- package/dist/src/ai/rules.js.map +0 -1
- package/dist/src/ai/task-agent.js.map +0 -1
- package/dist/src/ai/tester.js.map +0 -1
- package/dist/src/ai/tools.js.map +0 -1
- package/dist/src/api/api-client.js.map +0 -1
- package/dist/src/api/request-result.js.map +0 -1
- package/dist/src/api/request-store.js.map +0 -1
- package/dist/src/api/spec-reader.js.map +0 -1
- package/dist/src/api/xhr-capture.js.map +0 -1
- package/dist/src/browser-server.js.map +0 -1
- package/dist/src/command-handler.js.map +0 -1
- package/dist/src/commands/add-rule-command.js.map +0 -1
- package/dist/src/commands/base-command.js.map +0 -1
- package/dist/src/commands/clean-command.js.map +0 -1
- package/dist/src/commands/context-aria-command.js.map +0 -1
- package/dist/src/commands/context-command.js.map +0 -1
- package/dist/src/commands/context-data-command.js.map +0 -1
- package/dist/src/commands/context-experience-command.js.map +0 -1
- package/dist/src/commands/context-html-command.js.map +0 -1
- package/dist/src/commands/context-knowledge-command.js.map +0 -1
- package/dist/src/commands/debug-command.js.map +0 -1
- package/dist/src/commands/drill-command.js.map +0 -1
- package/dist/src/commands/exit-command.js.map +0 -1
- package/dist/src/commands/explore-command.js.map +0 -1
- package/dist/src/commands/freesail-command.js.map +0 -1
- package/dist/src/commands/help-command.js.map +0 -1
- package/dist/src/commands/index.js.map +0 -1
- package/dist/src/commands/knows-command.js.map +0 -1
- package/dist/src/commands/learn-command.js.map +0 -1
- package/dist/src/commands/navigate-command.js.map +0 -1
- package/dist/src/commands/path-command.js.map +0 -1
- package/dist/src/commands/plan-clear-command.js.map +0 -1
- package/dist/src/commands/plan-command.js.map +0 -1
- package/dist/src/commands/plan-edit-command.js.map +0 -1
- package/dist/src/commands/plan-load-command.js.map +0 -1
- package/dist/src/commands/plan-reload-command.js.map +0 -1
- package/dist/src/commands/plan-save-command.js.map +0 -1
- package/dist/src/commands/research-command.js.map +0 -1
- package/dist/src/commands/start-command.js.map +0 -1
- package/dist/src/commands/status-command.js.map +0 -1
- package/dist/src/commands/test-command.js.map +0 -1
- package/dist/src/components/ActivityPane.js.map +0 -1
- package/dist/src/components/AddKnowledge.js.map +0 -1
- package/dist/src/components/AddRule.js.map +0 -1
- package/dist/src/components/App.js.map +0 -1
- package/dist/src/components/Autocomplete.js.map +0 -1
- package/dist/src/components/InputPane.js.map +0 -1
- package/dist/src/components/InputReadline.js.map +0 -1
- package/dist/src/components/LogPane.js.map +0 -1
- package/dist/src/components/PlanEditor.js.map +0 -1
- package/dist/src/components/PlanPane.js.map +0 -1
- package/dist/src/components/SessionTimer.js.map +0 -1
- package/dist/src/components/StateTransitionPane.js.map +0 -1
- package/dist/src/components/StatusPane.js.map +0 -1
- package/dist/src/components/TaskPane.js.map +0 -1
- package/dist/src/components/Welcome.js.map +0 -1
- package/dist/src/components/WelcomeChecklist.js.map +0 -1
- package/dist/src/components/WelcomeCommands.js.map +0 -1
- package/dist/src/components/autocomplete-store.js.map +0 -1
- package/dist/src/components/parse-keypress.js.map +0 -1
- package/dist/src/config.js.map +0 -1
- package/dist/src/execution-controller.js.map +0 -1
- package/dist/src/experience-tracker.js.map +0 -1
- package/dist/src/explorbot.js.map +0 -1
- package/dist/src/explorer.js.map +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/knowledge-tracker.js.map +0 -1
- package/dist/src/observability.js.map +0 -1
- package/dist/src/reporter.js.map +0 -1
- package/dist/src/state-manager.js.map +0 -1
- package/dist/src/stats.js.map +0 -1
- package/dist/src/test-plan.js.map +0 -1
- package/dist/src/utils/aria.js.map +0 -1
- package/dist/src/utils/code-extractor.js.map +0 -1
- package/dist/src/utils/context-formatter.js.map +0 -1
- package/dist/src/utils/error-page.js.map +0 -1
- package/dist/src/utils/expandable.js.map +0 -1
- package/dist/src/utils/hooks-runner.js.map +0 -1
- package/dist/src/utils/html-diff.js.map +0 -1
- package/dist/src/utils/html.js.map +0 -1
- package/dist/src/utils/logger.js.map +0 -1
- package/dist/src/utils/loop.js.map +0 -1
- package/dist/src/utils/markdown-parser.js.map +0 -1
- package/dist/src/utils/markdown-query.js.map +0 -1
- package/dist/src/utils/markdown-terminal.js.map +0 -1
- package/dist/src/utils/research-parser.js.map +0 -1
- package/dist/src/utils/retry.js.map +0 -1
- package/dist/src/utils/rules-loader.js.map +0 -1
- package/dist/src/utils/strings.js.map +0 -1
- package/dist/src/utils/test-plan-markdown.js.map +0 -1
- package/dist/src/utils/throttle.js.map +0 -1
- package/dist/src/utils/unique-names.js.map +0 -1
- package/dist/src/utils/url-matcher.js.map +0 -1
- package/dist/src/utils/web-element.js.map +0 -1
- package/dist/src/utils/xpath.js.map +0 -1
- package/prompts/audit-rules.md +0 -124
package/src/config.ts
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
|
|
2
|
+
import path, { dirname, join, resolve } from 'node:path';
|
|
3
|
+
import { parseEnv } from 'node:util';
|
|
4
|
+
import { log } from './utils/logger.js';
|
|
5
|
+
|
|
6
|
+
interface PlaywrightConfig {
|
|
7
|
+
browser: 'chromium' | 'firefox' | 'webkit';
|
|
8
|
+
url: string;
|
|
9
|
+
show?: boolean;
|
|
10
|
+
windowSize?: string;
|
|
11
|
+
slowMo?: number;
|
|
12
|
+
chromium?: {
|
|
13
|
+
args?: string[];
|
|
14
|
+
};
|
|
15
|
+
firefox?: {
|
|
16
|
+
args?: string[];
|
|
17
|
+
};
|
|
18
|
+
webkit?: {
|
|
19
|
+
args?: string[];
|
|
20
|
+
};
|
|
21
|
+
timeout?: number;
|
|
22
|
+
waitForAction?: number;
|
|
23
|
+
waitForNavigation?: 'load' | 'domcontentloaded' | 'networkidle';
|
|
24
|
+
waitForTimeout?: number;
|
|
25
|
+
ignoreHTTPSErrors?: boolean;
|
|
26
|
+
userAgent?: string;
|
|
27
|
+
viewport?: {
|
|
28
|
+
width: number;
|
|
29
|
+
height: number;
|
|
30
|
+
};
|
|
31
|
+
args?: string[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type PlaywrightHookFn = (ctx: { page: any; url: string }) => Promise<void> | void;
|
|
35
|
+
type CodeceptJSHookFn = (ctx: { I: any; url: string }) => Promise<void> | void;
|
|
36
|
+
|
|
37
|
+
interface PlaywrightHook {
|
|
38
|
+
type: 'playwright';
|
|
39
|
+
hook: PlaywrightHookFn;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface CodeceptJSHook {
|
|
43
|
+
type: 'codeceptjs';
|
|
44
|
+
hook: CodeceptJSHookFn;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type Hook = PlaywrightHook | CodeceptJSHook;
|
|
48
|
+
type HookPatternMap = Record<string, Hook>;
|
|
49
|
+
type HookConfig = Hook | HookPatternMap;
|
|
50
|
+
|
|
51
|
+
interface HooksConfig {
|
|
52
|
+
beforeHook?: HookConfig;
|
|
53
|
+
afterHook?: HookConfig;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface AgentConfig extends HooksConfig {
|
|
57
|
+
model?: any;
|
|
58
|
+
enabled?: boolean;
|
|
59
|
+
systemPrompt?: string;
|
|
60
|
+
rules?: RuleEntry[];
|
|
61
|
+
providerOptions?: Record<string, any>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
interface ResearcherAgentConfig extends AgentConfig {
|
|
65
|
+
excludeSelectors?: string[];
|
|
66
|
+
includeSelectors?: string[];
|
|
67
|
+
stopWords?: string[];
|
|
68
|
+
maxElementsToExplore?: number;
|
|
69
|
+
maxExpandableClicks?: number;
|
|
70
|
+
retries?: number;
|
|
71
|
+
sections?: string[];
|
|
72
|
+
errorPageTimeout?: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface TesterAgentConfig extends AgentConfig {
|
|
76
|
+
progressCheckInterval?: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface PilotAgentConfig extends AgentConfig {
|
|
80
|
+
stepsToReview?: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface NavigatorAgentConfig extends AgentConfig {
|
|
84
|
+
addHtmlOnTry?: number;
|
|
85
|
+
maxAttempts?: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface PlannerAgentConfig extends AgentConfig {
|
|
89
|
+
styles?: string[];
|
|
90
|
+
stylesDir?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface AgentsConfig {
|
|
94
|
+
tester?: TesterAgentConfig;
|
|
95
|
+
navigator?: NavigatorAgentConfig;
|
|
96
|
+
researcher?: ResearcherAgentConfig;
|
|
97
|
+
planner?: PlannerAgentConfig;
|
|
98
|
+
pilot?: PilotAgentConfig;
|
|
99
|
+
'experience-compactor'?: AgentConfig;
|
|
100
|
+
captain?: AgentConfig;
|
|
101
|
+
quartermaster?: AgentConfig;
|
|
102
|
+
historian?: AgentConfig;
|
|
103
|
+
fisherman?: AgentConfig;
|
|
104
|
+
chief?: AgentConfig;
|
|
105
|
+
curler?: AgentConfig;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface AIConfig {
|
|
109
|
+
model: any;
|
|
110
|
+
apiKey?: string;
|
|
111
|
+
config?: Record<string, any>;
|
|
112
|
+
langfuse?: {
|
|
113
|
+
enabled?: boolean;
|
|
114
|
+
publicKey?: string;
|
|
115
|
+
secretKey?: string;
|
|
116
|
+
baseUrl?: string;
|
|
117
|
+
};
|
|
118
|
+
tools?: {
|
|
119
|
+
enabled: boolean;
|
|
120
|
+
maxConcurrency: number;
|
|
121
|
+
timeout: number;
|
|
122
|
+
};
|
|
123
|
+
vision?: boolean;
|
|
124
|
+
visionModel?: any;
|
|
125
|
+
agenticModel?: any;
|
|
126
|
+
maxAttempts?: number;
|
|
127
|
+
retryDelay?: number;
|
|
128
|
+
agents?: AgentsConfig;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
interface HtmlConfig {
|
|
132
|
+
minimal?: {
|
|
133
|
+
include?: string[];
|
|
134
|
+
exclude?: string[];
|
|
135
|
+
};
|
|
136
|
+
combined?: {
|
|
137
|
+
include?: string[];
|
|
138
|
+
exclude?: string[];
|
|
139
|
+
};
|
|
140
|
+
text?: {
|
|
141
|
+
include?: string[];
|
|
142
|
+
exclude?: string[];
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
interface ActionConfig {
|
|
147
|
+
delay?: number;
|
|
148
|
+
retries?: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface ReporterConfig {
|
|
152
|
+
enabled?: boolean;
|
|
153
|
+
html?: boolean;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
type ApiHookFn = (ctx: { headers: Record<string, string>; baseEndpoint: string }) => Promise<Record<string, string> | undefined> | Record<string, string> | undefined;
|
|
157
|
+
|
|
158
|
+
interface ApiConfig {
|
|
159
|
+
baseEndpoint?: string;
|
|
160
|
+
spec?: string[];
|
|
161
|
+
headers?: Record<string, string>;
|
|
162
|
+
bootstrap?: ApiHookFn;
|
|
163
|
+
teardown?: ApiHookFn;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
interface WebConfig {
|
|
167
|
+
url: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
interface ExplorbotConfig {
|
|
171
|
+
web?: WebConfig;
|
|
172
|
+
playwright: PlaywrightConfig;
|
|
173
|
+
ai: AIConfig;
|
|
174
|
+
html?: HtmlConfig;
|
|
175
|
+
action?: ActionConfig;
|
|
176
|
+
dirs?: {
|
|
177
|
+
knowledge: string;
|
|
178
|
+
experience: string;
|
|
179
|
+
output: string;
|
|
180
|
+
};
|
|
181
|
+
experience?: {
|
|
182
|
+
maxReadLines?: number;
|
|
183
|
+
};
|
|
184
|
+
reporter?: ReporterConfig;
|
|
185
|
+
api?: ApiConfig;
|
|
186
|
+
stepsFile?: string;
|
|
187
|
+
files?: Record<string, string>;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const config: ExplorbotConfig = {
|
|
191
|
+
playwright: {
|
|
192
|
+
browser: 'chromium',
|
|
193
|
+
url: 'http://localhost:3000',
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
ai: {
|
|
197
|
+
model: null as any,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
type RuleEntry = string | Record<string, string>;
|
|
202
|
+
|
|
203
|
+
export const EXPLORBOT_CONFIG_PATHS = ['explorbot.config.js', 'explorbot.config.mjs', 'explorbot.config.ts'];
|
|
204
|
+
|
|
205
|
+
export type {
|
|
206
|
+
ExplorbotConfig,
|
|
207
|
+
PlaywrightConfig,
|
|
208
|
+
AIConfig,
|
|
209
|
+
HtmlConfig,
|
|
210
|
+
ActionConfig,
|
|
211
|
+
AgentConfig,
|
|
212
|
+
AgentsConfig,
|
|
213
|
+
ResearcherAgentConfig,
|
|
214
|
+
NavigatorAgentConfig,
|
|
215
|
+
PlannerAgentConfig,
|
|
216
|
+
Hook,
|
|
217
|
+
HookConfig,
|
|
218
|
+
HooksConfig,
|
|
219
|
+
PlaywrightHook,
|
|
220
|
+
CodeceptJSHook,
|
|
221
|
+
HookPatternMap,
|
|
222
|
+
RuleEntry,
|
|
223
|
+
ReporterConfig,
|
|
224
|
+
ApiConfig,
|
|
225
|
+
WebConfig,
|
|
226
|
+
ApiHookFn,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
export class ConfigParser {
|
|
230
|
+
private static instance: ConfigParser;
|
|
231
|
+
private config: ExplorbotConfig | null = null;
|
|
232
|
+
private configPath: string | null = null;
|
|
233
|
+
|
|
234
|
+
private constructor() {}
|
|
235
|
+
|
|
236
|
+
public static loadEnv(filePath: string): void {
|
|
237
|
+
const resolved = resolve(filePath);
|
|
238
|
+
if (!existsSync(resolved)) return;
|
|
239
|
+
Object.assign(process.env, parseEnv(readFileSync(resolved, 'utf8')));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
public static getInstance(): ConfigParser {
|
|
243
|
+
if (!ConfigParser.instance) {
|
|
244
|
+
ConfigParser.instance = new ConfigParser();
|
|
245
|
+
}
|
|
246
|
+
return ConfigParser.instance;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
public async loadConfig(options?: {
|
|
250
|
+
config?: string;
|
|
251
|
+
path?: string;
|
|
252
|
+
}): Promise<ExplorbotConfig> {
|
|
253
|
+
if (this.config && !options?.config && !options?.path) {
|
|
254
|
+
return this.config;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Store the initial working directory for reference
|
|
258
|
+
if (!process.env.INITIAL_CWD) {
|
|
259
|
+
process.env.INITIAL_CWD = process.cwd();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const originalCwd = process.cwd();
|
|
263
|
+
if (options?.path) {
|
|
264
|
+
const resolvedWorkingPath = resolve(options.path);
|
|
265
|
+
process.chdir(resolvedWorkingPath);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
ConfigParser.loadEnv('.env');
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
const resolvedPath = options?.config || this.findConfigFile();
|
|
272
|
+
|
|
273
|
+
if (!resolvedPath) {
|
|
274
|
+
throw new Error('No configuration file found. Please create explorbot.config.js or explorbot.config.ts');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const configModule = await this.loadConfigModule(resolvedPath);
|
|
278
|
+
const loadedConfig = configModule.default || configModule;
|
|
279
|
+
|
|
280
|
+
if (!loadedConfig) {
|
|
281
|
+
throw new Error('Configuration file is empty or invalid');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
this.config = this.resolveConfig(loadedConfig as ExplorbotConfig);
|
|
285
|
+
this.configPath = resolvedPath;
|
|
286
|
+
|
|
287
|
+
log(`Configuration loaded from: ${resolvedPath}`);
|
|
288
|
+
|
|
289
|
+
// Restore original directory after successful config load
|
|
290
|
+
if (options?.path && originalCwd !== process.cwd()) {
|
|
291
|
+
process.chdir(originalCwd);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return this.config;
|
|
295
|
+
} catch (error) {
|
|
296
|
+
// Restore original directory on error
|
|
297
|
+
if (options?.path && originalCwd !== process.cwd()) {
|
|
298
|
+
process.chdir(originalCwd);
|
|
299
|
+
}
|
|
300
|
+
throw new Error(`Failed to load configuration: ${error}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
public getConfig(): ExplorbotConfig {
|
|
305
|
+
if (!this.config) {
|
|
306
|
+
throw new Error('Configuration not loaded. Call loadConfig() first.');
|
|
307
|
+
}
|
|
308
|
+
return this.config;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
public getConfigPath(): string | null {
|
|
312
|
+
return this.configPath;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
public getOutputDir(): string {
|
|
316
|
+
const config = this.getConfig();
|
|
317
|
+
const configPath = this.getConfigPath();
|
|
318
|
+
if (!configPath) throw new Error('Config path not found');
|
|
319
|
+
return path.join(path.dirname(configPath), config.dirs?.output || 'output');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
public getStatesDir(): string {
|
|
323
|
+
return outputPath('states');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
public getPlansDir(): string {
|
|
327
|
+
return outputPath('plans');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// For testing purposes only
|
|
331
|
+
public static resetForTesting(): void {
|
|
332
|
+
if (ConfigParser.instance) {
|
|
333
|
+
ConfigParser.instance.config = null;
|
|
334
|
+
ConfigParser.instance.configPath = null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// For testing purposes only - sets up minimal default config
|
|
339
|
+
public static setupTestConfig(): void {
|
|
340
|
+
const instance = ConfigParser.getInstance();
|
|
341
|
+
// Create unique directory names for this test run to ensure isolation
|
|
342
|
+
const testId = `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
343
|
+
const testBaseDir = join(process.cwd(), 'test-dirs', testId);
|
|
344
|
+
|
|
345
|
+
instance.config = {
|
|
346
|
+
playwright: {
|
|
347
|
+
url: 'https://example.com',
|
|
348
|
+
browser: 'chromium',
|
|
349
|
+
show: false,
|
|
350
|
+
},
|
|
351
|
+
ai: {
|
|
352
|
+
model: { modelId: 'test-model', provider: 'test' },
|
|
353
|
+
config: {},
|
|
354
|
+
vision: false,
|
|
355
|
+
},
|
|
356
|
+
dirs: {
|
|
357
|
+
knowledge: join(testBaseDir, 'knowledge'),
|
|
358
|
+
experience: join(testBaseDir, 'experience'),
|
|
359
|
+
output: join(testBaseDir, 'output'),
|
|
360
|
+
},
|
|
361
|
+
};
|
|
362
|
+
instance.configPath = join(testBaseDir, 'test-config');
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// For testing purposes only - get test directories for cleanup
|
|
366
|
+
public static getTestDirectories(): string[] {
|
|
367
|
+
const instance = ConfigParser.getInstance();
|
|
368
|
+
if (!instance.config?.dirs) return [];
|
|
369
|
+
|
|
370
|
+
return [instance.config.dirs.knowledge, instance.config.dirs.experience, instance.config.dirs.output, dirname(instance.configPath || '')].filter((dir) => dir?.includes('test-dirs'));
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// For testing purposes only - clean up all test directories
|
|
374
|
+
public static cleanupAllTestDirectories(): void {
|
|
375
|
+
try {
|
|
376
|
+
const testDirsBase = join(process.cwd(), 'test-dirs');
|
|
377
|
+
if (existsSync(testDirsBase)) {
|
|
378
|
+
rmSync(testDirsBase, { recursive: true, force: true });
|
|
379
|
+
}
|
|
380
|
+
} catch (error) {
|
|
381
|
+
// Ignore cleanup errors
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private findConfigFile(): string | null {
|
|
386
|
+
const possiblePaths = [...EXPLORBOT_CONFIG_PATHS, 'config/explorbot.config.js', 'config/explorbot.config.mjs', 'config/explorbot.config.ts', 'src/config/explorbot.config.js', 'src/config/explorbot.config.mjs', 'src/config/explorbot.config.ts'];
|
|
387
|
+
|
|
388
|
+
for (const path of possiblePaths) {
|
|
389
|
+
const fullPath = resolve(process.cwd(), path);
|
|
390
|
+
if (existsSync(fullPath)) {
|
|
391
|
+
return fullPath;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private async loadConfigModule(configPath: string): Promise<any> {
|
|
399
|
+
const ext = configPath.split('.').pop();
|
|
400
|
+
|
|
401
|
+
if (ext === 'ts') {
|
|
402
|
+
try {
|
|
403
|
+
const module = await import(configPath);
|
|
404
|
+
return module;
|
|
405
|
+
} catch (error) {
|
|
406
|
+
const require = (await import('node:module')).createRequire(import.meta.url);
|
|
407
|
+
return require(configPath);
|
|
408
|
+
}
|
|
409
|
+
} else if (ext === 'js' || ext === 'mjs') {
|
|
410
|
+
const module = await import(configPath);
|
|
411
|
+
return module;
|
|
412
|
+
} else {
|
|
413
|
+
const content = readFileSync(configPath, 'utf8');
|
|
414
|
+
return JSON.parse(content);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
private resolveConfig(config: ExplorbotConfig): ExplorbotConfig {
|
|
419
|
+
if (config.web?.url && !config.playwright?.url) {
|
|
420
|
+
config.playwright = config.playwright || { browser: 'chromium', url: '' };
|
|
421
|
+
config.playwright.url = config.web.url;
|
|
422
|
+
}
|
|
423
|
+
return config;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
public validateConfig(config: ExplorbotConfig): void {
|
|
427
|
+
if (!config.ai?.model) {
|
|
428
|
+
throw new Error('Missing required configuration field: ai.model');
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const url = config.playwright?.url || config.web?.url;
|
|
432
|
+
if (!url) {
|
|
433
|
+
throw new Error('Missing required configuration: web.url or playwright.url');
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
try {
|
|
437
|
+
new URL(url);
|
|
438
|
+
} catch {
|
|
439
|
+
throw new Error(`Invalid URL in configuration: ${url}`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
private getNestedValue(obj: any, path: string): any {
|
|
444
|
+
return path.split('.').reduce((current, key) => current?.[key], obj);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
public mergeWithDefaults(config: Partial<ExplorbotConfig>): ExplorbotConfig {
|
|
448
|
+
const defaults = {
|
|
449
|
+
playwright: {
|
|
450
|
+
browser: 'chromium',
|
|
451
|
+
show: false, // we need headless
|
|
452
|
+
},
|
|
453
|
+
action: {
|
|
454
|
+
delay: 1000,
|
|
455
|
+
retries: 3,
|
|
456
|
+
},
|
|
457
|
+
dirs: {
|
|
458
|
+
knowledge: 'knowledge',
|
|
459
|
+
experience: 'experience',
|
|
460
|
+
output: 'output',
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
return this.deepMerge(defaults, config);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
private deepMerge(target: any, source: any): any {
|
|
468
|
+
const result = { ...target };
|
|
469
|
+
|
|
470
|
+
for (const key in source) {
|
|
471
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key]) && source[key].constructor === Object) {
|
|
472
|
+
result[key] = this.deepMerge(result[key] || {}, source[key]);
|
|
473
|
+
} else {
|
|
474
|
+
result[key] = source[key];
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return result;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
public ensureDirectory(path: string): void {
|
|
482
|
+
if (!existsSync(path)) {
|
|
483
|
+
mkdirSync(path, { recursive: true });
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
export function outputPath(...segments: string[]): string {
|
|
489
|
+
return path.join(ConfigParser.getInstance().getOutputDir(), ...segments);
|
|
490
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import * as readline from 'node:readline';
|
|
3
|
+
import { clearActivity } from './activity.ts';
|
|
4
|
+
|
|
5
|
+
export type InputCallback = (prompt: string) => Promise<string | null>;
|
|
6
|
+
|
|
7
|
+
export class ExecutionController extends EventEmitter {
|
|
8
|
+
private static instance: ExecutionController;
|
|
9
|
+
private interrupted = false;
|
|
10
|
+
private inputCallback: InputCallback | null = null;
|
|
11
|
+
private interruptResolvers: Array<() => void> = [];
|
|
12
|
+
private abortController: AbortController | null = null;
|
|
13
|
+
|
|
14
|
+
private constructor() {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static getInstance(): ExecutionController {
|
|
19
|
+
if (!ExecutionController.instance) {
|
|
20
|
+
ExecutionController.instance = new ExecutionController();
|
|
21
|
+
}
|
|
22
|
+
return ExecutionController.instance;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setInputCallback(callback: InputCallback): void {
|
|
26
|
+
this.inputCallback = callback;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
startExecution(): void {
|
|
30
|
+
this.interrupted = false;
|
|
31
|
+
this.abortController = new AbortController();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getAbortSignal(): AbortSignal | undefined {
|
|
35
|
+
return this.abortController?.signal;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interrupt(): void {
|
|
39
|
+
clearActivity();
|
|
40
|
+
if (this.interrupted) return;
|
|
41
|
+
this.interrupted = true;
|
|
42
|
+
this.abortController?.abort();
|
|
43
|
+
this.emit('interrupt');
|
|
44
|
+
for (const resolve of this.interruptResolvers) {
|
|
45
|
+
resolve();
|
|
46
|
+
}
|
|
47
|
+
this.interruptResolvers = [];
|
|
48
|
+
this.emit('idle');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
isInterrupted(): boolean {
|
|
52
|
+
return this.interrupted;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
waitForInterrupt(): Promise<void> {
|
|
56
|
+
if (this.interrupted) {
|
|
57
|
+
return Promise.resolve();
|
|
58
|
+
}
|
|
59
|
+
return new Promise<void>((resolve) => {
|
|
60
|
+
this.interruptResolvers.push(resolve);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async checkInterrupt(): Promise<string | null> {
|
|
65
|
+
if (!this.interrupted) return null;
|
|
66
|
+
|
|
67
|
+
const userInput = await this.requestInput('Execution interrupted. What should we do instead?');
|
|
68
|
+
this.interrupted = false;
|
|
69
|
+
return userInput;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async handleInterrupt(prompt?: string): Promise<string | null> {
|
|
73
|
+
const message = prompt || 'Execution interrupted. Enter new instruction (or "stop"/"exit" to cancel):';
|
|
74
|
+
const userInput = await this.requestInput(message);
|
|
75
|
+
this.interrupted = false;
|
|
76
|
+
return userInput;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async requestInput(prompt: string): Promise<string | null> {
|
|
80
|
+
if (this.inputCallback) {
|
|
81
|
+
return await this.inputCallback(prompt);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return await this.readlineInput(prompt);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private async readlineInput(prompt: string): Promise<string | null> {
|
|
88
|
+
const rl = readline.createInterface({
|
|
89
|
+
input: process.stdin,
|
|
90
|
+
output: process.stdout,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return new Promise<string | null>((resolve) => {
|
|
94
|
+
rl.question(`${prompt}\n> `, (answer) => {
|
|
95
|
+
rl.close();
|
|
96
|
+
const trimmed = answer.trim();
|
|
97
|
+
resolve(trimmed || null);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
reset(): void {
|
|
103
|
+
this.interrupted = false;
|
|
104
|
+
this.interruptResolvers = [];
|
|
105
|
+
this.abortController = null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const executionController = ExecutionController.getInstance();
|