devharness 0.8.0
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/LICENSE +21 -0
- package/README.md +185 -0
- package/build/atomic-write.d.ts +28 -0
- package/build/atomic-write.d.ts.map +1 -0
- package/build/atomic-write.js +126 -0
- package/build/atomic-write.js.map +1 -0
- package/build/cdp-manager.d.ts +524 -0
- package/build/cdp-manager.d.ts.map +1 -0
- package/build/cdp-manager.js +1828 -0
- package/build/cdp-manager.js.map +1 -0
- package/build/cdp-manager.test.d.ts +6 -0
- package/build/cdp-manager.test.d.ts.map +1 -0
- package/build/cdp-manager.test.js +546 -0
- package/build/cdp-manager.test.js.map +1 -0
- package/build/chrome-launcher.d.ts +400 -0
- package/build/chrome-launcher.d.ts.map +1 -0
- package/build/chrome-launcher.js +1071 -0
- package/build/chrome-launcher.js.map +1 -0
- package/build/chrome-launcher.test.d.ts +11 -0
- package/build/chrome-launcher.test.d.ts.map +1 -0
- package/build/chrome-launcher.test.js +204 -0
- package/build/chrome-launcher.test.js.map +1 -0
- package/build/clickable-cache.d.ts +73 -0
- package/build/clickable-cache.d.ts.map +1 -0
- package/build/clickable-cache.js +90 -0
- package/build/clickable-cache.js.map +1 -0
- package/build/command-recorder.d.ts +401 -0
- package/build/command-recorder.d.ts.map +1 -0
- package/build/command-recorder.js +701 -0
- package/build/command-recorder.js.map +1 -0
- package/build/config.d.ts +390 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +826 -0
- package/build/config.js.map +1 -0
- package/build/config.test.d.ts +2 -0
- package/build/config.test.d.ts.map +1 -0
- package/build/config.test.js +112 -0
- package/build/config.test.js.map +1 -0
- package/build/connection-manager.d.ts +159 -0
- package/build/connection-manager.d.ts.map +1 -0
- package/build/connection-manager.js +432 -0
- package/build/connection-manager.js.map +1 -0
- package/build/connection-manager.test.d.ts +11 -0
- package/build/connection-manager.test.d.ts.map +1 -0
- package/build/connection-manager.test.js +114 -0
- package/build/connection-manager.test.js.map +1 -0
- package/build/console-monitor.d.ts +150 -0
- package/build/console-monitor.d.ts.map +1 -0
- package/build/console-monitor.js +454 -0
- package/build/console-monitor.js.map +1 -0
- package/build/dashboard/bundle.js +1 -0
- package/build/dashboard/dashboard-client.d.ts +42 -0
- package/build/dashboard/dashboard-client.d.ts.map +1 -0
- package/build/dashboard/dashboard-client.js +184 -0
- package/build/dashboard/dashboard-client.js.map +1 -0
- package/build/dashboard/dashboard-hub.d.ts +50 -0
- package/build/dashboard/dashboard-hub.d.ts.map +1 -0
- package/build/dashboard/dashboard-hub.js +654 -0
- package/build/dashboard/dashboard-hub.js.map +1 -0
- package/build/dashboard/hub-lock.d.ts +16 -0
- package/build/dashboard/hub-lock.d.ts.map +1 -0
- package/build/dashboard/hub-lock.js +77 -0
- package/build/dashboard/hub-lock.js.map +1 -0
- package/build/dashboard/index.d.ts +25 -0
- package/build/dashboard/index.d.ts.map +1 -0
- package/build/dashboard/index.js +77 -0
- package/build/dashboard/index.js.map +1 -0
- package/build/dashboard/types.d.ts +83 -0
- package/build/dashboard/types.d.ts.map +1 -0
- package/build/dashboard/types.js +6 -0
- package/build/dashboard/types.js.map +1 -0
- package/build/debug-logger.d.ts +85 -0
- package/build/debug-logger.d.ts.map +1 -0
- package/build/debug-logger.js +195 -0
- package/build/debug-logger.js.map +1 -0
- package/build/debugger-aware-wrapper.d.ts +37 -0
- package/build/debugger-aware-wrapper.d.ts.map +1 -0
- package/build/debugger-aware-wrapper.js +128 -0
- package/build/debugger-aware-wrapper.js.map +1 -0
- package/build/dom-change-monitor.d.ts +92 -0
- package/build/dom-change-monitor.d.ts.map +1 -0
- package/build/dom-change-monitor.js +437 -0
- package/build/dom-change-monitor.js.map +1 -0
- package/build/element-collector.d.ts +16 -0
- package/build/element-collector.d.ts.map +1 -0
- package/build/element-collector.js +207 -0
- package/build/element-collector.js.map +1 -0
- package/build/error-helpers.d.ts +43 -0
- package/build/error-helpers.d.ts.map +1 -0
- package/build/error-helpers.js +143 -0
- package/build/error-helpers.js.map +1 -0
- package/build/formatters/console-formatter.d.ts +160 -0
- package/build/formatters/console-formatter.d.ts.map +1 -0
- package/build/formatters/console-formatter.js +338 -0
- package/build/formatters/console-formatter.js.map +1 -0
- package/build/helpers/parser-plugins.d.ts +44 -0
- package/build/helpers/parser-plugins.d.ts.map +1 -0
- package/build/helpers/parser-plugins.js +102 -0
- package/build/helpers/parser-plugins.js.map +1 -0
- package/build/helpers/paths.d.ts +79 -0
- package/build/helpers/paths.d.ts.map +1 -0
- package/build/helpers/paths.js +168 -0
- package/build/helpers/paths.js.map +1 -0
- package/build/helpers/process-liveness.d.ts +24 -0
- package/build/helpers/process-liveness.d.ts.map +1 -0
- package/build/helpers/process-liveness.js +36 -0
- package/build/helpers/process-liveness.js.map +1 -0
- package/build/helpers/process-liveness.test.d.ts +2 -0
- package/build/helpers/process-liveness.test.d.ts.map +1 -0
- package/build/helpers/process-liveness.test.js +40 -0
- package/build/helpers/process-liveness.test.js.map +1 -0
- package/build/helpers/sequence-tree.d.ts +27 -0
- package/build/helpers/sequence-tree.d.ts.map +1 -0
- package/build/helpers/sequence-tree.js +80 -0
- package/build/helpers/sequence-tree.js.map +1 -0
- package/build/helpers/sequence-tree.test.d.ts +2 -0
- package/build/helpers/sequence-tree.test.d.ts.map +1 -0
- package/build/helpers/sequence-tree.test.js +122 -0
- package/build/helpers/sequence-tree.test.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +2007 -0
- package/build/index.js.map +1 -0
- package/build/interaction-recorder.d.ts +214 -0
- package/build/interaction-recorder.d.ts.map +1 -0
- package/build/interaction-recorder.js +2007 -0
- package/build/interaction-recorder.js.map +1 -0
- package/build/issue-tracker.d.ts +107 -0
- package/build/issue-tracker.d.ts.map +1 -0
- package/build/issue-tracker.js +582 -0
- package/build/issue-tracker.js.map +1 -0
- package/build/issue-tracker.test.d.ts +2 -0
- package/build/issue-tracker.test.d.ts.map +1 -0
- package/build/issue-tracker.test.js +88 -0
- package/build/issue-tracker.test.js.map +1 -0
- package/build/launch-chrome-port.test.d.ts +14 -0
- package/build/launch-chrome-port.test.d.ts.map +1 -0
- package/build/launch-chrome-port.test.js +97 -0
- package/build/launch-chrome-port.test.js.map +1 -0
- package/build/log-processor/orchestrator.d.ts +32 -0
- package/build/log-processor/orchestrator.d.ts.map +1 -0
- package/build/log-processor/orchestrator.js +27 -0
- package/build/log-processor/orchestrator.js.map +1 -0
- package/build/logpoint-execution-tracker.d.ts +57 -0
- package/build/logpoint-execution-tracker.d.ts.map +1 -0
- package/build/logpoint-execution-tracker.js +112 -0
- package/build/logpoint-execution-tracker.js.map +1 -0
- package/build/mcp-supervisor.d.ts +3 -0
- package/build/mcp-supervisor.d.ts.map +1 -0
- package/build/mcp-supervisor.js +211 -0
- package/build/mcp-supervisor.js.map +1 -0
- package/build/messages.d.ts +165 -0
- package/build/messages.d.ts.map +1 -0
- package/build/messages.js +574 -0
- package/build/messages.js.map +1 -0
- package/build/network-monitor.d.ts +172 -0
- package/build/network-monitor.d.ts.map +1 -0
- package/build/network-monitor.js +350 -0
- package/build/network-monitor.js.map +1 -0
- package/build/overlays.d.ts +49 -0
- package/build/overlays.d.ts.map +1 -0
- package/build/overlays.js +409 -0
- package/build/overlays.js.map +1 -0
- package/build/persistent-profiles.test.d.ts +15 -0
- package/build/persistent-profiles.test.d.ts.map +1 -0
- package/build/persistent-profiles.test.js +470 -0
- package/build/persistent-profiles.test.js.map +1 -0
- package/build/port-reserver.d.ts +32 -0
- package/build/port-reserver.d.ts.map +1 -0
- package/build/port-reserver.js +118 -0
- package/build/port-reserver.js.map +1 -0
- package/build/puppeteer-manager.d.ts +47 -0
- package/build/puppeteer-manager.d.ts.map +1 -0
- package/build/puppeteer-manager.js +116 -0
- package/build/puppeteer-manager.js.map +1 -0
- package/build/recording-coverage.test.d.ts +12 -0
- package/build/recording-coverage.test.d.ts.map +1 -0
- package/build/recording-coverage.test.js +72 -0
- package/build/recording-coverage.test.js.map +1 -0
- package/build/reference-validator.d.ts +47 -0
- package/build/reference-validator.d.ts.map +1 -0
- package/build/reference-validator.js +86 -0
- package/build/reference-validator.js.map +1 -0
- package/build/reference-validator.test.d.ts +5 -0
- package/build/reference-validator.test.d.ts.map +1 -0
- package/build/reference-validator.test.js +243 -0
- package/build/reference-validator.test.js.map +1 -0
- package/build/replay-cursor.d.ts +27 -0
- package/build/replay-cursor.d.ts.map +1 -0
- package/build/replay-cursor.js +240 -0
- package/build/replay-cursor.js.map +1 -0
- package/build/runners/docker-compose-runner.d.ts +69 -0
- package/build/runners/docker-compose-runner.d.ts.map +1 -0
- package/build/runners/docker-compose-runner.js +438 -0
- package/build/runners/docker-compose-runner.js.map +1 -0
- package/build/runners/docker-runner.d.ts +65 -0
- package/build/runners/docker-runner.d.ts.map +1 -0
- package/build/runners/docker-runner.js +414 -0
- package/build/runners/docker-runner.js.map +1 -0
- package/build/runners/index.d.ts +19 -0
- package/build/runners/index.d.ts.map +1 -0
- package/build/runners/index.js +35 -0
- package/build/runners/index.js.map +1 -0
- package/build/runners/native-runner.d.ts +95 -0
- package/build/runners/native-runner.d.ts.map +1 -0
- package/build/runners/native-runner.js +370 -0
- package/build/runners/native-runner.js.map +1 -0
- package/build/runners/types.d.ts +147 -0
- package/build/runners/types.d.ts.map +1 -0
- package/build/runners/types.js +25 -0
- package/build/runners/types.js.map +1 -0
- package/build/self-restart.d.ts +12 -0
- package/build/self-restart.d.ts.map +1 -0
- package/build/self-restart.js +41 -0
- package/build/self-restart.js.map +1 -0
- package/build/self-restart.test.d.ts +2 -0
- package/build/self-restart.test.d.ts.map +1 -0
- package/build/self-restart.test.js +34 -0
- package/build/self-restart.test.js.map +1 -0
- package/build/server-claims.d.ts +161 -0
- package/build/server-claims.d.ts.map +1 -0
- package/build/server-claims.js +382 -0
- package/build/server-claims.js.map +1 -0
- package/build/server-claims.test.d.ts +2 -0
- package/build/server-claims.test.d.ts.map +1 -0
- package/build/server-claims.test.js +197 -0
- package/build/server-claims.test.js.map +1 -0
- package/build/server-manager.d.ts +438 -0
- package/build/server-manager.d.ts.map +1 -0
- package/build/server-manager.js +1674 -0
- package/build/server-manager.js.map +1 -0
- package/build/server-manager.test.d.ts +17 -0
- package/build/server-manager.test.d.ts.map +1 -0
- package/build/server-manager.test.js +122 -0
- package/build/server-manager.test.js.map +1 -0
- package/build/server-ownership.test.d.ts +2 -0
- package/build/server-ownership.test.d.ts.map +1 -0
- package/build/server-ownership.test.js +238 -0
- package/build/server-ownership.test.js.map +1 -0
- package/build/server-watcher.d.ts +21 -0
- package/build/server-watcher.d.ts.map +1 -0
- package/build/server-watcher.js +105 -0
- package/build/server-watcher.js.map +1 -0
- package/build/session-detector.d.ts +47 -0
- package/build/session-detector.d.ts.map +1 -0
- package/build/session-detector.js +229 -0
- package/build/session-detector.js.map +1 -0
- package/build/session-detector.test.d.ts +9 -0
- package/build/session-detector.test.d.ts.map +1 -0
- package/build/session-detector.test.js +45 -0
- package/build/session-detector.test.js.map +1 -0
- package/build/sourcemap-handler.d.ts +114 -0
- package/build/sourcemap-handler.d.ts.map +1 -0
- package/build/sourcemap-handler.js +479 -0
- package/build/sourcemap-handler.js.map +1 -0
- package/build/supervisor/child-manager.d.ts +43 -0
- package/build/supervisor/child-manager.d.ts.map +1 -0
- package/build/supervisor/child-manager.js +148 -0
- package/build/supervisor/child-manager.js.map +1 -0
- package/build/supervisor/child-manager.test.d.ts +2 -0
- package/build/supervisor/child-manager.test.d.ts.map +1 -0
- package/build/supervisor/child-manager.test.js +107 -0
- package/build/supervisor/child-manager.test.js.map +1 -0
- package/build/supervisor/client-watcher.d.ts +48 -0
- package/build/supervisor/client-watcher.d.ts.map +1 -0
- package/build/supervisor/client-watcher.js +186 -0
- package/build/supervisor/client-watcher.js.map +1 -0
- package/build/supervisor/client-watcher.test.d.ts +2 -0
- package/build/supervisor/client-watcher.test.d.ts.map +1 -0
- package/build/supervisor/client-watcher.test.js +121 -0
- package/build/supervisor/client-watcher.test.js.map +1 -0
- package/build/supervisor/idle-config.d.ts +30 -0
- package/build/supervisor/idle-config.d.ts.map +1 -0
- package/build/supervisor/idle-config.js +76 -0
- package/build/supervisor/idle-config.js.map +1 -0
- package/build/supervisor/idle-config.test.d.ts +2 -0
- package/build/supervisor/idle-config.test.d.ts.map +1 -0
- package/build/supervisor/idle-config.test.js +119 -0
- package/build/supervisor/idle-config.test.js.map +1 -0
- package/build/supervisor/ndjson-reader.d.ts +47 -0
- package/build/supervisor/ndjson-reader.d.ts.map +1 -0
- package/build/supervisor/ndjson-reader.js +75 -0
- package/build/supervisor/ndjson-reader.js.map +1 -0
- package/build/supervisor/ndjson-reader.test.d.ts +2 -0
- package/build/supervisor/ndjson-reader.test.d.ts.map +1 -0
- package/build/supervisor/ndjson-reader.test.js +92 -0
- package/build/supervisor/ndjson-reader.test.js.map +1 -0
- package/build/supervisor/pidfile.d.ts +11 -0
- package/build/supervisor/pidfile.d.ts.map +1 -0
- package/build/supervisor/pidfile.js +29 -0
- package/build/supervisor/pidfile.js.map +1 -0
- package/build/supervisor/pidfile.test.d.ts +8 -0
- package/build/supervisor/pidfile.test.d.ts.map +1 -0
- package/build/supervisor/pidfile.test.js +46 -0
- package/build/supervisor/pidfile.test.js.map +1 -0
- package/build/supervisor/restart-coordinator.d.ts +73 -0
- package/build/supervisor/restart-coordinator.d.ts.map +1 -0
- package/build/supervisor/restart-coordinator.js +300 -0
- package/build/supervisor/restart-coordinator.js.map +1 -0
- package/build/supervisor/restart-coordinator.test.d.ts +2 -0
- package/build/supervisor/restart-coordinator.test.d.ts.map +1 -0
- package/build/supervisor/restart-coordinator.test.js +434 -0
- package/build/supervisor/restart-coordinator.test.js.map +1 -0
- package/build/test-support/fake-execute-tool-call.d.ts +11 -0
- package/build/test-support/fake-execute-tool-call.d.ts.map +1 -0
- package/build/test-support/fake-execute-tool-call.js +19 -0
- package/build/test-support/fake-execute-tool-call.js.map +1 -0
- package/build/tool-error.d.ts +14 -0
- package/build/tool-error.d.ts.map +1 -0
- package/build/tool-error.js +18 -0
- package/build/tool-error.js.map +1 -0
- package/build/tool-response.d.ts +293 -0
- package/build/tool-response.d.ts.map +1 -0
- package/build/tool-response.js +365 -0
- package/build/tool-response.js.map +1 -0
- package/build/tools/assert-tools.d.ts +62 -0
- package/build/tools/assert-tools.d.ts.map +1 -0
- package/build/tools/assert-tools.js +330 -0
- package/build/tools/assert-tools.js.map +1 -0
- package/build/tools/breakpoint-await-abort.test.d.ts +2 -0
- package/build/tools/breakpoint-await-abort.test.d.ts.map +1 -0
- package/build/tools/breakpoint-await-abort.test.js +124 -0
- package/build/tools/breakpoint-await-abort.test.js.map +1 -0
- package/build/tools/breakpoint-tools.d.ts +99 -0
- package/build/tools/breakpoint-tools.d.ts.map +1 -0
- package/build/tools/breakpoint-tools.js +1197 -0
- package/build/tools/breakpoint-tools.js.map +1 -0
- package/build/tools/config-tools.d.ts +58 -0
- package/build/tools/config-tools.d.ts.map +1 -0
- package/build/tools/config-tools.js +180 -0
- package/build/tools/config-tools.js.map +1 -0
- package/build/tools/connection-routing.test.d.ts +12 -0
- package/build/tools/connection-routing.test.d.ts.map +1 -0
- package/build/tools/connection-routing.test.js +206 -0
- package/build/tools/connection-routing.test.js.map +1 -0
- package/build/tools/console-tools.d.ts +84 -0
- package/build/tools/console-tools.d.ts.map +1 -0
- package/build/tools/console-tools.js +241 -0
- package/build/tools/console-tools.js.map +1 -0
- package/build/tools/content-tools.d.ts +74 -0
- package/build/tools/content-tools.d.ts.map +1 -0
- package/build/tools/content-tools.js +582 -0
- package/build/tools/content-tools.js.map +1 -0
- package/build/tools/dashboard-tools.d.ts +38 -0
- package/build/tools/dashboard-tools.d.ts.map +1 -0
- package/build/tools/dashboard-tools.js +123 -0
- package/build/tools/dashboard-tools.js.map +1 -0
- package/build/tools/dom-tools.d.ts +41 -0
- package/build/tools/dom-tools.d.ts.map +1 -0
- package/build/tools/dom-tools.js +277 -0
- package/build/tools/dom-tools.js.map +1 -0
- package/build/tools/download-tools.d.ts +55 -0
- package/build/tools/download-tools.d.ts.map +1 -0
- package/build/tools/download-tools.js +280 -0
- package/build/tools/download-tools.js.map +1 -0
- package/build/tools/execution-tools.d.ts +40 -0
- package/build/tools/execution-tools.d.ts.map +1 -0
- package/build/tools/execution-tools.js +121 -0
- package/build/tools/execution-tools.js.map +1 -0
- package/build/tools/input-abort.test.d.ts +2 -0
- package/build/tools/input-abort.test.d.ts.map +1 -0
- package/build/tools/input-abort.test.js +227 -0
- package/build/tools/input-abort.test.js.map +1 -0
- package/build/tools/input-ambiguous-selector.test.d.ts +2 -0
- package/build/tools/input-ambiguous-selector.test.d.ts.map +1 -0
- package/build/tools/input-ambiguous-selector.test.js +34 -0
- package/build/tools/input-ambiguous-selector.test.js.map +1 -0
- package/build/tools/input-tools.d.ts +168 -0
- package/build/tools/input-tools.d.ts.map +1 -0
- package/build/tools/input-tools.js +1397 -0
- package/build/tools/input-tools.js.map +1 -0
- package/build/tools/inspection-tools.d.ts +112 -0
- package/build/tools/inspection-tools.d.ts.map +1 -0
- package/build/tools/inspection-tools.js +637 -0
- package/build/tools/inspection-tools.js.map +1 -0
- package/build/tools/interpolation.d.ts +30 -0
- package/build/tools/interpolation.d.ts.map +1 -0
- package/build/tools/interpolation.js +143 -0
- package/build/tools/interpolation.js.map +1 -0
- package/build/tools/issues-abort-hygiene.test.d.ts +2 -0
- package/build/tools/issues-abort-hygiene.test.d.ts.map +1 -0
- package/build/tools/issues-abort-hygiene.test.js +79 -0
- package/build/tools/issues-abort-hygiene.test.js.map +1 -0
- package/build/tools/issues-tools.d.ts +98 -0
- package/build/tools/issues-tools.d.ts.map +1 -0
- package/build/tools/issues-tools.js +821 -0
- package/build/tools/issues-tools.js.map +1 -0
- package/build/tools/issues-tools.test.d.ts +8 -0
- package/build/tools/issues-tools.test.d.ts.map +1 -0
- package/build/tools/issues-tools.test.js +184 -0
- package/build/tools/issues-tools.test.js.map +1 -0
- package/build/tools/modal-tools.d.ts +73 -0
- package/build/tools/modal-tools.d.ts.map +1 -0
- package/build/tools/modal-tools.js +161 -0
- package/build/tools/modal-tools.js.map +1 -0
- package/build/tools/network-tools.d.ts +72 -0
- package/build/tools/network-tools.d.ts.map +1 -0
- package/build/tools/network-tools.js +432 -0
- package/build/tools/network-tools.js.map +1 -0
- package/build/tools/page-tools.d.ts +78 -0
- package/build/tools/page-tools.d.ts.map +1 -0
- package/build/tools/page-tools.js +255 -0
- package/build/tools/page-tools.js.map +1 -0
- package/build/tools/plugin-tools.d.ts +16 -0
- package/build/tools/plugin-tools.d.ts.map +1 -0
- package/build/tools/plugin-tools.js +17 -0
- package/build/tools/plugin-tools.js.map +1 -0
- package/build/tools/replay-abort.test.d.ts +2 -0
- package/build/tools/replay-abort.test.d.ts.map +1 -0
- package/build/tools/replay-abort.test.js +259 -0
- package/build/tools/replay-abort.test.js.map +1 -0
- package/build/tools/replay-add-conditional.test.d.ts +2 -0
- package/build/tools/replay-add-conditional.test.d.ts.map +1 -0
- package/build/tools/replay-add-conditional.test.js +205 -0
- package/build/tools/replay-add-conditional.test.js.map +1 -0
- package/build/tools/replay-background-run.test.d.ts +2 -0
- package/build/tools/replay-background-run.test.d.ts.map +1 -0
- package/build/tools/replay-background-run.test.js +176 -0
- package/build/tools/replay-background-run.test.js.map +1 -0
- package/build/tools/replay-capture-variables.test.d.ts +2 -0
- package/build/tools/replay-capture-variables.test.d.ts.map +1 -0
- package/build/tools/replay-capture-variables.test.js +331 -0
- package/build/tools/replay-capture-variables.test.js.map +1 -0
- package/build/tools/replay-conditional-idb-and-launch.test.d.ts +11 -0
- package/build/tools/replay-conditional-idb-and-launch.test.d.ts.map +1 -0
- package/build/tools/replay-conditional-idb-and-launch.test.js +429 -0
- package/build/tools/replay-conditional-idb-and-launch.test.js.map +1 -0
- package/build/tools/replay-conditional-timeout.test.d.ts +14 -0
- package/build/tools/replay-conditional-timeout.test.d.ts.map +1 -0
- package/build/tools/replay-conditional-timeout.test.js +126 -0
- package/build/tools/replay-conditional-timeout.test.js.map +1 -0
- package/build/tools/replay-declare.test.d.ts +2 -0
- package/build/tools/replay-declare.test.d.ts.map +1 -0
- package/build/tools/replay-declare.test.js +106 -0
- package/build/tools/replay-declare.test.js.map +1 -0
- package/build/tools/replay-declared-browser-cleanup.test.d.ts +2 -0
- package/build/tools/replay-declared-browser-cleanup.test.d.ts.map +1 -0
- package/build/tools/replay-declared-browser-cleanup.test.js +103 -0
- package/build/tools/replay-declared-browser-cleanup.test.js.map +1 -0
- package/build/tools/replay-declared-profile.test.d.ts +2 -0
- package/build/tools/replay-declared-profile.test.d.ts.map +1 -0
- package/build/tools/replay-declared-profile.test.js +116 -0
- package/build/tools/replay-declared-profile.test.js.map +1 -0
- package/build/tools/replay-executor.d.ts +556 -0
- package/build/tools/replay-executor.d.ts.map +1 -0
- package/build/tools/replay-executor.js +2347 -0
- package/build/tools/replay-executor.js.map +1 -0
- package/build/tools/replay-folder-save.test.d.ts +2 -0
- package/build/tools/replay-folder-save.test.d.ts.map +1 -0
- package/build/tools/replay-folder-save.test.js +63 -0
- package/build/tools/replay-folder-save.test.js.map +1 -0
- package/build/tools/replay-formatters.d.ts +148 -0
- package/build/tools/replay-formatters.d.ts.map +1 -0
- package/build/tools/replay-formatters.js +856 -0
- package/build/tools/replay-formatters.js.map +1 -0
- package/build/tools/replay-kill-chrome-on-finish.test.d.ts +2 -0
- package/build/tools/replay-kill-chrome-on-finish.test.d.ts.map +1 -0
- package/build/tools/replay-kill-chrome-on-finish.test.js +175 -0
- package/build/tools/replay-kill-chrome-on-finish.test.js.map +1 -0
- package/build/tools/replay-multi-connection.test.d.ts +2 -0
- package/build/tools/replay-multi-connection.test.d.ts.map +1 -0
- package/build/tools/replay-multi-connection.test.js +547 -0
- package/build/tools/replay-multi-connection.test.js.map +1 -0
- package/build/tools/replay-output-and-record-options.test.d.ts +2 -0
- package/build/tools/replay-output-and-record-options.test.d.ts.map +1 -0
- package/build/tools/replay-output-and-record-options.test.js +240 -0
- package/build/tools/replay-output-and-record-options.test.js.map +1 -0
- package/build/tools/replay-production-error-shape.test.d.ts +7 -0
- package/build/tools/replay-production-error-shape.test.d.ts.map +1 -0
- package/build/tools/replay-production-error-shape.test.js +93 -0
- package/build/tools/replay-production-error-shape.test.js.map +1 -0
- package/build/tools/replay-rebase.test.d.ts +2 -0
- package/build/tools/replay-rebase.test.d.ts.map +1 -0
- package/build/tools/replay-rebase.test.js +58 -0
- package/build/tools/replay-rebase.test.js.map +1 -0
- package/build/tools/replay-retry-classification.test.d.ts +9 -0
- package/build/tools/replay-retry-classification.test.d.ts.map +1 -0
- package/build/tools/replay-retry-classification.test.js +57 -0
- package/build/tools/replay-retry-classification.test.js.map +1 -0
- package/build/tools/replay-run-registry.d.ts +55 -0
- package/build/tools/replay-run-registry.d.ts.map +1 -0
- package/build/tools/replay-run-registry.js +65 -0
- package/build/tools/replay-run-registry.js.map +1 -0
- package/build/tools/replay-sequence-reload.test.d.ts +2 -0
- package/build/tools/replay-sequence-reload.test.d.ts.map +1 -0
- package/build/tools/replay-sequence-reload.test.js +82 -0
- package/build/tools/replay-sequence-reload.test.js.map +1 -0
- package/build/tools/replay-socket-scope.test.d.ts +2 -0
- package/build/tools/replay-socket-scope.test.d.ts.map +1 -0
- package/build/tools/replay-socket-scope.test.js +75 -0
- package/build/tools/replay-socket-scope.test.js.map +1 -0
- package/build/tools/replay-step-connection.test.d.ts +2 -0
- package/build/tools/replay-step-connection.test.d.ts.map +1 -0
- package/build/tools/replay-step-connection.test.js +292 -0
- package/build/tools/replay-step-connection.test.js.map +1 -0
- package/build/tools/replay-step-timeout.test.d.ts +2 -0
- package/build/tools/replay-step-timeout.test.d.ts.map +1 -0
- package/build/tools/replay-step-timeout.test.js +204 -0
- package/build/tools/replay-step-timeout.test.js.map +1 -0
- package/build/tools/replay-tags.test.d.ts +2 -0
- package/build/tools/replay-tags.test.d.ts.map +1 -0
- package/build/tools/replay-tags.test.js +99 -0
- package/build/tools/replay-tags.test.js.map +1 -0
- package/build/tools/replay-teardown-and-foreach.test.d.ts +13 -0
- package/build/tools/replay-teardown-and-foreach.test.d.ts.map +1 -0
- package/build/tools/replay-teardown-and-foreach.test.js +318 -0
- package/build/tools/replay-teardown-and-foreach.test.js.map +1 -0
- package/build/tools/replay-tool-name-validation.test.d.ts +2 -0
- package/build/tools/replay-tool-name-validation.test.d.ts.map +1 -0
- package/build/tools/replay-tool-name-validation.test.js +280 -0
- package/build/tools/replay-tool-name-validation.test.js.map +1 -0
- package/build/tools/replay-tools.d.ts +288 -0
- package/build/tools/replay-tools.d.ts.map +1 -0
- package/build/tools/replay-tools.js +2994 -0
- package/build/tools/replay-tools.js.map +1 -0
- package/build/tools/request-abort.test.d.ts +2 -0
- package/build/tools/request-abort.test.d.ts.map +1 -0
- package/build/tools/request-abort.test.js +130 -0
- package/build/tools/request-abort.test.js.map +1 -0
- package/build/tools/request-tools.d.ts +56 -0
- package/build/tools/request-tools.d.ts.map +1 -0
- package/build/tools/request-tools.js +174 -0
- package/build/tools/request-tools.js.map +1 -0
- package/build/tools/screenshot-tools.d.ts +135 -0
- package/build/tools/screenshot-tools.d.ts.map +1 -0
- package/build/tools/screenshot-tools.js +636 -0
- package/build/tools/screenshot-tools.js.map +1 -0
- package/build/tools/server-tools.d.ts +88 -0
- package/build/tools/server-tools.d.ts.map +1 -0
- package/build/tools/server-tools.js +485 -0
- package/build/tools/server-tools.js.map +1 -0
- package/build/tools/source-tools.d.ts +46 -0
- package/build/tools/source-tools.d.ts.map +1 -0
- package/build/tools/source-tools.js +47 -0
- package/build/tools/source-tools.js.map +1 -0
- package/build/tools/storage-tools.d.ts +141 -0
- package/build/tools/storage-tools.d.ts.map +1 -0
- package/build/tools/storage-tools.js +894 -0
- package/build/tools/storage-tools.js.map +1 -0
- package/build/tools/storage-tools.test.d.ts +13 -0
- package/build/tools/storage-tools.test.d.ts.map +1 -0
- package/build/tools/storage-tools.test.js +707 -0
- package/build/tools/storage-tools.test.js.map +1 -0
- package/build/tools/tab-tools.d.ts +42 -0
- package/build/tools/tab-tools.d.ts.map +1 -0
- package/build/tools/tab-tools.js +296 -0
- package/build/tools/tab-tools.js.map +1 -0
- package/build/tools/wait-tools.d.ts +85 -0
- package/build/tools/wait-tools.d.ts.map +1 -0
- package/build/tools/wait-tools.js +236 -0
- package/build/tools/wait-tools.js.map +1 -0
- package/build/tools/wait-tools.test.d.ts +9 -0
- package/build/tools/wait-tools.test.d.ts.map +1 -0
- package/build/tools/wait-tools.test.js +193 -0
- package/build/tools/wait-tools.test.js.map +1 -0
- package/build/types.d.ts +133 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +5 -0
- package/build/types.js.map +1 -0
- package/build/ui-verifier.d.ts +88 -0
- package/build/ui-verifier.d.ts.map +1 -0
- package/build/ui-verifier.js +540 -0
- package/build/ui-verifier.js.map +1 -0
- package/build/utils/abort.d.ts +68 -0
- package/build/utils/abort.d.ts.map +1 -0
- package/build/utils/abort.js +159 -0
- package/build/utils/abort.js.map +1 -0
- package/build/utils/abort.test.d.ts +2 -0
- package/build/utils/abort.test.d.ts.map +1 -0
- package/build/utils/abort.test.js +174 -0
- package/build/utils/abort.test.js.map +1 -0
- package/build/utils/modal-detection-core.d.ts +150 -0
- package/build/utils/modal-detection-core.d.ts.map +1 -0
- package/build/utils/modal-detection-core.js +332 -0
- package/build/utils/modal-detection-core.js.map +1 -0
- package/build/utils/modal-detection-core.test.d.ts +5 -0
- package/build/utils/modal-detection-core.test.d.ts.map +1 -0
- package/build/utils/modal-detection-core.test.js +492 -0
- package/build/utils/modal-detection-core.test.js.map +1 -0
- package/build/utils/modal-detector.d.ts +29 -0
- package/build/utils/modal-detector.d.ts.map +1 -0
- package/build/utils/modal-detector.js +281 -0
- package/build/utils/modal-detector.js.map +1 -0
- package/build/utils/modal-dismissal.d.ts +32 -0
- package/build/utils/modal-dismissal.d.ts.map +1 -0
- package/build/utils/modal-dismissal.js +190 -0
- package/build/utils/modal-dismissal.js.map +1 -0
- package/build/utils/port-check.d.ts +31 -0
- package/build/utils/port-check.d.ts.map +1 -0
- package/build/utils/port-check.js +87 -0
- package/build/utils/port-check.js.map +1 -0
- package/build/utils/port-check.test.d.ts +2 -0
- package/build/utils/port-check.test.d.ts.map +1 -0
- package/build/utils/port-check.test.js +66 -0
- package/build/utils/port-check.test.js.map +1 -0
- package/build/utils/selector-resolver.d.ts +66 -0
- package/build/utils/selector-resolver.d.ts.map +1 -0
- package/build/utils/selector-resolver.js +200 -0
- package/build/utils/selector-resolver.js.map +1 -0
- package/build/validation-helpers.d.ts +41 -0
- package/build/validation-helpers.d.ts.map +1 -0
- package/build/validation-helpers.js +236 -0
- package/build/validation-helpers.js.map +1 -0
- package/build/window-sizing.d.ts +26 -0
- package/build/window-sizing.d.ts.map +1 -0
- package/build/window-sizing.js +87 -0
- package/build/window-sizing.js.map +1 -0
- package/build/window-sizing.test.d.ts +8 -0
- package/build/window-sizing.test.d.ts.map +1 -0
- package/build/window-sizing.test.js +113 -0
- package/build/window-sizing.test.js.map +1 -0
- package/docs/README.md +74 -0
- package/docs/automation.md +562 -0
- package/docs/debugging.md +229 -0
- package/docs/installation.md +133 -0
- package/docs/instructions.md +227 -0
- package/docs/mcp-instructions.md +15 -0
- package/docs/message-system.md +327 -0
- package/docs/messages.md +3480 -0
- package/docs/parser-plugins.md +132 -0
- package/docs/replay.md +1411 -0
- package/docs/troubleshooting.md +272 -0
- package/docs/working_with_llm_notes.md +5 -0
- package/package.json +87 -0
- package/skills/devharness/SKILL.md +195 -0
- package/skills/devharness/references/sequences.md +613 -0
- package/skills/devharness/references/tool-categories.md +99 -0
package/build/config.js
ADDED
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Manager
|
|
3
|
+
* Manages user-editable configuration in .cdp-tools/config.json
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import { dirname, isAbsolute, join, resolve } from 'path';
|
|
7
|
+
import { homedir } from 'os';
|
|
8
|
+
import { getConfigSavePath, getOutputPath, setWorkingDirOverride } from './helpers/paths.js';
|
|
9
|
+
import { debugLog, enableDebugLogging, disableDebugLogging, isDebugEnabled, enableHistoryLogging, disableHistoryLogging, isHistoryLogEnabled, } from './debug-logger.js';
|
|
10
|
+
import { atomicWriteFile } from './atomic-write.js';
|
|
11
|
+
/**
|
|
12
|
+
* List of tools that can be toggled via config
|
|
13
|
+
* New tools added here will be auto-discovered and added to enabled list on startup
|
|
14
|
+
*/
|
|
15
|
+
export const TOGGLEABLE_TOOLS = [
|
|
16
|
+
'connection', // Core Chrome/debugger connection
|
|
17
|
+
'tab', // Tab management
|
|
18
|
+
'breakpoint', // Breakpoints, logpoints
|
|
19
|
+
'execution', // Pause, resume, step
|
|
20
|
+
'inspection', // Call stack, variables, evaluate
|
|
21
|
+
'source', // Source maps, code search
|
|
22
|
+
'console', // Console monitoring
|
|
23
|
+
'network', // Network monitoring
|
|
24
|
+
'page', // Navigation
|
|
25
|
+
'dom', // DOM queries
|
|
26
|
+
'screenshot', // Screenshots, PDF
|
|
27
|
+
'input', // Click, type, hover
|
|
28
|
+
'content', // Text extraction, interactive elements
|
|
29
|
+
'modal', // Modal detection/dismissal
|
|
30
|
+
'storage', // Cookies, localStorage
|
|
31
|
+
'download', // File downloads
|
|
32
|
+
'request', // HTTP requests (node or browser) as sequence steps
|
|
33
|
+
'assert', // Inline assertions as sequence steps (compare {{var:...}} values)
|
|
34
|
+
'wait', // Wait primitive for sequences (selector/expression polling, sleep)
|
|
35
|
+
'replay', // Sequence recording/playback
|
|
36
|
+
'server', // Dev server management
|
|
37
|
+
'issues', // Issue tracking
|
|
38
|
+
'dashboard', // Web dashboard for monitoring sessions
|
|
39
|
+
// Note: 'config' is NOT toggleable - always enabled
|
|
40
|
+
];
|
|
41
|
+
/**
|
|
42
|
+
* Tool dependencies - key depends on values
|
|
43
|
+
* If a dependency is disabled, the dependent tool cannot function
|
|
44
|
+
*/
|
|
45
|
+
export const TOOL_DEPENDENCIES = {
|
|
46
|
+
tab: ['connection'],
|
|
47
|
+
breakpoint: ['connection'],
|
|
48
|
+
execution: ['connection'],
|
|
49
|
+
inspection: ['connection'],
|
|
50
|
+
source: ['connection'],
|
|
51
|
+
console: ['connection'],
|
|
52
|
+
network: ['connection'],
|
|
53
|
+
page: ['connection'],
|
|
54
|
+
dom: ['connection'],
|
|
55
|
+
screenshot: ['connection'],
|
|
56
|
+
input: ['connection'],
|
|
57
|
+
content: ['connection'],
|
|
58
|
+
modal: ['connection'],
|
|
59
|
+
storage: ['connection'],
|
|
60
|
+
replay: ['connection', 'input', 'page'],
|
|
61
|
+
issues: ['replay'],
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Check for dependency conflicts in tools config
|
|
65
|
+
* Returns array of conflict descriptions (grouped by disabled dependency), empty if no conflicts
|
|
66
|
+
*/
|
|
67
|
+
export function checkToolDependencyConflicts(enabled, disabled) {
|
|
68
|
+
// Group dependents by their disabled dependency
|
|
69
|
+
const dependentsByDisabled = {};
|
|
70
|
+
for (const toolName of enabled) {
|
|
71
|
+
const deps = TOOL_DEPENDENCIES[toolName];
|
|
72
|
+
if (!deps)
|
|
73
|
+
continue;
|
|
74
|
+
for (const dep of deps) {
|
|
75
|
+
if (disabled.includes(dep)) {
|
|
76
|
+
if (!dependentsByDisabled[dep]) {
|
|
77
|
+
dependentsByDisabled[dep] = [];
|
|
78
|
+
}
|
|
79
|
+
dependentsByDisabled[dep].push(toolName);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Build conflict messages grouped by disabled dependency
|
|
84
|
+
const conflicts = [];
|
|
85
|
+
for (const [disabledTool, dependents] of Object.entries(dependentsByDisabled)) {
|
|
86
|
+
const count = dependents.length;
|
|
87
|
+
const toolWord = count === 1 ? 'tool' : 'tools';
|
|
88
|
+
const dependentsList = dependents.join(', ');
|
|
89
|
+
conflicts.push(`'${disabledTool}' is disabled but required for (${count}) ${toolWord}:\n\t${dependentsList}`);
|
|
90
|
+
}
|
|
91
|
+
return conflicts;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Default configuration values
|
|
95
|
+
*/
|
|
96
|
+
const DEFAULT_CONFIG = {
|
|
97
|
+
version: 1,
|
|
98
|
+
configLocation: 'local',
|
|
99
|
+
session: {
|
|
100
|
+
idleSuspendMinutes: 120, // Suspend after 2h of client silence (0 = never)
|
|
101
|
+
clientPollSeconds: 60, // Check the client is still alive every minute
|
|
102
|
+
},
|
|
103
|
+
chrome: {
|
|
104
|
+
startingDebugPort: 9222,
|
|
105
|
+
inactivityTimeoutMinutes: 5,
|
|
106
|
+
inactivityPollingMinutes: 2,
|
|
107
|
+
persistentProfileRoot: '', // '' = global ~/.cdp-tools/profiles
|
|
108
|
+
},
|
|
109
|
+
portMonitoring: {
|
|
110
|
+
portMonitoringFreqMs: {
|
|
111
|
+
block: 1000, // Fast detection for blocking
|
|
112
|
+
error: 2000, // Standard
|
|
113
|
+
inform: 5000, // Lower overhead for informational
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
replay: {
|
|
117
|
+
maxConditionalDepth: 10, // Maximum nesting depth for conditional commands
|
|
118
|
+
maxRegexLength: 500, // Maximum regex pattern length for url:matches
|
|
119
|
+
showCursor: true, // Show visual cursor during replay
|
|
120
|
+
playwrightExportPath: './tests/e2e', // Export path for Playwright tests
|
|
121
|
+
puppeteerExportPath: './tests/puppeteer', // Export path for Puppeteer tests
|
|
122
|
+
maxDelayMs: 1000, // Cap recorded delays at 1 second (0 = no limit)
|
|
123
|
+
},
|
|
124
|
+
changeDetection: {
|
|
125
|
+
enabled: true, // Detect DOM changes by default
|
|
126
|
+
settleTimeout: 2000, // Max wait for mutations to settle
|
|
127
|
+
quietPeriod: 300, // No mutations for 300ms = settled
|
|
128
|
+
navigationTimeout: 3000, // Longer timeout for page loads
|
|
129
|
+
},
|
|
130
|
+
clickValidation: {
|
|
131
|
+
enabled: true, // Enable click validation in replay
|
|
132
|
+
validateNavigation: true, // Check navigation success
|
|
133
|
+
requireDomChanges: false, // Don't require DOM mutations by default
|
|
134
|
+
domChangesFailMode: 'warn', // Just warn if no DOM changes
|
|
135
|
+
failOnConsoleErrors: true, // Check for console errors
|
|
136
|
+
consoleErrorsFailMode: 'error', // Fail on console errors
|
|
137
|
+
validateNetworkPayload: false, // Don't validate network by default
|
|
138
|
+
networkFailMode: 'warn', // Just warn on network failures
|
|
139
|
+
postClickDelayMs: 100, // Small delay before validation
|
|
140
|
+
},
|
|
141
|
+
debug: {
|
|
142
|
+
enabled: false, // Debug logging disabled by default
|
|
143
|
+
historyLogEnabled: false, // History log disabled by default
|
|
144
|
+
},
|
|
145
|
+
tools: {
|
|
146
|
+
enabled: ['issues'], // All tools enabled by default
|
|
147
|
+
disabled: [],
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Configuration Manager
|
|
152
|
+
* Loads and saves configuration from .cdp-tools/config.json
|
|
153
|
+
* Also tracks runtime port state
|
|
154
|
+
*/
|
|
155
|
+
export class ConfigManager {
|
|
156
|
+
config = { ...DEFAULT_CONFIG };
|
|
157
|
+
loaded = false;
|
|
158
|
+
loadedFromPath = null;
|
|
159
|
+
// Runtime port state (not persisted to config file)
|
|
160
|
+
currentPort = DEFAULT_CONFIG.chrome.startingDebugPort;
|
|
161
|
+
// Dependency conflict state - blocks all tool access if set
|
|
162
|
+
dependencyConflicts = [];
|
|
163
|
+
// Live-reload watcher state
|
|
164
|
+
configWatchers = [];
|
|
165
|
+
reloadTimer = null;
|
|
166
|
+
static RELOAD_DEBOUNCE_MS = 250;
|
|
167
|
+
constructor() {
|
|
168
|
+
// Sync load config at construction for early access (e.g., tool registration)
|
|
169
|
+
this.loadSync();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Synchronously load config for early access during module initialization
|
|
173
|
+
*/
|
|
174
|
+
loadSync() {
|
|
175
|
+
const localConfigPath = getOutputPath('config.json');
|
|
176
|
+
const globalConfigPath = join(homedir(), '.cdp-tools', 'config.json');
|
|
177
|
+
try {
|
|
178
|
+
if (fs.existsSync(localConfigPath)) {
|
|
179
|
+
const content = fs.readFileSync(localConfigPath, 'utf-8');
|
|
180
|
+
const loaded = JSON.parse(content);
|
|
181
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
182
|
+
this.loadedFromPath = localConfigPath;
|
|
183
|
+
this.loaded = true;
|
|
184
|
+
// Auto-discover new tools
|
|
185
|
+
if (this.discoverTools()) {
|
|
186
|
+
this.saveSync();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
// No local config - create one
|
|
191
|
+
// Seed from global if it exists, otherwise use defaults
|
|
192
|
+
if (fs.existsSync(globalConfigPath)) {
|
|
193
|
+
const content = fs.readFileSync(globalConfigPath, 'utf-8');
|
|
194
|
+
const loaded = JSON.parse(content);
|
|
195
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
199
|
+
}
|
|
200
|
+
// Auto-discover new tools (populates enabled list)
|
|
201
|
+
this.discoverTools();
|
|
202
|
+
// Save to local
|
|
203
|
+
this.loadedFromPath = this.getPreferredConfigPath();
|
|
204
|
+
this.saveSync();
|
|
205
|
+
this.loaded = true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Ignore errors, use defaults
|
|
210
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
211
|
+
this.discoverTools();
|
|
212
|
+
}
|
|
213
|
+
// Validate dependencies after config is fully loaded
|
|
214
|
+
this.validateDependencies();
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Validate tool dependencies and store any conflicts
|
|
218
|
+
*/
|
|
219
|
+
validateDependencies() {
|
|
220
|
+
this.dependencyConflicts = checkToolDependencyConflicts(this.config.tools.enabled, this.config.tools.disabled);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Check if there are dependency conflicts blocking tool access
|
|
224
|
+
*/
|
|
225
|
+
hasDependencyConflicts() {
|
|
226
|
+
return this.dependencyConflicts.length > 0;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get the list of dependency conflicts
|
|
230
|
+
*/
|
|
231
|
+
getDependencyConflicts() {
|
|
232
|
+
return [...this.dependencyConflicts];
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get preferred path for creating new config
|
|
236
|
+
* Prefers working directory if .cdp-tools folder exists or can be created
|
|
237
|
+
*/
|
|
238
|
+
getPreferredConfigPath() {
|
|
239
|
+
try {
|
|
240
|
+
const wdConfigPath = getOutputPath('config.json');
|
|
241
|
+
const wdBase = dirname(wdConfigPath);
|
|
242
|
+
// If .cdp-tools dir exists in working directory, use it
|
|
243
|
+
if (fs.existsSync(wdBase)) {
|
|
244
|
+
return wdConfigPath;
|
|
245
|
+
}
|
|
246
|
+
// Try to create .cdp-tools dir in working directory
|
|
247
|
+
fs.mkdirSync(wdBase, { recursive: true });
|
|
248
|
+
return wdConfigPath;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Fall back to global if working directory is not writable
|
|
252
|
+
return getConfigSavePath();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Load configuration from disk
|
|
257
|
+
* Checks local config first for configLocation preference.
|
|
258
|
+
* If configLocation is 'global', uses global config.
|
|
259
|
+
* Otherwise creates/uses local config (seeding from global if available).
|
|
260
|
+
*/
|
|
261
|
+
async load() {
|
|
262
|
+
const localConfigPath = getOutputPath('config.json');
|
|
263
|
+
const globalConfigPath = join(homedir(), '.cdp-tools', 'config.json');
|
|
264
|
+
try {
|
|
265
|
+
// Check if local config exists and has configLocation preference
|
|
266
|
+
if (fs.existsSync(localConfigPath)) {
|
|
267
|
+
const content = await fs.promises.readFile(localConfigPath, 'utf-8');
|
|
268
|
+
const loaded = JSON.parse(content);
|
|
269
|
+
// If local config says to use global, switch to global
|
|
270
|
+
if (loaded.configLocation === 'global' && fs.existsSync(globalConfigPath)) {
|
|
271
|
+
const globalContent = await fs.promises.readFile(globalConfigPath, 'utf-8');
|
|
272
|
+
const globalLoaded = JSON.parse(globalContent);
|
|
273
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, globalLoaded);
|
|
274
|
+
this.loadedFromPath = globalConfigPath;
|
|
275
|
+
// Auto-discover new tools
|
|
276
|
+
if (this.discoverTools()) {
|
|
277
|
+
await debugLog('ConfigManager', `Discovered new tools, updating config`);
|
|
278
|
+
}
|
|
279
|
+
await debugLog('ConfigManager', `Using global config (per local configLocation setting)`);
|
|
280
|
+
// Clean up local config to just have the pointer (atomic write)
|
|
281
|
+
await atomicWriteFile(localConfigPath, JSON.stringify({ configLocation: 'global' }, null, 2));
|
|
282
|
+
await this.save();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
// Use local config
|
|
286
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
287
|
+
this.loadedFromPath = localConfigPath;
|
|
288
|
+
// Auto-discover new tools
|
|
289
|
+
if (this.discoverTools()) {
|
|
290
|
+
await debugLog('ConfigManager', `Discovered new tools, updating config`);
|
|
291
|
+
}
|
|
292
|
+
await debugLog('ConfigManager', `Loaded config from ${localConfigPath}`);
|
|
293
|
+
await this.save();
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
// No local config - create one
|
|
297
|
+
// Seed from global if it exists, otherwise use defaults
|
|
298
|
+
if (fs.existsSync(globalConfigPath)) {
|
|
299
|
+
const content = await fs.promises.readFile(globalConfigPath, 'utf-8');
|
|
300
|
+
const loaded = JSON.parse(content);
|
|
301
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
302
|
+
await debugLog('ConfigManager', `Seeding local config from global ${globalConfigPath}`);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
306
|
+
}
|
|
307
|
+
// Auto-discover new tools
|
|
308
|
+
if (this.discoverTools()) {
|
|
309
|
+
await debugLog('ConfigManager', `Discovered new tools, updating config`);
|
|
310
|
+
}
|
|
311
|
+
// Save to local (getPreferredConfigPath will fall back to global if local not writable)
|
|
312
|
+
this.loadedFromPath = this.getPreferredConfigPath();
|
|
313
|
+
await this.save();
|
|
314
|
+
await debugLog('ConfigManager', `Created config at ${this.loadedFromPath}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
await debugLog('ConfigManager', `Failed to load config: ${err}, using defaults`);
|
|
319
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
320
|
+
this.loadedFromPath = null;
|
|
321
|
+
}
|
|
322
|
+
// Validate dependencies after config is fully loaded
|
|
323
|
+
this.validateDependencies();
|
|
324
|
+
if (this.hasDependencyConflicts()) {
|
|
325
|
+
await debugLog('ConfigManager', `Tool dependency conflicts detected: ${this.dependencyConflicts.join(', ')}`);
|
|
326
|
+
}
|
|
327
|
+
this.loaded = true;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Re-read config.json from disk and apply it to the running process.
|
|
331
|
+
* Unlike load(), this never writes back (no discover-and-persist) - it's
|
|
332
|
+
* meant to pick up a manual edit live, not to run the one-time bootstrap,
|
|
333
|
+
* and writing back here would re-trigger the file watcher that calls it.
|
|
334
|
+
*/
|
|
335
|
+
async reload() {
|
|
336
|
+
const localConfigPath = getOutputPath('config.json');
|
|
337
|
+
const globalConfigPath = join(homedir(), '.cdp-tools', 'config.json');
|
|
338
|
+
const previousSnapshot = JSON.stringify(this.config);
|
|
339
|
+
const previousDebug = { ...this.config.debug };
|
|
340
|
+
let nextConfig;
|
|
341
|
+
let nextPath;
|
|
342
|
+
try {
|
|
343
|
+
if (fs.existsSync(localConfigPath)) {
|
|
344
|
+
const content = await fs.promises.readFile(localConfigPath, 'utf-8');
|
|
345
|
+
const loaded = JSON.parse(content);
|
|
346
|
+
if (loaded.configLocation === 'global' && fs.existsSync(globalConfigPath)) {
|
|
347
|
+
const globalContent = await fs.promises.readFile(globalConfigPath, 'utf-8');
|
|
348
|
+
nextConfig = this.mergeConfig(DEFAULT_CONFIG, JSON.parse(globalContent));
|
|
349
|
+
nextPath = globalConfigPath;
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
nextConfig = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
353
|
+
nextPath = localConfigPath;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
else if (fs.existsSync(globalConfigPath)) {
|
|
357
|
+
const content = await fs.promises.readFile(globalConfigPath, 'utf-8');
|
|
358
|
+
nextConfig = this.mergeConfig(DEFAULT_CONFIG, JSON.parse(content));
|
|
359
|
+
nextPath = globalConfigPath;
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// Nothing on disk (e.g. deleted) - keep the current in-memory config.
|
|
363
|
+
return { changed: false, path: this.loadedFromPath };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
catch (err) {
|
|
367
|
+
await debugLog('ConfigManager', `Config reload failed: ${err}`);
|
|
368
|
+
return { changed: false, path: this.loadedFromPath };
|
|
369
|
+
}
|
|
370
|
+
this.config = nextConfig;
|
|
371
|
+
this.loadedFromPath = nextPath;
|
|
372
|
+
this.validateDependencies();
|
|
373
|
+
const changed = JSON.stringify(this.config) !== previousSnapshot;
|
|
374
|
+
if (changed) {
|
|
375
|
+
await debugLog('ConfigManager', `Config reloaded from ${nextPath}`);
|
|
376
|
+
this.applyLiveDebugSettings(previousDebug);
|
|
377
|
+
}
|
|
378
|
+
return { changed, path: nextPath };
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* debug.enabled/historyLogEnabled are otherwise only applied once at
|
|
382
|
+
* server startup (see main() in index.ts) - mirror that here so a live
|
|
383
|
+
* edit actually flips debug-logger.ts's module state.
|
|
384
|
+
*/
|
|
385
|
+
applyLiveDebugSettings(previousDebug) {
|
|
386
|
+
const next = this.config.debug;
|
|
387
|
+
if (next.enabled !== previousDebug.enabled) {
|
|
388
|
+
if (next.enabled && !isDebugEnabled()) {
|
|
389
|
+
void enableDebugLogging();
|
|
390
|
+
}
|
|
391
|
+
else if (!next.enabled && isDebugEnabled()) {
|
|
392
|
+
disableDebugLogging();
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (next.historyLogEnabled !== previousDebug.historyLogEnabled) {
|
|
396
|
+
if (next.historyLogEnabled && !isHistoryLogEnabled()) {
|
|
397
|
+
enableHistoryLogging();
|
|
398
|
+
}
|
|
399
|
+
else if (!next.historyLogEnabled && isHistoryLogEnabled()) {
|
|
400
|
+
disableHistoryLogging();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Watch the local and global config directories for edits and hot-reload
|
|
406
|
+
* config.json into the running process. Watches the parent directory
|
|
407
|
+
* (not the file itself) and ignores the event payload, debouncing to a
|
|
408
|
+
* full reload() - same pattern as issue-tracker.ts's watcher, and safe
|
|
409
|
+
* against atomic saves (write-temp + rename) losing the watch descriptor.
|
|
410
|
+
*
|
|
411
|
+
* Note: tools.enabled/tools.disabled cannot be hot-applied this way - the
|
|
412
|
+
* MCP tool list is built once at server startup. Everything else this
|
|
413
|
+
* class exposes (portMonitoring, replay, changeDetection, clickValidation,
|
|
414
|
+
* debug) is read live from getConfig() and picks up a reload immediately.
|
|
415
|
+
*/
|
|
416
|
+
startWatching() {
|
|
417
|
+
if (this.configWatchers.length > 0)
|
|
418
|
+
return;
|
|
419
|
+
const dirsToWatch = new Set([
|
|
420
|
+
dirname(getOutputPath('config.json')),
|
|
421
|
+
dirname(join(homedir(), '.cdp-tools', 'config.json')),
|
|
422
|
+
]);
|
|
423
|
+
for (const dir of dirsToWatch) {
|
|
424
|
+
try {
|
|
425
|
+
const watcher = fs.watch(dir, () => this.scheduleReload());
|
|
426
|
+
this.configWatchers.push(watcher);
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
// Directory doesn't exist yet / not watchable on this platform - skip silently.
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
stopWatching() {
|
|
434
|
+
for (const watcher of this.configWatchers) {
|
|
435
|
+
watcher.close();
|
|
436
|
+
}
|
|
437
|
+
this.configWatchers = [];
|
|
438
|
+
if (this.reloadTimer) {
|
|
439
|
+
clearTimeout(this.reloadTimer);
|
|
440
|
+
this.reloadTimer = null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Coalesce a burst of filesystem events into one reload, firing a fixed
|
|
445
|
+
* window after the FIRST event rather than the last.
|
|
446
|
+
*
|
|
447
|
+
* This used to clear and re-arm the timer on every event, which is the
|
|
448
|
+
* textbook debounce - and the wrong shape here. startWatching() watches the
|
|
449
|
+
* global ~/.cdp-tools directory as well as the project one, and that
|
|
450
|
+
* directory is shared by every cdp-tools process on the machine (dashboard
|
|
451
|
+
* locks, downloads, sequences). Under sustained unrelated writes there, the
|
|
452
|
+
* timer was reset before it could ever fire, so an edit to config.json was
|
|
453
|
+
* postponed indefinitely - live reload silently stopped working, and stayed
|
|
454
|
+
* broken for as long as the other process kept writing.
|
|
455
|
+
*
|
|
456
|
+
* Firing from the first event bounds the latency at RELOAD_DEBOUNCE_MS no
|
|
457
|
+
* matter how busy the directory is, while still collapsing the rapid
|
|
458
|
+
* write/rename pairs an atomic save produces.
|
|
459
|
+
*/
|
|
460
|
+
scheduleReload() {
|
|
461
|
+
if (this.reloadTimer)
|
|
462
|
+
return;
|
|
463
|
+
this.reloadTimer = setTimeout(() => {
|
|
464
|
+
this.reloadTimer = null;
|
|
465
|
+
void this.reload();
|
|
466
|
+
}, ConfigManager.RELOAD_DEBOUNCE_MS);
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Deep merge two config objects
|
|
470
|
+
*/
|
|
471
|
+
mergeConfig(defaults, loaded) {
|
|
472
|
+
return {
|
|
473
|
+
version: loaded.version ?? defaults.version,
|
|
474
|
+
configLocation: loaded.configLocation ?? defaults.configLocation,
|
|
475
|
+
session: {
|
|
476
|
+
idleSuspendMinutes: loaded.session?.idleSuspendMinutes ?? defaults.session.idleSuspendMinutes,
|
|
477
|
+
clientPollSeconds: loaded.session?.clientPollSeconds ?? defaults.session.clientPollSeconds,
|
|
478
|
+
},
|
|
479
|
+
chrome: {
|
|
480
|
+
startingDebugPort: loaded.chrome?.startingDebugPort ?? defaults.chrome.startingDebugPort,
|
|
481
|
+
inactivityTimeoutMinutes: loaded.chrome?.inactivityTimeoutMinutes ?? defaults.chrome.inactivityTimeoutMinutes,
|
|
482
|
+
inactivityPollingMinutes: loaded.chrome?.inactivityPollingMinutes ?? defaults.chrome.inactivityPollingMinutes,
|
|
483
|
+
persistentProfileRoot: loaded.chrome?.persistentProfileRoot ?? defaults.chrome.persistentProfileRoot,
|
|
484
|
+
},
|
|
485
|
+
portMonitoring: {
|
|
486
|
+
portMonitoringFreqMs: {
|
|
487
|
+
block: loaded.portMonitoring?.portMonitoringFreqMs?.block ?? defaults.portMonitoring.portMonitoringFreqMs.block,
|
|
488
|
+
error: loaded.portMonitoring?.portMonitoringFreqMs?.error ?? defaults.portMonitoring.portMonitoringFreqMs.error,
|
|
489
|
+
inform: loaded.portMonitoring?.portMonitoringFreqMs?.inform ?? defaults.portMonitoring.portMonitoringFreqMs.inform,
|
|
490
|
+
},
|
|
491
|
+
},
|
|
492
|
+
replay: {
|
|
493
|
+
maxConditionalDepth: loaded.replay?.maxConditionalDepth ?? defaults.replay.maxConditionalDepth,
|
|
494
|
+
maxRegexLength: loaded.replay?.maxRegexLength ?? defaults.replay.maxRegexLength,
|
|
495
|
+
showCursor: loaded.replay?.showCursor ?? defaults.replay.showCursor,
|
|
496
|
+
playwrightExportPath: loaded.replay?.playwrightExportPath ?? defaults.replay.playwrightExportPath,
|
|
497
|
+
puppeteerExportPath: loaded.replay?.puppeteerExportPath ?? defaults.replay.puppeteerExportPath,
|
|
498
|
+
maxDelayMs: loaded.replay?.maxDelayMs ?? defaults.replay.maxDelayMs,
|
|
499
|
+
},
|
|
500
|
+
changeDetection: {
|
|
501
|
+
enabled: loaded.changeDetection?.enabled ?? defaults.changeDetection.enabled,
|
|
502
|
+
settleTimeout: loaded.changeDetection?.settleTimeout ?? defaults.changeDetection.settleTimeout,
|
|
503
|
+
quietPeriod: loaded.changeDetection?.quietPeriod ?? defaults.changeDetection.quietPeriod,
|
|
504
|
+
navigationTimeout: loaded.changeDetection?.navigationTimeout ?? defaults.changeDetection.navigationTimeout,
|
|
505
|
+
},
|
|
506
|
+
clickValidation: {
|
|
507
|
+
enabled: loaded.clickValidation?.enabled ?? defaults.clickValidation.enabled,
|
|
508
|
+
validateNavigation: loaded.clickValidation?.validateNavigation ?? defaults.clickValidation.validateNavigation,
|
|
509
|
+
requireDomChanges: loaded.clickValidation?.requireDomChanges ?? defaults.clickValidation.requireDomChanges,
|
|
510
|
+
domChangesFailMode: loaded.clickValidation?.domChangesFailMode ?? defaults.clickValidation.domChangesFailMode,
|
|
511
|
+
failOnConsoleErrors: loaded.clickValidation?.failOnConsoleErrors ?? defaults.clickValidation.failOnConsoleErrors,
|
|
512
|
+
consoleErrorsFailMode: loaded.clickValidation?.consoleErrorsFailMode ?? defaults.clickValidation.consoleErrorsFailMode,
|
|
513
|
+
validateNetworkPayload: loaded.clickValidation?.validateNetworkPayload ?? defaults.clickValidation.validateNetworkPayload,
|
|
514
|
+
networkFailMode: loaded.clickValidation?.networkFailMode ?? defaults.clickValidation.networkFailMode,
|
|
515
|
+
postClickDelayMs: loaded.clickValidation?.postClickDelayMs ?? defaults.clickValidation.postClickDelayMs,
|
|
516
|
+
},
|
|
517
|
+
debug: {
|
|
518
|
+
enabled: loaded.debug?.enabled ?? defaults.debug.enabled,
|
|
519
|
+
historyLogEnabled: loaded.debug?.historyLogEnabled ?? defaults.debug.historyLogEnabled,
|
|
520
|
+
},
|
|
521
|
+
tools: {
|
|
522
|
+
enabled: loaded.tools?.enabled ?? defaults.tools.enabled,
|
|
523
|
+
disabled: loaded.tools?.disabled ?? defaults.tools.disabled,
|
|
524
|
+
},
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Save configuration to disk
|
|
529
|
+
* Saves to the same location it was loaded from, or global if new
|
|
530
|
+
*/
|
|
531
|
+
async save() {
|
|
532
|
+
const configPath = this.loadedFromPath || getConfigSavePath();
|
|
533
|
+
// Atomic write handles directory creation and prevents corruption
|
|
534
|
+
await atomicWriteFile(configPath, JSON.stringify(this.config, null, 2));
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Synchronously save configuration to disk
|
|
538
|
+
* Used during loadSync() to persist config before async code runs
|
|
539
|
+
*/
|
|
540
|
+
saveSync() {
|
|
541
|
+
const configPath = this.loadedFromPath || getConfigSavePath();
|
|
542
|
+
const dir = dirname(configPath);
|
|
543
|
+
if (!fs.existsSync(dir)) {
|
|
544
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
545
|
+
}
|
|
546
|
+
fs.writeFileSync(configPath, JSON.stringify(this.config, null, 2), 'utf-8');
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Get the full configuration
|
|
550
|
+
*/
|
|
551
|
+
getConfig() {
|
|
552
|
+
if (!this.loaded) {
|
|
553
|
+
// Synchronous fallback - return defaults
|
|
554
|
+
return { ...DEFAULT_CONFIG };
|
|
555
|
+
}
|
|
556
|
+
return this.config;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Get port monitoring configuration
|
|
560
|
+
*/
|
|
561
|
+
getPortMonitoringConfig() {
|
|
562
|
+
return this.getConfig().portMonitoring;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Get the interval for a specific monitoring level
|
|
566
|
+
*/
|
|
567
|
+
getIntervalForLevel(level) {
|
|
568
|
+
return this.getPortMonitoringConfig().portMonitoringFreqMs[level];
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Get Chrome configuration
|
|
572
|
+
*/
|
|
573
|
+
getChromeConfig() {
|
|
574
|
+
return this.getConfig().chrome;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Absolute directory that named persistent Chrome profiles live in
|
|
578
|
+
* (`launchChrome({ profile })`, `config({action:'resetProfile'})`).
|
|
579
|
+
*
|
|
580
|
+
* Defaults to the global `~/.cdp-tools/profiles` so a named profile is shared
|
|
581
|
+
* across projects. `chrome.persistentProfileRoot` in a project-local config
|
|
582
|
+
* overrides it; relative values resolve against the working directory and a
|
|
583
|
+
* leading `~/` is expanded.
|
|
584
|
+
*/
|
|
585
|
+
getPersistentProfileRoot() {
|
|
586
|
+
const configured = (this.getChromeConfig().persistentProfileRoot || '').trim();
|
|
587
|
+
if (!configured) {
|
|
588
|
+
return join(homedir(), '.cdp-tools', 'profiles');
|
|
589
|
+
}
|
|
590
|
+
if (configured === '~') {
|
|
591
|
+
return homedir();
|
|
592
|
+
}
|
|
593
|
+
if (configured.startsWith('~/')) {
|
|
594
|
+
return join(homedir(), configured.slice(2));
|
|
595
|
+
}
|
|
596
|
+
return isAbsolute(configured) ? configured : resolve(process.cwd(), configured);
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get replay system configuration
|
|
600
|
+
*/
|
|
601
|
+
getReplayConfig() {
|
|
602
|
+
return this.getConfig().replay;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Get change detection configuration
|
|
606
|
+
*/
|
|
607
|
+
getChangeDetectionConfig() {
|
|
608
|
+
return this.getConfig().changeDetection;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Get click validation configuration for replay sequences
|
|
612
|
+
*/
|
|
613
|
+
getClickValidationConfig() {
|
|
614
|
+
return this.getConfig().clickValidation;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Get debug configuration
|
|
618
|
+
*/
|
|
619
|
+
getDebugConfig() {
|
|
620
|
+
return this.getConfig().debug;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Get tools configuration
|
|
624
|
+
*/
|
|
625
|
+
getToolsConfig() {
|
|
626
|
+
return this.getConfig().tools;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Check if a tool is enabled
|
|
630
|
+
* A tool is enabled if it's in the enabled list and not in the disabled list
|
|
631
|
+
*/
|
|
632
|
+
isToolEnabled(toolName) {
|
|
633
|
+
const tools = this.getToolsConfig();
|
|
634
|
+
// If in disabled list, it's disabled
|
|
635
|
+
if (tools.disabled.includes(toolName))
|
|
636
|
+
return false;
|
|
637
|
+
// If in enabled list, it's enabled
|
|
638
|
+
if (tools.enabled.includes(toolName))
|
|
639
|
+
return true;
|
|
640
|
+
// Default to disabled if not in either list
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Auto-discover and enable new tools
|
|
645
|
+
* Any tool in TOGGLEABLE_TOOLS that isn't in disabled will be added to enabled
|
|
646
|
+
* Also removes tools from enabled if they are in disabled
|
|
647
|
+
* Returns true if config was modified
|
|
648
|
+
*/
|
|
649
|
+
discoverTools() {
|
|
650
|
+
let modified = false;
|
|
651
|
+
// Remove any tools from enabled that are in disabled
|
|
652
|
+
for (const toolName of this.config.tools.disabled) {
|
|
653
|
+
const enabledIndex = this.config.tools.enabled.indexOf(toolName);
|
|
654
|
+
if (enabledIndex !== -1) {
|
|
655
|
+
this.config.tools.enabled.splice(enabledIndex, 1);
|
|
656
|
+
modified = true;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
// Auto-add new tools to enabled (if not in disabled)
|
|
660
|
+
for (const toolName of TOGGLEABLE_TOOLS) {
|
|
661
|
+
// Skip if already in enabled or disabled
|
|
662
|
+
if (this.config.tools.enabled.includes(toolName))
|
|
663
|
+
continue;
|
|
664
|
+
if (this.config.tools.disabled.includes(toolName))
|
|
665
|
+
continue;
|
|
666
|
+
// Auto-add to enabled
|
|
667
|
+
this.config.tools.enabled.push(toolName);
|
|
668
|
+
modified = true;
|
|
669
|
+
}
|
|
670
|
+
return modified;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Get list of available toggleable tools with their current state
|
|
674
|
+
*/
|
|
675
|
+
getToggleableTools() {
|
|
676
|
+
return TOGGLEABLE_TOOLS.map(name => ({
|
|
677
|
+
name,
|
|
678
|
+
enabled: this.isToolEnabled(name),
|
|
679
|
+
dependencies: TOOL_DEPENDENCIES[name] || [],
|
|
680
|
+
}));
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Update port monitoring frequency configuration
|
|
684
|
+
*/
|
|
685
|
+
async updatePortMonitoringFreqMs(updates) {
|
|
686
|
+
this.config.portMonitoring.portMonitoringFreqMs = {
|
|
687
|
+
...this.config.portMonitoring.portMonitoringFreqMs,
|
|
688
|
+
...updates,
|
|
689
|
+
};
|
|
690
|
+
await this.save();
|
|
691
|
+
}
|
|
692
|
+
// Runtime port state methods (not persisted)
|
|
693
|
+
/**
|
|
694
|
+
* Get the current port in use (runtime state)
|
|
695
|
+
*/
|
|
696
|
+
getCurrentPort() {
|
|
697
|
+
return this.currentPort;
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Set the current port (runtime state)
|
|
701
|
+
*/
|
|
702
|
+
setCurrentPort(port) {
|
|
703
|
+
this.currentPort = port;
|
|
704
|
+
}
|
|
705
|
+
// Config management methods
|
|
706
|
+
/**
|
|
707
|
+
* Get info about current config location and status
|
|
708
|
+
*/
|
|
709
|
+
getStatus() {
|
|
710
|
+
const localPath = getOutputPath('config.json');
|
|
711
|
+
const globalPath = join(homedir(), '.cdp-tools', 'config.json');
|
|
712
|
+
return {
|
|
713
|
+
loadedFrom: this.loadedFromPath,
|
|
714
|
+
isLocal: this.loadedFromPath === localPath,
|
|
715
|
+
localPath,
|
|
716
|
+
globalPath,
|
|
717
|
+
localExists: fs.existsSync(localPath),
|
|
718
|
+
globalExists: fs.existsSync(globalPath),
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Switch to using local config (creates if needed, optionally seeds from global)
|
|
723
|
+
*
|
|
724
|
+
* @param seedFromGlobal - seed new local config from global if it exists
|
|
725
|
+
* @param projectPath - explicit project directory to treat as "local".
|
|
726
|
+
* Needed when the MCP server's process.cwd() doesn't reflect the
|
|
727
|
+
* project the user is currently working in (e.g. a shared long-lived
|
|
728
|
+
* server process spawned from the home directory).
|
|
729
|
+
*/
|
|
730
|
+
async useLocal(seedFromGlobal = true, projectPath) {
|
|
731
|
+
if (projectPath) {
|
|
732
|
+
setWorkingDirOverride(projectPath);
|
|
733
|
+
}
|
|
734
|
+
const localPath = getOutputPath('config.json');
|
|
735
|
+
const globalPath = join(homedir(), '.cdp-tools', 'config.json');
|
|
736
|
+
const localDir = dirname(localPath);
|
|
737
|
+
// Create directory if needed
|
|
738
|
+
if (!fs.existsSync(localDir)) {
|
|
739
|
+
await fs.promises.mkdir(localDir, { recursive: true });
|
|
740
|
+
}
|
|
741
|
+
let seeded = false;
|
|
742
|
+
if (!fs.existsSync(localPath) && seedFromGlobal && fs.existsSync(globalPath)) {
|
|
743
|
+
// Seed from global
|
|
744
|
+
const content = await fs.promises.readFile(globalPath, 'utf-8');
|
|
745
|
+
const loaded = JSON.parse(content);
|
|
746
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
747
|
+
seeded = true;
|
|
748
|
+
}
|
|
749
|
+
// Set configLocation to local explicitly
|
|
750
|
+
this.config.configLocation = 'local';
|
|
751
|
+
this.loadedFromPath = localPath;
|
|
752
|
+
await this.save();
|
|
753
|
+
return { path: localPath, seeded };
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Switch to using global config
|
|
757
|
+
* Writes a minimal local config with just configLocation: 'global'
|
|
758
|
+
*/
|
|
759
|
+
async useGlobal() {
|
|
760
|
+
const localPath = getOutputPath('config.json');
|
|
761
|
+
const globalPath = join(homedir(), '.cdp-tools', 'config.json');
|
|
762
|
+
const localDir = dirname(localPath);
|
|
763
|
+
const globalDir = dirname(globalPath);
|
|
764
|
+
// Ensure global directory exists (for reading config below)
|
|
765
|
+
if (!fs.existsSync(globalDir)) {
|
|
766
|
+
await fs.promises.mkdir(globalDir, { recursive: true });
|
|
767
|
+
}
|
|
768
|
+
// Write minimal local config with just the preference (atomic write)
|
|
769
|
+
const minimalConfig = { configLocation: 'global' };
|
|
770
|
+
await atomicWriteFile(localPath, JSON.stringify(minimalConfig, null, 2));
|
|
771
|
+
// Load and use global config
|
|
772
|
+
if (fs.existsSync(globalPath)) {
|
|
773
|
+
const content = await fs.promises.readFile(globalPath, 'utf-8');
|
|
774
|
+
const loaded = JSON.parse(content);
|
|
775
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
779
|
+
}
|
|
780
|
+
this.loadedFromPath = globalPath;
|
|
781
|
+
await this.save();
|
|
782
|
+
return { path: globalPath };
|
|
783
|
+
}
|
|
784
|
+
/**
|
|
785
|
+
* Reset config to defaults
|
|
786
|
+
*/
|
|
787
|
+
async reset() {
|
|
788
|
+
this.config = { ...DEFAULT_CONFIG };
|
|
789
|
+
await this.save();
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Create a backup of current config
|
|
793
|
+
*/
|
|
794
|
+
async backup() {
|
|
795
|
+
if (!this.loadedFromPath || !fs.existsSync(this.loadedFromPath)) {
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
799
|
+
const backupPath = this.loadedFromPath.replace('.json', `.backup-${timestamp}.json`);
|
|
800
|
+
await fs.promises.copyFile(this.loadedFromPath, backupPath);
|
|
801
|
+
return { path: backupPath };
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Clone global config to local
|
|
805
|
+
*/
|
|
806
|
+
async cloneFromGlobal() {
|
|
807
|
+
const globalPath = join(homedir(), '.cdp-tools', 'config.json');
|
|
808
|
+
if (!fs.existsSync(globalPath)) {
|
|
809
|
+
return { error: 'No global config exists to clone from' };
|
|
810
|
+
}
|
|
811
|
+
const content = await fs.promises.readFile(globalPath, 'utf-8');
|
|
812
|
+
const loaded = JSON.parse(content);
|
|
813
|
+
this.config = this.mergeConfig(DEFAULT_CONFIG, loaded);
|
|
814
|
+
const localPath = getOutputPath('config.json');
|
|
815
|
+
const localDir = dirname(localPath);
|
|
816
|
+
if (!fs.existsSync(localDir)) {
|
|
817
|
+
await fs.promises.mkdir(localDir, { recursive: true });
|
|
818
|
+
}
|
|
819
|
+
this.loadedFromPath = localPath;
|
|
820
|
+
await this.save();
|
|
821
|
+
return { path: localPath };
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
// Export singleton instance
|
|
825
|
+
export const configManager = new ConfigManager();
|
|
826
|
+
//# sourceMappingURL=config.js.map
|