@avi770/testteam 2.0.0 → 3.2.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/CHANGELOG.md +188 -3
- package/README.md +111 -20
- package/bin/testteam.js +32 -4
- package/dist/agents/01-analyst.d.ts +2 -2
- package/dist/agents/01-analyst.js +1 -1
- package/dist/agents/02-seed-architect.d.ts +2 -2
- package/dist/agents/02-seed-architect.js +2 -2
- package/dist/agents/03-test-generator.d.ts +2 -2
- package/dist/agents/03-test-generator.js +2 -2
- package/dist/agents/04-unit-runner.d.ts +2 -2
- package/dist/agents/04-unit-runner.d.ts.map +1 -1
- package/dist/agents/04-unit-runner.js +12 -3
- package/dist/agents/04-unit-runner.js.map +1 -1
- package/dist/agents/05-browser-crawler.d.ts +2 -2
- package/dist/agents/05-browser-crawler.d.ts.map +1 -1
- package/dist/agents/05-browser-crawler.js +24 -12
- package/dist/agents/05-browser-crawler.js.map +1 -1
- package/dist/agents/06-api-exerciser.d.ts +2 -2
- package/dist/agents/06-api-exerciser.js +2 -2
- package/dist/agents/07-security-scout.d.ts +2 -2
- package/dist/agents/07-security-scout.js +2 -2
- package/dist/agents/08-a11y-guardian.d.ts +2 -2
- package/dist/agents/08-a11y-guardian.d.ts.map +1 -1
- package/dist/agents/08-a11y-guardian.js +9 -5
- package/dist/agents/08-a11y-guardian.js.map +1 -1
- package/dist/agents/09-healer.d.ts +2 -2
- package/dist/agents/09-healer.js +2 -2
- package/dist/agents/10-reporter.d.ts +2 -2
- package/dist/agents/10-reporter.d.ts.map +1 -1
- package/dist/agents/10-reporter.js +55 -27
- package/dist/agents/10-reporter.js.map +1 -1
- package/dist/agents/100-error-handling-auditor.d.ts +63 -0
- package/dist/agents/100-error-handling-auditor.d.ts.map +1 -0
- package/dist/agents/100-error-handling-auditor.js +334 -0
- package/dist/agents/100-error-handling-auditor.js.map +1 -0
- package/dist/agents/101-rate-limit-auditor.d.ts +72 -0
- package/dist/agents/101-rate-limit-auditor.d.ts.map +1 -0
- package/dist/agents/101-rate-limit-auditor.js +295 -0
- package/dist/agents/101-rate-limit-auditor.js.map +1 -0
- package/dist/agents/102-dockerfile-auditor.d.ts +62 -0
- package/dist/agents/102-dockerfile-auditor.d.ts.map +1 -0
- package/dist/agents/102-dockerfile-auditor.js +337 -0
- package/dist/agents/102-dockerfile-auditor.js.map +1 -0
- package/dist/agents/103-ci-workflow-auditor.d.ts +57 -0
- package/dist/agents/103-ci-workflow-auditor.d.ts.map +1 -0
- package/dist/agents/103-ci-workflow-auditor.js +247 -0
- package/dist/agents/103-ci-workflow-auditor.js.map +1 -0
- package/dist/agents/104-n-plus-one-detector.d.ts +57 -0
- package/dist/agents/104-n-plus-one-detector.d.ts.map +1 -0
- package/dist/agents/104-n-plus-one-detector.js +329 -0
- package/dist/agents/104-n-plus-one-detector.js.map +1 -0
- package/dist/agents/105-unbounded-query-auditor.d.ts +50 -0
- package/dist/agents/105-unbounded-query-auditor.d.ts.map +1 -0
- package/dist/agents/105-unbounded-query-auditor.js +284 -0
- package/dist/agents/105-unbounded-query-auditor.js.map +1 -0
- package/dist/agents/106-hardcoded-config-auditor.d.ts +54 -0
- package/dist/agents/106-hardcoded-config-auditor.d.ts.map +1 -0
- package/dist/agents/106-hardcoded-config-auditor.js +251 -0
- package/dist/agents/106-hardcoded-config-auditor.js.map +1 -0
- package/dist/agents/107-open-redirect-detector.d.ts +52 -0
- package/dist/agents/107-open-redirect-detector.d.ts.map +1 -0
- package/dist/agents/107-open-redirect-detector.js +263 -0
- package/dist/agents/107-open-redirect-detector.js.map +1 -0
- package/dist/agents/108-sql-injection-detector.d.ts +51 -0
- package/dist/agents/108-sql-injection-detector.d.ts.map +1 -0
- package/dist/agents/108-sql-injection-detector.js +323 -0
- package/dist/agents/108-sql-injection-detector.js.map +1 -0
- package/dist/agents/109-path-traversal-detector.d.ts +51 -0
- package/dist/agents/109-path-traversal-detector.d.ts.map +1 -0
- package/dist/agents/109-path-traversal-detector.js +244 -0
- package/dist/agents/109-path-traversal-detector.js.map +1 -0
- package/dist/agents/11-fixer.d.ts +4 -2
- package/dist/agents/11-fixer.d.ts.map +1 -1
- package/dist/agents/11-fixer.js +52 -11
- package/dist/agents/11-fixer.js.map +1 -1
- package/dist/agents/110-mass-assignment-detector.d.ts +52 -0
- package/dist/agents/110-mass-assignment-detector.d.ts.map +1 -0
- package/dist/agents/110-mass-assignment-detector.js +199 -0
- package/dist/agents/110-mass-assignment-detector.js.map +1 -0
- package/dist/agents/111-dynamic-eval-detector.d.ts +46 -0
- package/dist/agents/111-dynamic-eval-detector.d.ts.map +1 -0
- package/dist/agents/111-dynamic-eval-detector.js +233 -0
- package/dist/agents/111-dynamic-eval-detector.js.map +1 -0
- package/dist/agents/112-taint-tracker.d.ts +226 -0
- package/dist/agents/112-taint-tracker.d.ts.map +1 -0
- package/dist/agents/112-taint-tracker.js +1273 -0
- package/dist/agents/112-taint-tracker.js.map +1 -0
- package/dist/agents/113-response-contract-auditor.d.ts +92 -0
- package/dist/agents/113-response-contract-auditor.d.ts.map +1 -0
- package/dist/agents/113-response-contract-auditor.js +694 -0
- package/dist/agents/113-response-contract-auditor.js.map +1 -0
- package/dist/agents/114-static-a11y-auditor.d.ts +66 -0
- package/dist/agents/114-static-a11y-auditor.d.ts.map +1 -0
- package/dist/agents/114-static-a11y-auditor.js +377 -0
- package/dist/agents/114-static-a11y-auditor.js.map +1 -0
- package/dist/agents/115-multihop-taint-tracker.d.ts +84 -0
- package/dist/agents/115-multihop-taint-tracker.d.ts.map +1 -0
- package/dist/agents/115-multihop-taint-tracker.js +340 -0
- package/dist/agents/115-multihop-taint-tracker.js.map +1 -0
- package/dist/agents/116-runtime-contract-capture.d.ts +79 -0
- package/dist/agents/116-runtime-contract-capture.d.ts.map +1 -0
- package/dist/agents/116-runtime-contract-capture.js +274 -0
- package/dist/agents/116-runtime-contract-capture.js.map +1 -0
- package/dist/agents/117-aria-rule-engine.d.ts +52 -0
- package/dist/agents/117-aria-rule-engine.d.ts.map +1 -0
- package/dist/agents/117-aria-rule-engine.js +415 -0
- package/dist/agents/117-aria-rule-engine.js.map +1 -0
- package/dist/agents/118-insecure-crypto-auditor.d.ts +48 -0
- package/dist/agents/118-insecure-crypto-auditor.d.ts.map +1 -0
- package/dist/agents/118-insecure-crypto-auditor.js +232 -0
- package/dist/agents/118-insecure-crypto-auditor.js.map +1 -0
- package/dist/agents/119-secrets-scanner.d.ts +44 -0
- package/dist/agents/119-secrets-scanner.d.ts.map +1 -0
- package/dist/agents/119-secrets-scanner.js +242 -0
- package/dist/agents/119-secrets-scanner.js.map +1 -0
- package/dist/agents/12-ux-inspector.d.ts +2 -2
- package/dist/agents/12-ux-inspector.d.ts.map +1 -1
- package/dist/agents/12-ux-inspector.js +8 -4
- package/dist/agents/12-ux-inspector.js.map +1 -1
- package/dist/agents/120-async-safety-auditor.d.ts +48 -0
- package/dist/agents/120-async-safety-auditor.d.ts.map +1 -0
- package/dist/agents/120-async-safety-auditor.js +250 -0
- package/dist/agents/120-async-safety-auditor.js.map +1 -0
- package/dist/agents/13-performance-profiler.d.ts +2 -2
- package/dist/agents/13-performance-profiler.d.ts.map +1 -1
- package/dist/agents/13-performance-profiler.js +5 -4
- package/dist/agents/13-performance-profiler.js.map +1 -1
- package/dist/agents/14-data-integrity-auditor.d.ts +2 -2
- package/dist/agents/14-data-integrity-auditor.js +4 -4
- package/dist/agents/14-data-integrity-auditor.js.map +1 -1
- package/dist/agents/15-regression-sentinel.d.ts +6 -4
- package/dist/agents/15-regression-sentinel.d.ts.map +1 -1
- package/dist/agents/15-regression-sentinel.js +5 -4
- package/dist/agents/15-regression-sentinel.js.map +1 -1
- package/dist/agents/16-chaos-agent.d.ts +2 -2
- package/dist/agents/16-chaos-agent.d.ts.map +1 -1
- package/dist/agents/16-chaos-agent.js +11 -4
- package/dist/agents/16-chaos-agent.js.map +1 -1
- package/dist/agents/17-documentation-validator.d.ts +2 -2
- package/dist/agents/17-documentation-validator.d.ts.map +1 -1
- package/dist/agents/17-documentation-validator.js +5 -2
- package/dist/agents/17-documentation-validator.js.map +1 -1
- package/dist/agents/18-integration-watchdog.d.ts +2 -2
- package/dist/agents/18-integration-watchdog.d.ts.map +1 -1
- package/dist/agents/18-integration-watchdog.js +5 -2
- package/dist/agents/18-integration-watchdog.js.map +1 -1
- package/dist/agents/19-tenant-isolation-auditor.d.ts +2 -2
- package/dist/agents/19-tenant-isolation-auditor.js +4 -4
- package/dist/agents/19-tenant-isolation-auditor.js.map +1 -1
- package/dist/agents/20-workflow-completion-tester.d.ts +2 -2
- package/dist/agents/20-workflow-completion-tester.d.ts.map +1 -1
- package/dist/agents/20-workflow-completion-tester.js +10 -6
- package/dist/agents/20-workflow-completion-tester.js.map +1 -1
- package/dist/agents/21-state-session-tester.d.ts +2 -2
- package/dist/agents/21-state-session-tester.d.ts.map +1 -1
- package/dist/agents/21-state-session-tester.js +15 -5
- package/dist/agents/21-state-session-tester.js.map +1 -1
- package/dist/agents/22-email-notification-verifier.d.ts +2 -2
- package/dist/agents/22-email-notification-verifier.js +2 -2
- package/dist/agents/23-migration-tester.d.ts +2 -2
- package/dist/agents/23-migration-tester.js +1 -1
- package/dist/agents/24-signup-onboarding-tester.d.ts +2 -2
- package/dist/agents/24-signup-onboarding-tester.d.ts.map +1 -1
- package/dist/agents/24-signup-onboarding-tester.js +13 -10
- package/dist/agents/24-signup-onboarding-tester.js.map +1 -1
- package/dist/agents/25-crud-flow-tester.d.ts +2 -2
- package/dist/agents/25-crud-flow-tester.d.ts.map +1 -1
- package/dist/agents/25-crud-flow-tester.js +12 -6
- package/dist/agents/25-crud-flow-tester.js.map +1 -1
- package/dist/agents/26-form-validator.d.ts +2 -2
- package/dist/agents/26-form-validator.d.ts.map +1 -1
- package/dist/agents/26-form-validator.js +12 -6
- package/dist/agents/26-form-validator.js.map +1 -1
- package/dist/agents/27-search-filter-tester.d.ts +2 -2
- package/dist/agents/27-search-filter-tester.d.ts.map +1 -1
- package/dist/agents/27-search-filter-tester.js +12 -6
- package/dist/agents/27-search-filter-tester.js.map +1 -1
- package/dist/agents/28-navigation-routing-tester.d.ts +2 -2
- package/dist/agents/28-navigation-routing-tester.d.ts.map +1 -1
- package/dist/agents/28-navigation-routing-tester.js +12 -6
- package/dist/agents/28-navigation-routing-tester.js.map +1 -1
- package/dist/agents/29-responsive-interaction-tester.d.ts +2 -2
- package/dist/agents/29-responsive-interaction-tester.d.ts.map +1 -1
- package/dist/agents/29-responsive-interaction-tester.js +12 -6
- package/dist/agents/29-responsive-interaction-tester.js.map +1 -1
- package/dist/agents/30-multi-user-scenario-tester.d.ts +2 -2
- package/dist/agents/30-multi-user-scenario-tester.d.ts.map +1 -1
- package/dist/agents/30-multi-user-scenario-tester.js +20 -13
- package/dist/agents/30-multi-user-scenario-tester.js.map +1 -1
- package/dist/agents/31-load-tester.d.ts +2 -2
- package/dist/agents/31-load-tester.js +2 -2
- package/dist/agents/32-memory-leak-detector.d.ts +2 -2
- package/dist/agents/32-memory-leak-detector.d.ts.map +1 -1
- package/dist/agents/32-memory-leak-detector.js +5 -4
- package/dist/agents/32-memory-leak-detector.js.map +1 -1
- package/dist/agents/33-bundle-analyzer.d.ts +2 -2
- package/dist/agents/33-bundle-analyzer.js +1 -1
- package/dist/agents/34-xss-scanner.d.ts +2 -2
- package/dist/agents/34-xss-scanner.d.ts.map +1 -1
- package/dist/agents/34-xss-scanner.js +12 -6
- package/dist/agents/34-xss-scanner.js.map +1 -1
- package/dist/agents/35-csrf-tester.d.ts +2 -2
- package/dist/agents/35-csrf-tester.js +2 -2
- package/dist/agents/36-auth-fuzzer.d.ts +2 -2
- package/dist/agents/36-auth-fuzzer.js +2 -2
- package/dist/agents/37-dependency-scanner.d.ts +2 -2
- package/dist/agents/37-dependency-scanner.js +1 -1
- package/dist/agents/38-secrets-scanner.d.ts +2 -2
- package/dist/agents/38-secrets-scanner.d.ts.map +1 -1
- package/dist/agents/38-secrets-scanner.js +39 -4
- package/dist/agents/38-secrets-scanner.js.map +1 -1
- package/dist/agents/39-api-contract-tester.d.ts +2 -2
- package/dist/agents/39-api-contract-tester.js +2 -2
- package/dist/agents/40-rate-limit-tester.d.ts +2 -2
- package/dist/agents/40-rate-limit-tester.js +2 -2
- package/dist/agents/41-api-pagination-tester.d.ts +2 -2
- package/dist/agents/41-api-pagination-tester.js +2 -2
- package/dist/agents/42-graphql-tester.d.ts +2 -2
- package/dist/agents/42-graphql-tester.js +2 -2
- package/dist/agents/43-data-consistency-checker.d.ts +2 -2
- package/dist/agents/43-data-consistency-checker.js +3 -3
- package/dist/agents/44-backup-recovery-tester.d.ts +2 -2
- package/dist/agents/44-backup-recovery-tester.js +1 -1
- package/dist/agents/45-data-privacy-scanner.d.ts +2 -2
- package/dist/agents/45-data-privacy-scanner.js +3 -3
- package/dist/agents/46-seo-auditor.d.ts +2 -2
- package/dist/agents/46-seo-auditor.d.ts.map +1 -1
- package/dist/agents/46-seo-auditor.js +12 -6
- package/dist/agents/46-seo-auditor.js.map +1 -1
- package/dist/agents/47-social-preview-tester.d.ts +2 -2
- package/dist/agents/47-social-preview-tester.d.ts.map +1 -1
- package/dist/agents/47-social-preview-tester.js +12 -6
- package/dist/agents/47-social-preview-tester.js.map +1 -1
- package/dist/agents/48-lighthouse-auditor.d.ts +2 -2
- package/dist/agents/48-lighthouse-auditor.d.ts.map +1 -1
- package/dist/agents/48-lighthouse-auditor.js +5 -4
- package/dist/agents/48-lighthouse-auditor.js.map +1 -1
- package/dist/agents/49-i18n-tester.d.ts +2 -2
- package/dist/agents/49-i18n-tester.d.ts.map +1 -1
- package/dist/agents/49-i18n-tester.js +12 -6
- package/dist/agents/49-i18n-tester.js.map +1 -1
- package/dist/agents/50-timezone-tester.d.ts +2 -2
- package/dist/agents/50-timezone-tester.d.ts.map +1 -1
- package/dist/agents/50-timezone-tester.js +40 -33
- package/dist/agents/50-timezone-tester.js.map +1 -1
- package/dist/agents/51-error-recovery-tester.d.ts +2 -2
- package/dist/agents/51-error-recovery-tester.d.ts.map +1 -1
- package/dist/agents/51-error-recovery-tester.js +12 -7
- package/dist/agents/51-error-recovery-tester.js.map +1 -1
- package/dist/agents/52-offline-mode-tester.d.ts +2 -2
- package/dist/agents/52-offline-mode-tester.d.ts.map +1 -1
- package/dist/agents/52-offline-mode-tester.js +12 -7
- package/dist/agents/52-offline-mode-tester.js.map +1 -1
- package/dist/agents/53-graceful-degradation-tester.d.ts +2 -2
- package/dist/agents/53-graceful-degradation-tester.d.ts.map +1 -1
- package/dist/agents/53-graceful-degradation-tester.js +10 -3
- package/dist/agents/53-graceful-degradation-tester.js.map +1 -1
- package/dist/agents/54-websocket-tester.d.ts +2 -2
- package/dist/agents/54-websocket-tester.d.ts.map +1 -1
- package/dist/agents/54-websocket-tester.js +12 -6
- package/dist/agents/54-websocket-tester.js.map +1 -1
- package/dist/agents/55-realtime-sync-tester.d.ts +2 -2
- package/dist/agents/55-realtime-sync-tester.d.ts.map +1 -1
- package/dist/agents/55-realtime-sync-tester.js +101 -96
- package/dist/agents/55-realtime-sync-tester.js.map +1 -1
- package/dist/agents/56-file-upload-tester.d.ts +2 -2
- package/dist/agents/56-file-upload-tester.d.ts.map +1 -1
- package/dist/agents/56-file-upload-tester.js +17 -13
- package/dist/agents/56-file-upload-tester.js.map +1 -1
- package/dist/agents/57-export-tester.d.ts +2 -2
- package/dist/agents/57-export-tester.d.ts.map +1 -1
- package/dist/agents/57-export-tester.js +8 -4
- package/dist/agents/57-export-tester.js.map +1 -1
- package/dist/agents/58-payment-flow-tester.d.ts +2 -2
- package/dist/agents/58-payment-flow-tester.d.ts.map +1 -1
- package/dist/agents/58-payment-flow-tester.js +8 -4
- package/dist/agents/58-payment-flow-tester.js.map +1 -1
- package/dist/agents/59-ssl-tls-auditor.d.ts +2 -2
- package/dist/agents/59-ssl-tls-auditor.js +2 -2
- package/dist/agents/60-dns-cdn-tester.d.ts +2 -2
- package/dist/agents/60-dns-cdn-tester.js +2 -2
- package/dist/agents/61-docker-health-checker.d.ts +2 -2
- package/dist/agents/61-docker-health-checker.js +1 -1
- package/dist/agents/62-env-config-validator.d.ts +2 -2
- package/dist/agents/62-env-config-validator.js +1 -1
- package/dist/agents/63-log-quality-auditor.d.ts +2 -2
- package/dist/agents/63-log-quality-auditor.js +1 -1
- package/dist/agents/64-analytics-tracker-tester.d.ts +2 -2
- package/dist/agents/64-analytics-tracker-tester.d.ts.map +1 -1
- package/dist/agents/64-analytics-tracker-tester.js +8 -4
- package/dist/agents/64-analytics-tracker-tester.js.map +1 -1
- package/dist/agents/65-gdpr-compliance-tester.d.ts +2 -2
- package/dist/agents/65-gdpr-compliance-tester.d.ts.map +1 -1
- package/dist/agents/65-gdpr-compliance-tester.js +55 -40
- package/dist/agents/65-gdpr-compliance-tester.js.map +1 -1
- package/dist/agents/66-soc2-control-validator.d.ts +2 -2
- package/dist/agents/66-soc2-control-validator.d.ts.map +1 -1
- package/dist/agents/66-soc2-control-validator.js +29 -21
- package/dist/agents/66-soc2-control-validator.js.map +1 -1
- package/dist/agents/67-wcag-aaa-tester.d.ts +2 -2
- package/dist/agents/67-wcag-aaa-tester.d.ts.map +1 -1
- package/dist/agents/67-wcag-aaa-tester.js +12 -6
- package/dist/agents/67-wcag-aaa-tester.js.map +1 -1
- package/dist/agents/68-dead-code-detector.d.ts +2 -2
- package/dist/agents/68-dead-code-detector.d.ts.map +1 -1
- package/dist/agents/68-dead-code-detector.js +6 -3
- package/dist/agents/68-dead-code-detector.js.map +1 -1
- package/dist/agents/69-type-safety-auditor.d.ts +2 -2
- package/dist/agents/69-type-safety-auditor.js +1 -1
- package/dist/agents/70-complexity-analyzer.d.ts +2 -2
- package/dist/agents/70-complexity-analyzer.js +1 -1
- package/dist/agents/71-unit-testing-agent.d.ts +15 -0
- package/dist/agents/71-unit-testing-agent.d.ts.map +1 -0
- package/dist/agents/71-unit-testing-agent.js +220 -0
- package/dist/agents/71-unit-testing-agent.js.map +1 -0
- package/dist/agents/72-integration-testing-agent.d.ts +13 -0
- package/dist/agents/72-integration-testing-agent.d.ts.map +1 -0
- package/dist/agents/72-integration-testing-agent.js +243 -0
- package/dist/agents/72-integration-testing-agent.js.map +1 -0
- package/dist/agents/73-system-testing-agent.d.ts +11 -0
- package/dist/agents/73-system-testing-agent.d.ts.map +1 -0
- package/dist/agents/73-system-testing-agent.js +175 -0
- package/dist/agents/73-system-testing-agent.js.map +1 -0
- package/dist/agents/74-acceptance-testing-agent.d.ts +13 -0
- package/dist/agents/74-acceptance-testing-agent.d.ts.map +1 -0
- package/dist/agents/74-acceptance-testing-agent.js +254 -0
- package/dist/agents/74-acceptance-testing-agent.js.map +1 -0
- package/dist/agents/75-sanity-testing-agent.d.ts +15 -0
- package/dist/agents/75-sanity-testing-agent.d.ts.map +1 -0
- package/dist/agents/75-sanity-testing-agent.js +240 -0
- package/dist/agents/75-sanity-testing-agent.js.map +1 -0
- package/dist/agents/76-regression-testing-agent.d.ts +14 -0
- package/dist/agents/76-regression-testing-agent.d.ts.map +1 -0
- package/dist/agents/76-regression-testing-agent.js +230 -0
- package/dist/agents/76-regression-testing-agent.js.map +1 -0
- package/dist/agents/77-browser-load-testing-agent.d.ts +11 -0
- package/dist/agents/77-browser-load-testing-agent.d.ts.map +1 -0
- package/dist/agents/77-browser-load-testing-agent.js +128 -0
- package/dist/agents/77-browser-load-testing-agent.js.map +1 -0
- package/dist/agents/78-stress-testing-agent.d.ts +11 -0
- package/dist/agents/78-stress-testing-agent.d.ts.map +1 -0
- package/dist/agents/78-stress-testing-agent.js +146 -0
- package/dist/agents/78-stress-testing-agent.js.map +1 -0
- package/dist/agents/79-endurance-testing-agent.d.ts +12 -0
- package/dist/agents/79-endurance-testing-agent.d.ts.map +1 -0
- package/dist/agents/79-endurance-testing-agent.js +165 -0
- package/dist/agents/79-endurance-testing-agent.js.map +1 -0
- package/dist/agents/80-usability-testing-agent.d.ts +11 -0
- package/dist/agents/80-usability-testing-agent.d.ts.map +1 -0
- package/dist/agents/80-usability-testing-agent.js +196 -0
- package/dist/agents/80-usability-testing-agent.js.map +1 -0
- package/dist/agents/81-compatibility-testing-agent.d.ts +11 -0
- package/dist/agents/81-compatibility-testing-agent.d.ts.map +1 -0
- package/dist/agents/81-compatibility-testing-agent.js +224 -0
- package/dist/agents/81-compatibility-testing-agent.js.map +1 -0
- package/dist/agents/82-exploratory-testing-agent.d.ts +14 -0
- package/dist/agents/82-exploratory-testing-agent.d.ts.map +1 -0
- package/dist/agents/82-exploratory-testing-agent.js +345 -0
- package/dist/agents/82-exploratory-testing-agent.js.map +1 -0
- package/dist/agents/83-static-analysis-agent.d.ts +14 -0
- package/dist/agents/83-static-analysis-agent.d.ts.map +1 -0
- package/dist/agents/83-static-analysis-agent.js +261 -0
- package/dist/agents/83-static-analysis-agent.js.map +1 -0
- package/dist/agents/84-governance-testing-agent.d.ts +28 -0
- package/dist/agents/84-governance-testing-agent.d.ts.map +1 -0
- package/dist/agents/84-governance-testing-agent.js +591 -0
- package/dist/agents/84-governance-testing-agent.js.map +1 -0
- package/dist/agents/85-stagehand-agent.d.ts +22 -0
- package/dist/agents/85-stagehand-agent.d.ts.map +1 -0
- package/dist/agents/85-stagehand-agent.js +81 -0
- package/dist/agents/85-stagehand-agent.js.map +1 -0
- package/dist/agents/86-browser-use-agent.d.ts +31 -0
- package/dist/agents/86-browser-use-agent.d.ts.map +1 -0
- package/dist/agents/86-browser-use-agent.js +121 -0
- package/dist/agents/86-browser-use-agent.js.map +1 -0
- package/dist/agents/87-connection-mapper.d.ts +93 -0
- package/dist/agents/87-connection-mapper.d.ts.map +1 -0
- package/dist/agents/87-connection-mapper.js +658 -0
- package/dist/agents/87-connection-mapper.js.map +1 -0
- package/dist/agents/88-localhost-walkthrough.d.ts +272 -0
- package/dist/agents/88-localhost-walkthrough.d.ts.map +1 -0
- package/dist/agents/88-localhost-walkthrough.js +1203 -0
- package/dist/agents/88-localhost-walkthrough.js.map +1 -0
- package/dist/agents/89-repair-retest.d.ts +63 -0
- package/dist/agents/89-repair-retest.d.ts.map +1 -0
- package/dist/agents/89-repair-retest.js +227 -0
- package/dist/agents/89-repair-retest.js.map +1 -0
- package/dist/agents/90-response-shape-validator.d.ts +35 -0
- package/dist/agents/90-response-shape-validator.d.ts.map +1 -0
- package/dist/agents/90-response-shape-validator.js +156 -0
- package/dist/agents/90-response-shape-validator.js.map +1 -0
- package/dist/agents/91-boundary-fuzzer.d.ts +99 -0
- package/dist/agents/91-boundary-fuzzer.d.ts.map +1 -0
- package/dist/agents/91-boundary-fuzzer.js +0 -0
- package/dist/agents/91-boundary-fuzzer.js.map +1 -0
- package/dist/agents/92-repair-simulator.d.ts +89 -0
- package/dist/agents/92-repair-simulator.d.ts.map +1 -0
- package/dist/agents/92-repair-simulator.js +401 -0
- package/dist/agents/92-repair-simulator.js.map +1 -0
- package/dist/agents/93-env-var-auditor.d.ts +64 -0
- package/dist/agents/93-env-var-auditor.d.ts.map +1 -0
- package/dist/agents/93-env-var-auditor.js +435 -0
- package/dist/agents/93-env-var-auditor.js.map +1 -0
- package/dist/agents/94-schema-validator.d.ts +148 -0
- package/dist/agents/94-schema-validator.d.ts.map +1 -0
- package/dist/agents/94-schema-validator.js +567 -0
- package/dist/agents/94-schema-validator.js.map +1 -0
- package/dist/agents/95-contract-drift.d.ts +87 -0
- package/dist/agents/95-contract-drift.d.ts.map +1 -0
- package/dist/agents/95-contract-drift.js +335 -0
- package/dist/agents/95-contract-drift.js.map +1 -0
- package/dist/agents/96-cookie-security-auditor.d.ts +86 -0
- package/dist/agents/96-cookie-security-auditor.d.ts.map +1 -0
- package/dist/agents/96-cookie-security-auditor.js +339 -0
- package/dist/agents/96-cookie-security-auditor.js.map +1 -0
- package/dist/agents/97-healthcheck-validator.d.ts +62 -0
- package/dist/agents/97-healthcheck-validator.d.ts.map +1 -0
- package/dist/agents/97-healthcheck-validator.js +204 -0
- package/dist/agents/97-healthcheck-validator.js.map +1 -0
- package/dist/agents/98-cors-csp-auditor.d.ts +70 -0
- package/dist/agents/98-cors-csp-auditor.d.ts.map +1 -0
- package/dist/agents/98-cors-csp-auditor.js +308 -0
- package/dist/agents/98-cors-csp-auditor.js.map +1 -0
- package/dist/agents/99-logging-hygiene-auditor.d.ts +67 -0
- package/dist/agents/99-logging-hygiene-auditor.d.ts.map +1 -0
- package/dist/agents/99-logging-hygiene-auditor.js +325 -0
- package/dist/agents/99-logging-hygiene-auditor.js.map +1 -0
- package/dist/agents/base-agent.d.ts +75 -3
- package/dist/agents/base-agent.d.ts.map +1 -1
- package/dist/agents/base-agent.js +112 -1
- package/dist/agents/base-agent.js.map +1 -1
- package/dist/agents/browser-use-client.d.ts +68 -0
- package/dist/agents/browser-use-client.d.ts.map +1 -0
- package/dist/agents/browser-use-client.js +92 -0
- package/dist/agents/browser-use-client.js.map +1 -0
- package/dist/agents/lib/source-scan.d.ts +53 -0
- package/dist/agents/lib/source-scan.d.ts.map +1 -0
- package/dist/agents/lib/source-scan.js +279 -0
- package/dist/agents/lib/source-scan.js.map +1 -0
- package/dist/agents/registry.d.ts +27 -8
- package/dist/agents/registry.d.ts.map +1 -1
- package/dist/agents/registry.js +365 -151
- package/dist/agents/registry.js.map +1 -1
- package/dist/agents/stagehand-runner.d.ts +104 -0
- package/dist/agents/stagehand-runner.d.ts.map +1 -0
- package/dist/agents/stagehand-runner.js +153 -0
- package/dist/agents/stagehand-runner.js.map +1 -0
- package/dist/bridge/agent-registry.d.ts +21 -0
- package/dist/bridge/agent-registry.d.ts.map +1 -0
- package/dist/bridge/agent-registry.js +224 -0
- package/dist/bridge/agent-registry.js.map +1 -0
- package/dist/bridge/api-contract-reader.d.ts +55 -0
- package/dist/bridge/api-contract-reader.d.ts.map +1 -0
- package/dist/bridge/api-contract-reader.js +103 -0
- package/dist/bridge/api-contract-reader.js.map +1 -0
- package/dist/bridge/compliance-reader.d.ts +47 -0
- package/dist/bridge/compliance-reader.d.ts.map +1 -0
- package/dist/bridge/compliance-reader.js +91 -0
- package/dist/bridge/compliance-reader.js.map +1 -0
- package/dist/bridge/data-integrity-reader.d.ts +77 -0
- package/dist/bridge/data-integrity-reader.d.ts.map +1 -0
- package/dist/bridge/data-integrity-reader.js +110 -0
- package/dist/bridge/data-integrity-reader.js.map +1 -0
- package/dist/bridge/design-reader.d.ts +51 -0
- package/dist/bridge/design-reader.d.ts.map +1 -0
- package/dist/bridge/design-reader.js +105 -0
- package/dist/bridge/design-reader.js.map +1 -0
- package/dist/bridge/file-scanner.d.ts +21 -0
- package/dist/bridge/file-scanner.d.ts.map +1 -0
- package/dist/bridge/file-scanner.js +117 -0
- package/dist/bridge/file-scanner.js.map +1 -0
- package/dist/bridge/finding-normalize.d.ts +24 -0
- package/dist/bridge/finding-normalize.d.ts.map +1 -0
- package/dist/bridge/finding-normalize.js +46 -0
- package/dist/bridge/finding-normalize.js.map +1 -0
- package/dist/bridge/http-client.d.ts +44 -0
- package/dist/bridge/http-client.d.ts.map +1 -0
- package/dist/bridge/http-client.js +130 -0
- package/dist/bridge/http-client.js.map +1 -0
- package/dist/bridge/knowledge-reader.d.ts +10 -0
- package/dist/bridge/knowledge-reader.d.ts.map +1 -0
- package/dist/bridge/knowledge-reader.js +46 -0
- package/dist/bridge/knowledge-reader.js.map +1 -0
- package/dist/bridge/loop-engine-reader.d.ts +77 -0
- package/dist/bridge/loop-engine-reader.d.ts.map +1 -0
- package/dist/bridge/loop-engine-reader.js +73 -0
- package/dist/bridge/loop-engine-reader.js.map +1 -0
- package/dist/bridge/playwright-pool.d.ts +33 -0
- package/dist/bridge/playwright-pool.d.ts.map +1 -0
- package/dist/bridge/playwright-pool.js +89 -0
- package/dist/bridge/playwright-pool.js.map +1 -0
- package/dist/bridge/rate-limiter.d.ts +40 -0
- package/dist/bridge/rate-limiter.d.ts.map +1 -0
- package/dist/bridge/rate-limiter.js +33 -0
- package/dist/bridge/rate-limiter.js.map +1 -0
- package/dist/bridge/reliability-reader.d.ts +67 -0
- package/dist/bridge/reliability-reader.d.ts.map +1 -0
- package/dist/bridge/reliability-reader.js +146 -0
- package/dist/bridge/reliability-reader.js.map +1 -0
- package/dist/bridge/router.d.ts +26 -0
- package/dist/bridge/router.d.ts.map +1 -0
- package/dist/bridge/router.js +137 -0
- package/dist/bridge/router.js.map +1 -0
- package/dist/bridge/run-stream.d.ts +47 -0
- package/dist/bridge/run-stream.d.ts.map +1 -0
- package/dist/bridge/run-stream.js +67 -0
- package/dist/bridge/run-stream.js.map +1 -0
- package/dist/bridge/runs-reader.d.ts +41 -0
- package/dist/bridge/runs-reader.d.ts.map +1 -0
- package/dist/bridge/runs-reader.js +185 -0
- package/dist/bridge/runs-reader.js.map +1 -0
- package/dist/bridge/sentinel-reader.d.ts +55 -0
- package/dist/bridge/sentinel-reader.d.ts.map +1 -0
- package/dist/bridge/sentinel-reader.js +88 -0
- package/dist/bridge/sentinel-reader.js.map +1 -0
- package/dist/bridge/server.d.ts +83 -0
- package/dist/bridge/server.d.ts.map +1 -0
- package/dist/bridge/server.js +1103 -0
- package/dist/bridge/server.js.map +1 -0
- package/dist/bridge/shell-executor.d.ts +49 -0
- package/dist/bridge/shell-executor.d.ts.map +1 -0
- package/dist/bridge/shell-executor.js +181 -0
- package/dist/bridge/shell-executor.js.map +1 -0
- package/dist/bridge/tech-debt-reader.d.ts +57 -0
- package/dist/bridge/tech-debt-reader.d.ts.map +1 -0
- package/dist/bridge/tech-debt-reader.js +119 -0
- package/dist/bridge/tech-debt-reader.js.map +1 -0
- package/dist/bridge/types.d.ts +63 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +7 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/clients/agent-mvp.d.ts +68 -0
- package/dist/clients/agent-mvp.d.ts.map +1 -0
- package/dist/clients/agent-mvp.js +102 -0
- package/dist/clients/agent-mvp.js.map +1 -0
- package/dist/clients/llm-council.d.ts +47 -0
- package/dist/clients/llm-council.d.ts.map +1 -0
- package/dist/clients/llm-council.js +52 -0
- package/dist/clients/llm-council.js.map +1 -0
- package/dist/clients/total-recall.d.ts +37 -0
- package/dist/clients/total-recall.d.ts.map +1 -0
- package/dist/clients/total-recall.js +239 -0
- package/dist/clients/total-recall.js.map +1 -0
- package/dist/core/agent-contract.d.ts +21 -0
- package/dist/core/agent-contract.d.ts.map +1 -0
- package/dist/core/agent-contract.js +18 -0
- package/dist/core/agent-contract.js.map +1 -0
- package/dist/core/api-contract/api-contract-validator.d.ts +178 -0
- package/dist/core/api-contract/api-contract-validator.d.ts.map +1 -0
- package/dist/core/api-contract/api-contract-validator.js +796 -0
- package/dist/core/api-contract/api-contract-validator.js.map +1 -0
- package/dist/core/api-contract/index.d.ts +16 -0
- package/dist/core/api-contract/index.d.ts.map +1 -0
- package/dist/core/api-contract/index.js +24 -0
- package/dist/core/api-contract/index.js.map +1 -0
- package/dist/core/api-contract/types.d.ts +235 -0
- package/dist/core/api-contract/types.d.ts.map +1 -0
- package/dist/core/api-contract/types.js +27 -0
- package/dist/core/api-contract/types.js.map +1 -0
- package/dist/core/blackboard/blackboard.d.ts +34 -0
- package/dist/core/blackboard/blackboard.d.ts.map +1 -0
- package/dist/core/blackboard/blackboard.js +133 -0
- package/dist/core/blackboard/blackboard.js.map +1 -0
- package/dist/core/blackboard/coordination.d.ts +27 -0
- package/dist/core/blackboard/coordination.d.ts.map +1 -0
- package/dist/core/blackboard/coordination.js +31 -0
- package/dist/core/blackboard/coordination.js.map +1 -0
- package/dist/core/blackboard/direct-channel.d.ts +26 -0
- package/dist/core/blackboard/direct-channel.d.ts.map +1 -0
- package/dist/core/blackboard/direct-channel.js +26 -0
- package/dist/core/blackboard/direct-channel.js.map +1 -0
- package/dist/core/blackboard/index.d.ts +10 -0
- package/dist/core/blackboard/index.d.ts.map +1 -0
- package/dist/core/blackboard/index.js +4 -0
- package/dist/core/blackboard/index.js.map +1 -0
- package/dist/core/blackboard/types.d.ts +36 -0
- package/dist/core/blackboard/types.d.ts.map +1 -0
- package/dist/core/blackboard/types.js +2 -0
- package/dist/core/blackboard/types.js.map +1 -0
- package/dist/core/canvas/schema.d.ts +81 -0
- package/dist/core/canvas/schema.d.ts.map +1 -0
- package/dist/core/canvas/schema.js +144 -0
- package/dist/core/canvas/schema.js.map +1 -0
- package/dist/core/canvas/store.d.ts +41 -0
- package/dist/core/canvas/store.d.ts.map +1 -0
- package/dist/core/canvas/store.js +121 -0
- package/dist/core/canvas/store.js.map +1 -0
- package/dist/core/ci-output.d.ts +1 -1
- package/dist/core/ci-output.d.ts.map +1 -1
- package/dist/core/ci-output.js +2 -0
- package/dist/core/ci-output.js.map +1 -1
- package/dist/core/cli.d.ts +15 -1
- package/dist/core/cli.d.ts.map +1 -1
- package/dist/core/cli.js +416 -35
- package/dist/core/cli.js.map +1 -1
- package/dist/core/compliance/auditor.d.ts +119 -0
- package/dist/core/compliance/auditor.d.ts.map +1 -0
- package/dist/core/compliance/auditor.js +577 -0
- package/dist/core/compliance/auditor.js.map +1 -0
- package/dist/core/compliance/index.d.ts +11 -0
- package/dist/core/compliance/index.d.ts.map +1 -0
- package/dist/core/compliance/index.js +10 -0
- package/dist/core/compliance/index.js.map +1 -0
- package/dist/core/compliance/types.d.ts +174 -0
- package/dist/core/compliance/types.d.ts.map +1 -0
- package/dist/core/compliance/types.js +12 -0
- package/dist/core/compliance/types.js.map +1 -0
- package/dist/core/conductor/conductor.d.ts +37 -0
- package/dist/core/conductor/conductor.d.ts.map +1 -0
- package/dist/core/conductor/conductor.js +96 -0
- package/dist/core/conductor/conductor.js.map +1 -0
- package/dist/core/conductor/index.d.ts +9 -0
- package/dist/core/conductor/index.d.ts.map +1 -0
- package/dist/core/conductor/index.js +3 -0
- package/dist/core/conductor/index.js.map +1 -0
- package/dist/core/conductor/model-router.d.ts +17 -0
- package/dist/core/conductor/model-router.d.ts.map +1 -0
- package/dist/core/conductor/model-router.js +29 -0
- package/dist/core/conductor/model-router.js.map +1 -0
- package/dist/core/conductor/types.d.ts +33 -0
- package/dist/core/conductor/types.d.ts.map +1 -0
- package/dist/core/conductor/types.js +2 -0
- package/dist/core/conductor/types.js.map +1 -0
- package/dist/core/config.d.ts +148 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +53 -4
- package/dist/core/config.js.map +1 -1
- package/dist/core/data-integrity/data-integrity.d.ts +291 -0
- package/dist/core/data-integrity/data-integrity.d.ts.map +1 -0
- package/dist/core/data-integrity/data-integrity.js +892 -0
- package/dist/core/data-integrity/data-integrity.js.map +1 -0
- package/dist/core/data-integrity/index.d.ts +16 -0
- package/dist/core/data-integrity/index.d.ts.map +1 -0
- package/dist/core/data-integrity/index.js +17 -0
- package/dist/core/data-integrity/index.js.map +1 -0
- package/dist/core/data-integrity/types.d.ts +236 -0
- package/dist/core/data-integrity/types.d.ts.map +1 -0
- package/dist/core/data-integrity/types.js +14 -0
- package/dist/core/data-integrity/types.js.map +1 -0
- package/dist/core/disaster-recovery/index.d.ts +13 -0
- package/dist/core/disaster-recovery/index.d.ts.map +1 -0
- package/dist/core/disaster-recovery/index.js +3 -0
- package/dist/core/disaster-recovery/index.js.map +1 -0
- package/dist/core/disaster-recovery/simulator.d.ts +158 -0
- package/dist/core/disaster-recovery/simulator.d.ts.map +1 -0
- package/dist/core/disaster-recovery/simulator.js +553 -0
- package/dist/core/disaster-recovery/simulator.js.map +1 -0
- package/dist/core/disaster-recovery/types.d.ts +299 -0
- package/dist/core/disaster-recovery/types.d.ts.map +1 -0
- package/dist/core/disaster-recovery/types.js +33 -0
- package/dist/core/disaster-recovery/types.js.map +1 -0
- package/dist/core/escalation/heal-or-ask.d.ts +20 -0
- package/dist/core/escalation/heal-or-ask.d.ts.map +1 -0
- package/dist/core/escalation/heal-or-ask.js +19 -0
- package/dist/core/escalation/heal-or-ask.js.map +1 -0
- package/dist/core/escalation/index.d.ts +9 -0
- package/dist/core/escalation/index.d.ts.map +1 -0
- package/dist/core/escalation/index.js +3 -0
- package/dist/core/escalation/index.js.map +1 -0
- package/dist/core/escalation/pause-gate.d.ts +48 -0
- package/dist/core/escalation/pause-gate.d.ts.map +1 -0
- package/dist/core/escalation/pause-gate.js +96 -0
- package/dist/core/escalation/pause-gate.js.map +1 -0
- package/dist/core/escalation/types.d.ts +33 -0
- package/dist/core/escalation/types.d.ts.map +1 -0
- package/dist/core/escalation/types.js +9 -0
- package/dist/core/escalation/types.js.map +1 -0
- package/dist/core/evidence.d.ts +32 -1
- package/dist/core/evidence.d.ts.map +1 -1
- package/dist/core/evidence.js +99 -1
- package/dist/core/evidence.js.map +1 -1
- package/dist/core/feature-bdd/fix.d.ts +84 -0
- package/dist/core/feature-bdd/fix.d.ts.map +1 -0
- package/dist/core/feature-bdd/fix.js +121 -0
- package/dist/core/feature-bdd/fix.js.map +1 -0
- package/dist/core/feature-bdd/generate.d.ts +96 -0
- package/dist/core/feature-bdd/generate.d.ts.map +1 -0
- package/dist/core/feature-bdd/generate.js +228 -0
- package/dist/core/feature-bdd/generate.js.map +1 -0
- package/dist/core/feature-bdd/llm-provider.d.ts +92 -0
- package/dist/core/feature-bdd/llm-provider.d.ts.map +1 -0
- package/dist/core/feature-bdd/llm-provider.js +187 -0
- package/dist/core/feature-bdd/llm-provider.js.map +1 -0
- package/dist/core/feature-bdd/run.d.ts +56 -0
- package/dist/core/feature-bdd/run.d.ts.map +1 -0
- package/dist/core/feature-bdd/run.js +175 -0
- package/dist/core/feature-bdd/run.js.map +1 -0
- package/dist/core/feature-bdd/schema.d.ts +111 -0
- package/dist/core/feature-bdd/schema.d.ts.map +1 -0
- package/dist/core/feature-bdd/schema.js +272 -0
- package/dist/core/feature-bdd/schema.js.map +1 -0
- package/dist/core/feature-bdd/store.d.ts +145 -0
- package/dist/core/feature-bdd/store.d.ts.map +1 -0
- package/dist/core/feature-bdd/store.js +470 -0
- package/dist/core/feature-bdd/store.js.map +1 -0
- package/dist/core/finding-correlation.d.ts +55 -0
- package/dist/core/finding-correlation.d.ts.map +1 -0
- package/dist/core/finding-correlation.js +96 -0
- package/dist/core/finding-correlation.js.map +1 -0
- package/dist/core/fix-loop.d.ts +20 -1
- package/dist/core/fix-loop.d.ts.map +1 -1
- package/dist/core/fix-loop.js +34 -0
- package/dist/core/fix-loop.js.map +1 -1
- package/dist/core/governance/calibration.d.ts +31 -0
- package/dist/core/governance/calibration.d.ts.map +1 -0
- package/dist/core/governance/calibration.js +78 -0
- package/dist/core/governance/calibration.js.map +1 -0
- package/dist/core/governance/degradation.d.ts +35 -0
- package/dist/core/governance/degradation.d.ts.map +1 -0
- package/dist/core/governance/degradation.js +25 -0
- package/dist/core/governance/degradation.js.map +1 -0
- package/dist/core/governance/ethical-constraint.d.ts +55 -0
- package/dist/core/governance/ethical-constraint.d.ts.map +1 -0
- package/dist/core/governance/ethical-constraint.js +98 -0
- package/dist/core/governance/ethical-constraint.js.map +1 -0
- package/dist/core/governance/index.d.ts +9 -0
- package/dist/core/governance/index.d.ts.map +1 -0
- package/dist/core/governance/index.js +9 -0
- package/dist/core/governance/index.js.map +1 -0
- package/dist/core/harness/audit-log.d.ts +12 -0
- package/dist/core/harness/audit-log.d.ts.map +1 -0
- package/dist/core/harness/audit-log.js +62 -0
- package/dist/core/harness/audit-log.js.map +1 -0
- package/dist/core/harness/authorization.d.ts +24 -0
- package/dist/core/harness/authorization.d.ts.map +1 -0
- package/dist/core/harness/authorization.js +48 -0
- package/dist/core/harness/authorization.js.map +1 -0
- package/dist/core/harness/harness.d.ts +64 -0
- package/dist/core/harness/harness.d.ts.map +1 -0
- package/dist/core/harness/harness.js +188 -0
- package/dist/core/harness/harness.js.map +1 -0
- package/dist/core/harness/index.d.ts +10 -0
- package/dist/core/harness/index.d.ts.map +1 -0
- package/dist/core/harness/index.js +4 -0
- package/dist/core/harness/index.js.map +1 -0
- package/dist/core/harness/types.d.ts +88 -0
- package/dist/core/harness/types.d.ts.map +1 -0
- package/dist/core/harness/types.js +2 -0
- package/dist/core/harness/types.js.map +1 -0
- package/dist/core/health-check.d.ts +6 -0
- package/dist/core/health-check.d.ts.map +1 -1
- package/dist/core/health-check.js +14 -2
- package/dist/core/health-check.js.map +1 -1
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +58 -18
- package/dist/core/init.js.map +1 -1
- package/dist/core/knowledge/cached-map.d.ts +17 -0
- package/dist/core/knowledge/cached-map.d.ts.map +1 -0
- package/dist/core/knowledge/cached-map.js +23 -0
- package/dist/core/knowledge/cached-map.js.map +1 -0
- package/dist/core/knowledge/index.d.ts +10 -0
- package/dist/core/knowledge/index.d.ts.map +1 -0
- package/dist/core/knowledge/index.js +4 -0
- package/dist/core/knowledge/index.js.map +1 -0
- package/dist/core/knowledge/system-map.d.ts +50 -0
- package/dist/core/knowledge/system-map.d.ts.map +1 -0
- package/dist/core/knowledge/system-map.js +121 -0
- package/dist/core/knowledge/system-map.js.map +1 -0
- package/dist/core/knowledge/traversal.d.ts +12 -0
- package/dist/core/knowledge/traversal.d.ts.map +1 -0
- package/dist/core/knowledge/traversal.js +37 -0
- package/dist/core/knowledge/traversal.js.map +1 -0
- package/dist/core/knowledge/types.d.ts +41 -0
- package/dist/core/knowledge/types.d.ts.map +1 -0
- package/dist/core/knowledge/types.js +2 -0
- package/dist/core/knowledge/types.js.map +1 -0
- package/dist/core/license-gen.d.ts +1 -1
- package/dist/core/license-gen.d.ts.map +1 -1
- package/dist/core/license-gen.js +10 -5
- package/dist/core/license-gen.js.map +1 -1
- package/dist/core/license.d.ts +12 -2
- package/dist/core/license.d.ts.map +1 -1
- package/dist/core/license.js +104 -28
- package/dist/core/license.js.map +1 -1
- package/dist/core/loop-engine/circuit-breaker.d.ts +24 -0
- package/dist/core/loop-engine/circuit-breaker.d.ts.map +1 -0
- package/dist/core/loop-engine/circuit-breaker.js +48 -0
- package/dist/core/loop-engine/circuit-breaker.js.map +1 -0
- package/dist/core/loop-engine/demo.d.ts +35 -0
- package/dist/core/loop-engine/demo.d.ts.map +1 -0
- package/dist/core/loop-engine/demo.js +71 -0
- package/dist/core/loop-engine/demo.js.map +1 -0
- package/dist/core/loop-engine/event-store.d.ts +8 -0
- package/dist/core/loop-engine/event-store.d.ts.map +1 -0
- package/dist/core/loop-engine/event-store.js +9 -0
- package/dist/core/loop-engine/event-store.js.map +1 -0
- package/dist/core/loop-engine/index.d.ts +11 -0
- package/dist/core/loop-engine/index.d.ts.map +1 -0
- package/dist/core/loop-engine/index.js +11 -0
- package/dist/core/loop-engine/index.js.map +1 -0
- package/dist/core/loop-engine/kernel.d.ts +66 -0
- package/dist/core/loop-engine/kernel.d.ts.map +1 -0
- package/dist/core/loop-engine/kernel.js +196 -0
- package/dist/core/loop-engine/kernel.js.map +1 -0
- package/dist/core/loop-engine/tracing.d.ts +12 -0
- package/dist/core/loop-engine/tracing.d.ts.map +1 -0
- package/dist/core/loop-engine/tracing.js +15 -0
- package/dist/core/loop-engine/tracing.js.map +1 -0
- package/dist/core/loop-engine/types.d.ts +92 -0
- package/dist/core/loop-engine/types.d.ts.map +1 -0
- package/dist/core/loop-engine/types.js +21 -0
- package/dist/core/loop-engine/types.js.map +1 -0
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +101 -1
- package/dist/core/messages.js.map +1 -1
- package/dist/core/orchestrator.d.ts +87 -7
- package/dist/core/orchestrator.d.ts.map +1 -1
- package/dist/core/orchestrator.js +399 -33
- package/dist/core/orchestrator.js.map +1 -1
- package/dist/core/phase-gate.d.ts +2 -2
- package/dist/core/quality-score/calculator.d.ts +125 -0
- package/dist/core/quality-score/calculator.d.ts.map +1 -0
- package/dist/core/quality-score/calculator.js +489 -0
- package/dist/core/quality-score/calculator.js.map +1 -0
- package/dist/core/quality-score/from-run.d.ts +27 -0
- package/dist/core/quality-score/from-run.d.ts.map +1 -0
- package/dist/core/quality-score/from-run.js +64 -0
- package/dist/core/quality-score/from-run.js.map +1 -0
- package/dist/core/quality-score/index.d.ts +9 -0
- package/dist/core/quality-score/index.d.ts.map +1 -0
- package/dist/core/quality-score/index.js +9 -0
- package/dist/core/quality-score/index.js.map +1 -0
- package/dist/core/quality-score/types.d.ts +225 -0
- package/dist/core/quality-score/types.d.ts.map +1 -0
- package/dist/core/quality-score/types.js +26 -0
- package/dist/core/quality-score/types.js.map +1 -0
- package/dist/core/report-html-script.d.ts +3 -0
- package/dist/core/report-html-script.d.ts.map +1 -0
- package/dist/core/report-html-script.js +47 -0
- package/dist/core/report-html-script.js.map +1 -0
- package/dist/core/report-html-styles.d.ts +3 -0
- package/dist/core/report-html-styles.d.ts.map +1 -0
- package/dist/core/report-html-styles.js +231 -0
- package/dist/core/report-html-styles.js.map +1 -0
- package/dist/core/report-html.d.ts +1 -1
- package/dist/core/report-html.d.ts.map +1 -1
- package/dist/core/report-html.js +5 -280
- package/dist/core/report-html.js.map +1 -1
- package/dist/core/report-upload.d.ts +8 -0
- package/dist/core/report-upload.d.ts.map +1 -1
- package/dist/core/report-upload.js +17 -4
- package/dist/core/report-upload.js.map +1 -1
- package/dist/core/run-counter.d.ts.map +1 -1
- package/dist/core/run-counter.js +25 -1
- package/dist/core/run-counter.js.map +1 -1
- package/dist/core/run-events/emitter.d.ts +112 -0
- package/dist/core/run-events/emitter.d.ts.map +1 -0
- package/dist/core/run-events/emitter.js +234 -0
- package/dist/core/run-events/emitter.js.map +1 -0
- package/dist/core/run-events/frame-sink.d.ts +24 -0
- package/dist/core/run-events/frame-sink.d.ts.map +1 -0
- package/dist/core/run-events/frame-sink.js +32 -0
- package/dist/core/run-events/frame-sink.js.map +1 -0
- package/dist/core/run-events/index.d.ts +7 -0
- package/dist/core/run-events/index.d.ts.map +1 -0
- package/dist/core/run-events/index.js +5 -0
- package/dist/core/run-events/index.js.map +1 -0
- package/dist/core/run-events/loop-event-sink.d.ts +56 -0
- package/dist/core/run-events/loop-event-sink.d.ts.map +1 -0
- package/dist/core/run-events/loop-event-sink.js +60 -0
- package/dist/core/run-events/loop-event-sink.js.map +1 -0
- package/dist/core/run-events/sse.d.ts +47 -0
- package/dist/core/run-events/sse.d.ts.map +1 -0
- package/dist/core/run-events/sse.js +64 -0
- package/dist/core/run-events/sse.js.map +1 -0
- package/dist/core/run-events/types.d.ts +147 -0
- package/dist/core/run-events/types.d.ts.map +1 -0
- package/dist/core/run-events/types.js +17 -0
- package/dist/core/run-events/types.js.map +1 -0
- package/dist/core/run-mode/capture.d.ts +37 -0
- package/dist/core/run-mode/capture.d.ts.map +1 -0
- package/dist/core/run-mode/capture.js +43 -0
- package/dist/core/run-mode/capture.js.map +1 -0
- package/dist/core/run-mode/index.d.ts +9 -0
- package/dist/core/run-mode/index.d.ts.map +1 -0
- package/dist/core/run-mode/index.js +3 -0
- package/dist/core/run-mode/index.js.map +1 -0
- package/dist/core/run-mode/run-mode.d.ts +35 -0
- package/dist/core/run-mode/run-mode.d.ts.map +1 -0
- package/dist/core/run-mode/run-mode.js +51 -0
- package/dist/core/run-mode/run-mode.js.map +1 -0
- package/dist/core/run-mode/types.d.ts +36 -0
- package/dist/core/run-mode/types.d.ts.map +1 -0
- package/dist/core/run-mode/types.js +15 -0
- package/dist/core/run-mode/types.js.map +1 -0
- package/dist/core/run-quota.d.ts +22 -0
- package/dist/core/run-quota.d.ts.map +1 -0
- package/dist/core/run-quota.js +44 -0
- package/dist/core/run-quota.js.map +1 -0
- package/dist/core/security-audit/index.d.ts +9 -0
- package/dist/core/security-audit/index.d.ts.map +1 -0
- package/dist/core/security-audit/index.js +10 -0
- package/dist/core/security-audit/index.js.map +1 -0
- package/dist/core/security-audit/sentinel.d.ts +196 -0
- package/dist/core/security-audit/sentinel.d.ts.map +1 -0
- package/dist/core/security-audit/sentinel.js +725 -0
- package/dist/core/security-audit/sentinel.js.map +1 -0
- package/dist/core/security-audit/types.d.ts +240 -0
- package/dist/core/security-audit/types.d.ts.map +1 -0
- package/dist/core/security-audit/types.js +42 -0
- package/dist/core/security-audit/types.js.map +1 -0
- package/dist/core/tech-debt/index.d.ts +11 -0
- package/dist/core/tech-debt/index.d.ts.map +1 -0
- package/dist/core/tech-debt/index.js +11 -0
- package/dist/core/tech-debt/index.js.map +1 -0
- package/dist/core/tech-debt/tech-debt-tracker.d.ts +46 -0
- package/dist/core/tech-debt/tech-debt-tracker.d.ts.map +1 -0
- package/dist/core/tech-debt/tech-debt-tracker.js +533 -0
- package/dist/core/tech-debt/tech-debt-tracker.js.map +1 -0
- package/dist/core/tech-debt/types.d.ts +263 -0
- package/dist/core/tech-debt/types.d.ts.map +1 -0
- package/dist/core/tech-debt/types.js +2 -0
- package/dist/core/tech-debt/types.js.map +1 -0
- package/dist/core/tester/diff-planner.d.ts +18 -0
- package/dist/core/tester/diff-planner.d.ts.map +1 -0
- package/dist/core/tester/diff-planner.js +37 -0
- package/dist/core/tester/diff-planner.js.map +1 -0
- package/dist/core/tester/honest-report.d.ts +13 -0
- package/dist/core/tester/honest-report.d.ts.map +1 -0
- package/dist/core/tester/honest-report.js +64 -0
- package/dist/core/tester/honest-report.js.map +1 -0
- package/dist/core/tester/index.d.ts +9 -0
- package/dist/core/tester/index.d.ts.map +1 -0
- package/dist/core/tester/index.js +3 -0
- package/dist/core/tester/index.js.map +1 -0
- package/dist/core/tester/types.d.ts +55 -0
- package/dist/core/tester/types.d.ts.map +1 -0
- package/dist/core/tester/types.js +8 -0
- package/dist/core/tester/types.js.map +1 -0
- package/dist/core/triggers/index.d.ts +9 -0
- package/dist/core/triggers/index.d.ts.map +1 -0
- package/dist/core/triggers/index.js +3 -0
- package/dist/core/triggers/index.js.map +1 -0
- package/dist/core/triggers/trigger-bus.d.ts +49 -0
- package/dist/core/triggers/trigger-bus.d.ts.map +1 -0
- package/dist/core/triggers/trigger-bus.js +167 -0
- package/dist/core/triggers/trigger-bus.js.map +1 -0
- package/dist/core/triggers/types.d.ts +56 -0
- package/dist/core/triggers/types.d.ts.map +1 -0
- package/dist/core/triggers/types.js +13 -0
- package/dist/core/triggers/types.js.map +1 -0
- package/dist/core/trust.d.ts +12 -0
- package/dist/core/trust.d.ts.map +1 -0
- package/dist/core/trust.js +13 -0
- package/dist/core/trust.js.map +1 -0
- package/dist/core/types.d.ts +24 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/ui-ux/index.d.ts +12 -0
- package/dist/core/ui-ux/index.d.ts.map +1 -0
- package/dist/core/ui-ux/index.js +13 -0
- package/dist/core/ui-ux/index.js.map +1 -0
- package/dist/core/ui-ux/orchestrator.d.ts +206 -0
- package/dist/core/ui-ux/orchestrator.d.ts.map +1 -0
- package/dist/core/ui-ux/orchestrator.js +672 -0
- package/dist/core/ui-ux/orchestrator.js.map +1 -0
- package/dist/core/ui-ux/types.d.ts +339 -0
- package/dist/core/ui-ux/types.d.ts.map +1 -0
- package/dist/core/ui-ux/types.js +17 -0
- package/dist/core/ui-ux/types.js.map +1 -0
- package/dist/enterprise/audit-trail.d.ts +31 -0
- package/dist/enterprise/audit-trail.d.ts.map +1 -0
- package/dist/enterprise/audit-trail.js +111 -0
- package/dist/enterprise/audit-trail.js.map +1 -0
- package/dist/enterprise/sla.d.ts +26 -0
- package/dist/enterprise/sla.d.ts.map +1 -0
- package/dist/enterprise/sla.js +101 -0
- package/dist/enterprise/sla.js.map +1 -0
- package/dist/helpers/element-discovery.js +1 -1
- package/dist/helpers/element-discovery.js.map +1 -1
- package/dist/helpers/env-resolver.d.ts +2 -2
- package/dist/helpers/quality-gate.d.ts.map +1 -1
- package/dist/helpers/quality-gate.js +21 -3
- package/dist/helpers/quality-gate.js.map +1 -1
- package/dist/helpers/shape-fingerprint.d.ts +18 -0
- package/dist/helpers/shape-fingerprint.d.ts.map +1 -0
- package/dist/helpers/shape-fingerprint.js +40 -0
- package/dist/helpers/shape-fingerprint.js.map +1 -0
- package/dist/sdk/custom-agent.d.ts +51 -0
- package/dist/sdk/custom-agent.d.ts.map +1 -0
- package/dist/sdk/custom-agent.js +94 -0
- package/dist/sdk/custom-agent.js.map +1 -0
- package/dist/sdk/index.d.ts +5 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +3 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/loader.d.ts +28 -0
- package/dist/sdk/loader.d.ts.map +1 -0
- package/dist/sdk/loader.js +140 -0
- package/dist/sdk/loader.js.map +1 -0
- package/package.json +46 -20
- package/agents/01-analyst.ts +0 -100
- package/agents/02-seed-architect.ts +0 -59
- package/agents/03-test-generator.ts +0 -191
- package/agents/04-unit-runner.ts +0 -160
- package/agents/05-browser-crawler.ts +0 -790
- package/agents/06-api-exerciser.ts +0 -311
- package/agents/07-security-scout.ts +0 -188
- package/agents/08-a11y-guardian.ts +0 -212
- package/agents/09-healer.ts +0 -228
- package/agents/10-reporter.ts +0 -266
- package/agents/11-fixer.ts +0 -253
- package/agents/12-ux-inspector.ts +0 -444
- package/agents/13-performance-profiler.ts +0 -271
- package/agents/14-data-integrity-auditor.ts +0 -417
- package/agents/15-regression-sentinel.ts +0 -307
- package/agents/16-chaos-agent.ts +0 -228
- package/agents/17-documentation-validator.ts +0 -266
- package/agents/18-integration-watchdog.ts +0 -178
- package/agents/19-tenant-isolation-auditor.ts +0 -199
- package/agents/20-workflow-completion-tester.ts +0 -203
- package/agents/21-state-session-tester.ts +0 -262
- package/agents/22-email-notification-verifier.ts +0 -244
- package/agents/23-migration-tester.ts +0 -80
- package/agents/24-signup-onboarding-tester.ts +0 -429
- package/agents/25-crud-flow-tester.ts +0 -302
- package/agents/26-form-validator.ts +0 -297
- package/agents/27-search-filter-tester.ts +0 -326
- package/agents/28-navigation-routing-tester.ts +0 -425
- package/agents/29-responsive-interaction-tester.ts +0 -350
- package/agents/30-multi-user-scenario-tester.ts +0 -319
- package/agents/31-load-tester.ts +0 -134
- package/agents/32-memory-leak-detector.ts +0 -194
- package/agents/33-bundle-analyzer.ts +0 -132
- package/agents/34-xss-scanner.ts +0 -191
- package/agents/35-csrf-tester.ts +0 -82
- package/agents/36-auth-fuzzer.ts +0 -194
- package/agents/37-dependency-scanner.ts +0 -176
- package/agents/38-secrets-scanner.ts +0 -137
- package/agents/39-api-contract-tester.ts +0 -199
- package/agents/40-rate-limit-tester.ts +0 -94
- package/agents/41-api-pagination-tester.ts +0 -97
- package/agents/42-graphql-tester.ts +0 -222
- package/agents/43-data-consistency-checker.ts +0 -205
- package/agents/44-backup-recovery-tester.ts +0 -152
- package/agents/45-data-privacy-scanner.ts +0 -125
- package/agents/46-seo-auditor.ts +0 -294
- package/agents/47-social-preview-tester.ts +0 -232
- package/agents/48-lighthouse-auditor.ts +0 -213
- package/agents/49-i18n-tester.ts +0 -198
- package/agents/50-timezone-tester.ts +0 -173
- package/agents/51-error-recovery-tester.ts +0 -155
- package/agents/52-offline-mode-tester.ts +0 -180
- package/agents/53-graceful-degradation-tester.ts +0 -156
- package/agents/54-websocket-tester.ts +0 -151
- package/agents/55-realtime-sync-tester.ts +0 -194
- package/agents/56-file-upload-tester.ts +0 -194
- package/agents/57-export-tester.ts +0 -174
- package/agents/58-payment-flow-tester.ts +0 -183
- package/agents/59-ssl-tls-auditor.ts +0 -141
- package/agents/60-dns-cdn-tester.ts +0 -117
- package/agents/61-docker-health-checker.ts +0 -111
- package/agents/62-env-config-validator.ts +0 -152
- package/agents/63-log-quality-auditor.ts +0 -136
- package/agents/64-analytics-tracker-tester.ts +0 -165
- package/agents/65-gdpr-compliance-tester.ts +0 -215
- package/agents/66-soc2-control-validator.ts +0 -210
- package/agents/67-wcag-aaa-tester.ts +0 -241
- package/agents/68-dead-code-detector.ts +0 -135
- package/agents/69-type-safety-auditor.ts +0 -164
- package/agents/70-complexity-analyzer.ts +0 -179
- package/agents/__tests__/01-analyst.test.ts +0 -188
- package/agents/__tests__/02-seed-architect.test.ts +0 -152
- package/agents/__tests__/03-test-generator-full.test.ts +0 -321
- package/agents/__tests__/03-test-generator.test.ts +0 -318
- package/agents/__tests__/04-unit-runner.test.ts +0 -320
- package/agents/__tests__/05-browser-crawler-beta.test.ts +0 -492
- package/agents/__tests__/05-browser-crawler-release.test.ts +0 -412
- package/agents/__tests__/05-browser-crawler-uat.test.ts +0 -578
- package/agents/__tests__/05-browser-crawler.test.ts +0 -518
- package/agents/__tests__/06-api-exerciser.test.ts +0 -619
- package/agents/__tests__/07-security-scout.test.ts +0 -382
- package/agents/__tests__/08-a11y-guardian.test.ts +0 -530
- package/agents/__tests__/09-healer.test.ts +0 -384
- package/agents/__tests__/10-reporter.test.ts +0 -366
- package/agents/__tests__/11-fixer.test.ts +0 -406
- package/agents/__tests__/12-ux-inspector-extended.test.ts +0 -465
- package/agents/__tests__/12-ux-inspector.test.ts +0 -443
- package/agents/__tests__/13-performance-profiler.test.ts +0 -411
- package/agents/__tests__/14-data-integrity-auditor-extended.test.ts +0 -573
- package/agents/__tests__/14-data-integrity-auditor.test.ts +0 -407
- package/agents/__tests__/15-regression-sentinel.test.ts +0 -657
- package/agents/__tests__/16-chaos-agent.test.ts +0 -427
- package/agents/__tests__/17-documentation-validator.test.ts +0 -402
- package/agents/__tests__/18-integration-watchdog.test.ts +0 -263
- package/agents/__tests__/19-tenant-isolation-auditor.test.ts +0 -400
- package/agents/__tests__/20-workflow-completion-tester.test.ts +0 -586
- package/agents/__tests__/21-state-session-tester.test.ts +0 -374
- package/agents/__tests__/22-email-notification-verifier.test.ts +0 -441
- package/agents/__tests__/23-migration-tester.test.ts +0 -145
- package/agents/__tests__/24-signup-onboarding-tester.test.ts +0 -274
- package/agents/__tests__/25-crud-flow-tester.test.ts +0 -322
- package/agents/__tests__/26-form-validator.test.ts +0 -345
- package/agents/__tests__/27-search-filter-tester.test.ts +0 -311
- package/agents/__tests__/28-navigation-routing-tester.test.ts +0 -328
- package/agents/__tests__/29-responsive-interaction-tester.test.ts +0 -297
- package/agents/__tests__/30-multi-user-scenario-tester.test.ts +0 -328
- package/agents/__tests__/31-load-tester.test.ts +0 -189
- package/agents/__tests__/32-memory-leak-detector.test.ts +0 -251
- package/agents/__tests__/33-bundle-analyzer.test.ts +0 -237
- package/agents/__tests__/34-xss-scanner.test.ts +0 -258
- package/agents/__tests__/35-csrf-tester.test.ts +0 -200
- package/agents/__tests__/36-auth-fuzzer.test.ts +0 -214
- package/agents/__tests__/37-dependency-scanner.test.ts +0 -266
- package/agents/__tests__/38-secrets-scanner.test.ts +0 -224
- package/agents/__tests__/39-api-contract-tester.test.ts +0 -312
- package/agents/__tests__/40-rate-limit-tester.test.ts +0 -192
- package/agents/__tests__/41-api-pagination-tester.test.ts +0 -198
- package/agents/__tests__/42-graphql-tester.test.ts +0 -252
- package/agents/__tests__/43-data-consistency-checker.test.ts +0 -232
- package/agents/__tests__/44-backup-recovery-tester.test.ts +0 -222
- package/agents/__tests__/45-data-privacy-scanner.test.ts +0 -223
- package/agents/__tests__/46-seo-auditor.test.ts +0 -261
- package/agents/__tests__/47-social-preview-tester.test.ts +0 -245
- package/agents/__tests__/48-lighthouse-auditor.test.ts +0 -276
- package/agents/__tests__/49-i18n-tester.test.ts +0 -201
- package/agents/__tests__/50-timezone-tester.test.ts +0 -172
- package/agents/__tests__/51-error-recovery-tester.test.ts +0 -162
- package/agents/__tests__/52-offline-mode-tester.test.ts +0 -164
- package/agents/__tests__/53-graceful-degradation-tester.test.ts +0 -168
- package/agents/__tests__/54-websocket-tester.test.ts +0 -157
- package/agents/__tests__/55-realtime-sync-tester.test.ts +0 -181
- package/agents/__tests__/56-file-upload-tester.test.ts +0 -172
- package/agents/__tests__/57-export-tester.test.ts +0 -169
- package/agents/__tests__/58-payment-flow-tester.test.ts +0 -182
- package/agents/__tests__/59-ssl-tls-auditor.test.ts +0 -179
- package/agents/__tests__/60-dns-cdn-tester.test.ts +0 -176
- package/agents/__tests__/61-docker-health-checker.test.ts +0 -150
- package/agents/__tests__/62-env-config-validator.test.ts +0 -166
- package/agents/__tests__/63-log-quality-auditor.test.ts +0 -175
- package/agents/__tests__/64-analytics-tracker-tester.test.ts +0 -158
- package/agents/__tests__/65-gdpr-compliance-tester.test.ts +0 -174
- package/agents/__tests__/66-soc2-control-validator.test.ts +0 -183
- package/agents/__tests__/67-wcag-aaa-tester.test.ts +0 -190
- package/agents/__tests__/68-dead-code-detector.test.ts +0 -174
- package/agents/__tests__/69-type-safety-auditor.test.ts +0 -173
- package/agents/__tests__/70-complexity-analyzer.test.ts +0 -177
- package/agents/__tests__/base-agent.test.ts +0 -188
- package/agents/__tests__/registry.test.ts +0 -218
- package/agents/base-agent.ts +0 -77
- package/agents/registry.ts +0 -277
- package/baselines/api-schemas/.gitkeep +0 -0
- package/baselines/performance/.gitkeep +0 -0
- package/baselines/screenshots/.gitkeep +0 -0
- package/core/__tests__/ci-output.test.ts +0 -430
- package/core/__tests__/cli.test.ts +0 -387
- package/core/__tests__/config.test.ts +0 -78
- package/core/__tests__/cost-tracker.test.ts +0 -158
- package/core/__tests__/evidence.test.ts +0 -265
- package/core/__tests__/fix-loop.test.ts +0 -210
- package/core/__tests__/health-check.test.ts +0 -44
- package/core/__tests__/init.test.ts +0 -609
- package/core/__tests__/integration.test.ts +0 -204
- package/core/__tests__/license-gen.test.ts +0 -227
- package/core/__tests__/license.test.ts +0 -326
- package/core/__tests__/multi-browser.test.ts +0 -278
- package/core/__tests__/orchestrator.test.ts +0 -520
- package/core/__tests__/phase-gate.test.ts +0 -43
- package/core/__tests__/report-html.test.ts +0 -398
- package/core/__tests__/report-upload.test.ts +0 -325
- package/core/__tests__/run-counter.test.ts +0 -234
- package/core/ci-output.ts +0 -240
- package/core/cli.ts +0 -232
- package/core/config.ts +0 -178
- package/core/cost-tracker.ts +0 -59
- package/core/evidence.ts +0 -132
- package/core/fix-loop.ts +0 -85
- package/core/health-check.ts +0 -54
- package/core/init.ts +0 -546
- package/core/license-gen.ts +0 -212
- package/core/license.ts +0 -208
- package/core/messages.ts +0 -67
- package/core/multi-browser.ts +0 -136
- package/core/orchestrator.ts +0 -356
- package/core/phase-gate.ts +0 -55
- package/core/report-html.ts +0 -657
- package/core/report-upload.ts +0 -188
- package/core/run-counter.ts +0 -175
- package/core/types.ts +0 -57
- package/dist/core/multi-browser.d.ts +0 -36
- package/dist/core/multi-browser.d.ts.map +0 -1
- package/dist/core/multi-browser.js +0 -88
- package/dist/core/multi-browser.js.map +0 -1
- package/helpers/__tests__/api-client.test.ts +0 -199
- package/helpers/__tests__/element-discovery.test.ts +0 -202
- package/helpers/__tests__/form-filler-extended.test.ts +0 -212
- package/helpers/__tests__/form-filler.test.ts +0 -99
- package/helpers/__tests__/modal-handler.test.ts +0 -152
- package/helpers/__tests__/navigation.test.ts +0 -214
- package/helpers/__tests__/quality-gate.test.ts +0 -117
- package/helpers/__tests__/screenshot.test.ts +0 -139
- package/helpers/__tests__/seed-validator.test.ts +0 -114
- package/helpers/api-client.ts +0 -111
- package/helpers/element-discovery.ts +0 -105
- package/helpers/env-resolver.ts +0 -69
- package/helpers/form-filler.ts +0 -126
- package/helpers/modal-handler.ts +0 -108
- package/helpers/navigation.ts +0 -100
- package/helpers/quality-gate.ts +0 -180
- package/helpers/screenshot.ts +0 -111
- package/helpers/seed-validator.ts +0 -70
|
@@ -0,0 +1,1203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Localhost Walkthrough Agent — autonomously exercises the target app on
|
|
3
|
+
* localhost using the connection map produced by Agent #87.
|
|
4
|
+
*
|
|
5
|
+
* For every HTTP route discovered, sends a request through a native fetch
|
|
6
|
+
* client and surfaces any 5xx, network error, or unexpected status as a
|
|
7
|
+
* finding. For every UI module declared in the user's config, opens it in
|
|
8
|
+
* Playwright, captures console errors, and (where forms are detected) fills
|
|
9
|
+
* them with helpers/form-filler.ts test values and submits.
|
|
10
|
+
*
|
|
11
|
+
* Dev-server lifecycle: tries `config.devServer.command` first; falls back
|
|
12
|
+
* to `npm run dev` if the target project's package.json has that script.
|
|
13
|
+
* Waits for `config.devServer.healthUrl` (or `http://localhost:<port>/`)
|
|
14
|
+
* to return any 2xx/3xx/4xx response. The server process is torn down in
|
|
15
|
+
* a finally block so we never leak it.
|
|
16
|
+
*
|
|
17
|
+
* Stagehand (#85) fallback: when a UI route fails the deterministic walk
|
|
18
|
+
* AND the @browserbasehq/stagehand dep is reachable, attempt a single
|
|
19
|
+
* Stagehand-driven retry under the existing $0.10/test cost cap. If the
|
|
20
|
+
* dep is absent, surface that a fallback would have engaged.
|
|
21
|
+
*/
|
|
22
|
+
import { spawn } from 'node:child_process';
|
|
23
|
+
import { randomBytes } from 'node:crypto';
|
|
24
|
+
import * as fs from 'node:fs';
|
|
25
|
+
import * as path from 'node:path';
|
|
26
|
+
import { BaseAgent } from './base-agent.js';
|
|
27
|
+
import { launchOptions, startScreencast } from '../core/run-mode/index.js';
|
|
28
|
+
import { fillForm } from '../helpers/form-filler.js';
|
|
29
|
+
import { inferShape } from '../helpers/shape-fingerprint.js';
|
|
30
|
+
const DEFAULT_READY_TIMEOUT_MS = 60_000;
|
|
31
|
+
const ROUTE_REQUEST_TIMEOUT_MS = 8_000;
|
|
32
|
+
const MAX_ROUTES_PER_RUN = 60;
|
|
33
|
+
const MAX_UI_MODULES_PER_RUN = 20;
|
|
34
|
+
function readJson(file) {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Resolve a dev-server descriptor from explicit config first, npm script second. */
|
|
43
|
+
export function resolveDevServer(projectRoot, devServer) {
|
|
44
|
+
if (devServer?.command) {
|
|
45
|
+
const port = devServer.port;
|
|
46
|
+
return {
|
|
47
|
+
command: devServer.command,
|
|
48
|
+
cwd: devServer.cwd ?? projectRoot,
|
|
49
|
+
port,
|
|
50
|
+
healthUrl: devServer.healthUrl ?? `http://localhost:${port}/`,
|
|
51
|
+
readyText: devServer.readyText,
|
|
52
|
+
readyTimeoutMs: devServer.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,
|
|
53
|
+
source: 'config',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const pkg = readJson(path.join(projectRoot, 'package.json'));
|
|
57
|
+
if (!pkg?.scripts?.['dev']) {
|
|
58
|
+
return { error: 'No devServer config and no `dev` script in package.json' };
|
|
59
|
+
}
|
|
60
|
+
const port = devServer?.port ?? 3000;
|
|
61
|
+
return {
|
|
62
|
+
command: 'npm run dev',
|
|
63
|
+
cwd: devServer?.cwd ?? projectRoot,
|
|
64
|
+
port,
|
|
65
|
+
healthUrl: devServer?.healthUrl ?? `http://localhost:${port}/`,
|
|
66
|
+
readyText: devServer?.readyText,
|
|
67
|
+
readyTimeoutMs: devServer?.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,
|
|
68
|
+
source: 'autodetect',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function waitForReady(url, timeoutMs, child, hasErrored) {
|
|
72
|
+
const deadline = Date.now() + timeoutMs;
|
|
73
|
+
while (Date.now() < deadline) {
|
|
74
|
+
if (hasErrored?.())
|
|
75
|
+
return false; // spawn failed (ENOENT/EACCES) — stop polling now
|
|
76
|
+
if (child.exitCode !== null)
|
|
77
|
+
return false;
|
|
78
|
+
try {
|
|
79
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(2_000) });
|
|
80
|
+
// Any HTTP response means the server is listening (even 404).
|
|
81
|
+
if (res.status > 0)
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Connection refused / abort — keep polling.
|
|
86
|
+
}
|
|
87
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
function killTree(child) {
|
|
92
|
+
if (child.exitCode !== null || child.killed)
|
|
93
|
+
return;
|
|
94
|
+
try {
|
|
95
|
+
// Negative PID kills the whole process group on POSIX (we spawned with detached:true).
|
|
96
|
+
if (process.platform !== 'win32' && child.pid) {
|
|
97
|
+
process.kill(-child.pid, 'SIGTERM');
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
child.kill('SIGTERM');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// best effort
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Common login route paths searched when `config.auth.loginUrl` is absent.
|
|
109
|
+
* Order matters — more specific patterns first.
|
|
110
|
+
*/
|
|
111
|
+
const LOGIN_PATH_PATTERNS = [
|
|
112
|
+
/^\/api\/auth\/(?:login|sign[-_]?in|session)s?$/i,
|
|
113
|
+
/^\/api\/(?:login|sign[-_]?in|sessions?)$/i,
|
|
114
|
+
/^\/auth\/(?:login|sign[-_]?in|session)s?$/i,
|
|
115
|
+
/^\/(?:login|sign[-_]?in)$/i,
|
|
116
|
+
/^\/sessions?$/i,
|
|
117
|
+
];
|
|
118
|
+
/**
|
|
119
|
+
* Common logout route paths searched when `config.auth.logoutUrl` is absent.
|
|
120
|
+
* Mirrors the login-path list — logout endpoints almost always live under
|
|
121
|
+
* the same prefix as their login counterpart.
|
|
122
|
+
*/
|
|
123
|
+
const LOGOUT_PATH_PATTERNS = [
|
|
124
|
+
/^\/api\/auth\/(?:logout|sign[-_]?out|session)s?$/i,
|
|
125
|
+
/^\/api\/(?:logout|sign[-_]?out|sessions?)$/i,
|
|
126
|
+
/^\/auth\/(?:logout|sign[-_]?out|session)s?$/i,
|
|
127
|
+
/^\/(?:logout|sign[-_]?out)$/i,
|
|
128
|
+
/^\/sessions?$/i,
|
|
129
|
+
];
|
|
130
|
+
/**
|
|
131
|
+
* Common refresh-token route paths searched when `config.auth.refreshUrl`
|
|
132
|
+
* is absent. Refresh endpoints usually sit next to login under the same
|
|
133
|
+
* prefix.
|
|
134
|
+
*/
|
|
135
|
+
const REFRESH_PATH_PATTERNS = [
|
|
136
|
+
/^\/api\/auth\/(?:refresh|refresh[-_]?token|token\/refresh)\/?$/i,
|
|
137
|
+
/^\/api\/(?:refresh|refresh[-_]?token|token\/refresh|token)\/?$/i,
|
|
138
|
+
/^\/auth\/(?:refresh|refresh[-_]?token|token\/refresh)\/?$/i,
|
|
139
|
+
/^\/(?:refresh|refresh[-_]?token)\/?$/i,
|
|
140
|
+
];
|
|
141
|
+
const JSON_BEARER_KEYS = [
|
|
142
|
+
'token',
|
|
143
|
+
'accessToken',
|
|
144
|
+
'access_token',
|
|
145
|
+
'jwt',
|
|
146
|
+
'authToken',
|
|
147
|
+
'auth_token',
|
|
148
|
+
'idToken',
|
|
149
|
+
'id_token',
|
|
150
|
+
];
|
|
151
|
+
const JSON_REFRESH_KEYS = [
|
|
152
|
+
'refreshToken',
|
|
153
|
+
'refresh_token',
|
|
154
|
+
'refresh',
|
|
155
|
+
];
|
|
156
|
+
/** Pull a refresh token from common locations in a login response body. */
|
|
157
|
+
export function extractRefreshToken(body) {
|
|
158
|
+
if (!body || typeof body !== 'object')
|
|
159
|
+
return null;
|
|
160
|
+
const obj = body;
|
|
161
|
+
for (const key of JSON_REFRESH_KEYS) {
|
|
162
|
+
const v = obj[key];
|
|
163
|
+
if (typeof v === 'string' && v.length > 0)
|
|
164
|
+
return v;
|
|
165
|
+
}
|
|
166
|
+
if (obj.data && typeof obj.data === 'object') {
|
|
167
|
+
const nested = extractRefreshToken(obj.data);
|
|
168
|
+
if (nested)
|
|
169
|
+
return nested;
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
/** Pull the bearer token from any common location in a login response body. */
|
|
174
|
+
export function extractBearer(body) {
|
|
175
|
+
if (!body || typeof body !== 'object')
|
|
176
|
+
return null;
|
|
177
|
+
const obj = body;
|
|
178
|
+
for (const key of JSON_BEARER_KEYS) {
|
|
179
|
+
const v = obj[key];
|
|
180
|
+
if (typeof v === 'string' && v.length > 0)
|
|
181
|
+
return v;
|
|
182
|
+
}
|
|
183
|
+
// Nested under .data — common in Rails/Laravel/NestJS responses.
|
|
184
|
+
if (obj.data && typeof obj.data === 'object') {
|
|
185
|
+
const nested = extractBearer(obj.data);
|
|
186
|
+
if (nested)
|
|
187
|
+
return nested;
|
|
188
|
+
}
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
/** Parse a single Set-Cookie header value into { name, value }, stripping attributes. */
|
|
192
|
+
export function parseSetCookie(header) {
|
|
193
|
+
const first = header.split(';', 1)[0]?.trim();
|
|
194
|
+
if (!first)
|
|
195
|
+
return null;
|
|
196
|
+
const eq = first.indexOf('=');
|
|
197
|
+
if (eq <= 0)
|
|
198
|
+
return null;
|
|
199
|
+
return { name: first.slice(0, eq).trim(), value: first.slice(eq + 1).trim() };
|
|
200
|
+
}
|
|
201
|
+
function pickFirstCredential(credentials) {
|
|
202
|
+
if (!credentials)
|
|
203
|
+
return null;
|
|
204
|
+
for (const [role, entry] of Object.entries(credentials)) {
|
|
205
|
+
if (entry.email && entry.password)
|
|
206
|
+
return { role, email: entry.email, password: entry.password };
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
/** Enumerate every credential entry that has both an email and a password. */
|
|
211
|
+
export function listAllCredentials(credentials) {
|
|
212
|
+
if (!credentials)
|
|
213
|
+
return [];
|
|
214
|
+
const out = [];
|
|
215
|
+
for (const [role, entry] of Object.entries(credentials)) {
|
|
216
|
+
if (entry.email && entry.password)
|
|
217
|
+
out.push({ role, email: entry.email, password: entry.password });
|
|
218
|
+
}
|
|
219
|
+
return out;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Path patterns that indicate a route is intended for elevated access only.
|
|
223
|
+
* If a non-first role can hit a 2xx response on one of these, that's a likely
|
|
224
|
+
* authorization-bypass bug.
|
|
225
|
+
*/
|
|
226
|
+
export const ADMIN_PATH_PATTERNS = [
|
|
227
|
+
/\/admin(?:\/|$|\?)/i,
|
|
228
|
+
/\/internal(?:\/|$|\?)/i,
|
|
229
|
+
/\/staff(?:\/|$|\?)/i,
|
|
230
|
+
/\/management(?:\/|$|\?)/i,
|
|
231
|
+
/\/manage(?:\/|$|\?)/i,
|
|
232
|
+
/\/control[-_]?panel(?:\/|$|\?)/i,
|
|
233
|
+
/\/superuser(?:\/|$|\?)/i,
|
|
234
|
+
/\/sudo(?:\/|$|\?)/i,
|
|
235
|
+
];
|
|
236
|
+
export function isAdminPath(routePath) {
|
|
237
|
+
return ADMIN_PATH_PATTERNS.some((p) => p.test(routePath));
|
|
238
|
+
}
|
|
239
|
+
/** Find the logout URL by config first, then by scanning connection-map routes. */
|
|
240
|
+
export function findLogoutUrl(configuredUrl, routes, baseUrl) {
|
|
241
|
+
if (configuredUrl) {
|
|
242
|
+
if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://'))
|
|
243
|
+
return configuredUrl;
|
|
244
|
+
return baseUrl + (configuredUrl.startsWith('/') ? configuredUrl : `/${configuredUrl}`);
|
|
245
|
+
}
|
|
246
|
+
// Most logout endpoints accept POST or GET; some are DELETE on /sessions.
|
|
247
|
+
const candidates = routes.filter((r) => (r.method === 'POST' || r.method === 'GET' || r.method === 'DELETE' || r.method === 'ALL') &&
|
|
248
|
+
LOGOUT_PATH_PATTERNS.some((p) => p.test(r.path)));
|
|
249
|
+
if (candidates.length === 0)
|
|
250
|
+
return null;
|
|
251
|
+
for (const pat of LOGOUT_PATH_PATTERNS) {
|
|
252
|
+
const hit = candidates.find((r) => pat.test(r.path));
|
|
253
|
+
if (hit)
|
|
254
|
+
return baseUrl + (hit.path.startsWith('/') ? hit.path : `/${hit.path}`);
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
/** Find the refresh-token URL by config first, then connection-map scan. */
|
|
259
|
+
export function findRefreshUrl(configuredUrl, routes, baseUrl) {
|
|
260
|
+
if (configuredUrl) {
|
|
261
|
+
if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://'))
|
|
262
|
+
return configuredUrl;
|
|
263
|
+
return baseUrl + (configuredUrl.startsWith('/') ? configuredUrl : `/${configuredUrl}`);
|
|
264
|
+
}
|
|
265
|
+
const candidates = routes.filter((r) => (r.method === 'POST' || r.method === 'ALL') && REFRESH_PATH_PATTERNS.some((p) => p.test(r.path)));
|
|
266
|
+
if (candidates.length === 0)
|
|
267
|
+
return null;
|
|
268
|
+
for (const pat of REFRESH_PATH_PATTERNS) {
|
|
269
|
+
const hit = candidates.find((r) => pat.test(r.path));
|
|
270
|
+
if (hit)
|
|
271
|
+
return baseUrl + (hit.path.startsWith('/') ? hit.path : `/${hit.path}`);
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* POST to the refresh URL with the captured refresh token (sent both as a
|
|
277
|
+
* JSON body field and via the session cookies, covering body-based and
|
|
278
|
+
* cookie-based refresh schemes). Returns the status and whether a NEW
|
|
279
|
+
* access token / session cookie came back. null on network error.
|
|
280
|
+
*/
|
|
281
|
+
/**
|
|
282
|
+
* Validate that a fetch target is an http(s) URL before issuing an outbound
|
|
283
|
+
* request. Auth-flow URLs are built from discovered/config data, so this barrier
|
|
284
|
+
* keeps requests on http(s) and rejects malformed or other-scheme URLs. Throws
|
|
285
|
+
* on a bad URL; call sites treat a throw as a failed/aborted request.
|
|
286
|
+
*/
|
|
287
|
+
function assertSafeFetchUrl(raw) {
|
|
288
|
+
const parsed = new URL(raw);
|
|
289
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
290
|
+
throw new Error(`unsupported URL scheme: ${parsed.protocol}`);
|
|
291
|
+
}
|
|
292
|
+
return parsed;
|
|
293
|
+
}
|
|
294
|
+
export async function attemptRefresh(refreshUrl, session) {
|
|
295
|
+
const headers = { 'Content-Type': 'application/json', Accept: 'application/json' };
|
|
296
|
+
const cookieHeader = session.cookies.map((c) => `${c.name}=${c.value}`).join('; ');
|
|
297
|
+
if (cookieHeader)
|
|
298
|
+
headers.Cookie = cookieHeader;
|
|
299
|
+
if (session.bearerToken)
|
|
300
|
+
headers.Authorization = `Bearer ${session.bearerToken}`;
|
|
301
|
+
try {
|
|
302
|
+
const res = await fetch(assertSafeFetchUrl(refreshUrl), {
|
|
303
|
+
method: 'POST',
|
|
304
|
+
headers,
|
|
305
|
+
body: JSON.stringify({
|
|
306
|
+
refreshToken: session.refreshToken ?? undefined,
|
|
307
|
+
refresh_token: session.refreshToken ?? undefined,
|
|
308
|
+
}),
|
|
309
|
+
redirect: 'manual',
|
|
310
|
+
signal: AbortSignal.timeout(8_000),
|
|
311
|
+
});
|
|
312
|
+
let gotNewToken = false;
|
|
313
|
+
const setCookies = typeof res.headers.getSetCookie === 'function' ? res.headers.getSetCookie() : [];
|
|
314
|
+
if (setCookies.length > 0)
|
|
315
|
+
gotNewToken = true;
|
|
316
|
+
if ((res.headers.get('content-type') ?? '').includes('application/json')) {
|
|
317
|
+
try {
|
|
318
|
+
const body = await res.clone().json();
|
|
319
|
+
if (extractBearer(body))
|
|
320
|
+
gotNewToken = true;
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
// not JSON — rely on cookies
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return { status: res.status, gotNewToken };
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* POST to the logout URL with the live session attached. Returns the HTTP
|
|
334
|
+
* status (or null on network error). Some apps respond 200, some 204, some
|
|
335
|
+
* 302 — any 2xx/302 counts as accepted; the actual invalidation check is
|
|
336
|
+
* separate.
|
|
337
|
+
*/
|
|
338
|
+
export async function attemptLogout(logoutUrl, session) {
|
|
339
|
+
const headers = { ...sessionHeaders(session) };
|
|
340
|
+
try {
|
|
341
|
+
const res = await fetch(assertSafeFetchUrl(logoutUrl), {
|
|
342
|
+
method: 'POST',
|
|
343
|
+
headers,
|
|
344
|
+
redirect: 'manual',
|
|
345
|
+
signal: AbortSignal.timeout(8_000),
|
|
346
|
+
});
|
|
347
|
+
return { status: res.status };
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* After logout, re-attempt the login URL with the OLD session cookie still
|
|
355
|
+
* attached. Many servers reject by responding 401/403 with the now-invalid
|
|
356
|
+
* cookie — that's the "invalidated" case. If the server returns 2xx or
|
|
357
|
+
* keeps issuing a fresh session for the old cookie, the session wasn't
|
|
358
|
+
* properly destroyed.
|
|
359
|
+
*
|
|
360
|
+
* Returns true if the session appears invalidated (4xx or no cookies in
|
|
361
|
+
* response), false if it still works.
|
|
362
|
+
*/
|
|
363
|
+
export async function verifySessionInvalidated(loginUrl, session) {
|
|
364
|
+
try {
|
|
365
|
+
const res = await fetch(loginUrl, {
|
|
366
|
+
method: 'GET',
|
|
367
|
+
headers: sessionHeaders(session),
|
|
368
|
+
redirect: 'manual',
|
|
369
|
+
signal: AbortSignal.timeout(5_000),
|
|
370
|
+
});
|
|
371
|
+
// 4xx with an authenticated cookie attached = server is correctly rejecting
|
|
372
|
+
if (res.status >= 400 && res.status < 500)
|
|
373
|
+
return true;
|
|
374
|
+
// 2xx = session might still be valid; treat as not invalidated
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
catch {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/** Find the login URL by config first, then by scanning connection-map routes. */
|
|
382
|
+
export function findLoginUrl(configuredUrl, routes, baseUrl) {
|
|
383
|
+
if (configuredUrl) {
|
|
384
|
+
if (configuredUrl.startsWith('http://') || configuredUrl.startsWith('https://'))
|
|
385
|
+
return configuredUrl;
|
|
386
|
+
return baseUrl + (configuredUrl.startsWith('/') ? configuredUrl : `/${configuredUrl}`);
|
|
387
|
+
}
|
|
388
|
+
const candidates = routes.filter((r) => (r.method === 'POST' || r.method === 'ALL') && LOGIN_PATH_PATTERNS.some((p) => p.test(r.path)));
|
|
389
|
+
if (candidates.length === 0)
|
|
390
|
+
return null;
|
|
391
|
+
// Prefer the most specific match: pick by pattern order, not route order.
|
|
392
|
+
for (const pat of LOGIN_PATH_PATTERNS) {
|
|
393
|
+
const hit = candidates.find((r) => pat.test(r.path));
|
|
394
|
+
if (hit)
|
|
395
|
+
return baseUrl + (hit.path.startsWith('/') ? hit.path : `/${hit.path}`);
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
/** Attempt login; returns a session on success, null on failure. */
|
|
400
|
+
async function attemptLogin(loginUrl, role, email, password) {
|
|
401
|
+
const tryBody = async (kind) => {
|
|
402
|
+
try {
|
|
403
|
+
const body = kind === 'json'
|
|
404
|
+
? JSON.stringify({ email, password, username: email })
|
|
405
|
+
: new URLSearchParams({ email, password, username: email }).toString();
|
|
406
|
+
const headers = kind === 'json'
|
|
407
|
+
? { 'Content-Type': 'application/json', Accept: 'application/json' }
|
|
408
|
+
: { 'Content-Type': 'application/x-www-form-urlencoded' };
|
|
409
|
+
return await fetch(assertSafeFetchUrl(loginUrl), {
|
|
410
|
+
method: 'POST',
|
|
411
|
+
headers,
|
|
412
|
+
body,
|
|
413
|
+
redirect: 'manual',
|
|
414
|
+
signal: AbortSignal.timeout(8_000),
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
catch (err) {
|
|
418
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
for (const kind of ['json', 'form']) {
|
|
422
|
+
const res = await tryBody(kind);
|
|
423
|
+
if ('error' in res)
|
|
424
|
+
continue;
|
|
425
|
+
// 2xx, or 302 redirect (common for form login) — both can carry a session cookie.
|
|
426
|
+
if ((res.status >= 200 && res.status < 300) || res.status === 302) {
|
|
427
|
+
const setCookies = typeof res.headers.getSetCookie === 'function' ? res.headers.getSetCookie() : [];
|
|
428
|
+
const cookies = setCookies
|
|
429
|
+
.map(parseSetCookie)
|
|
430
|
+
.filter((c) => c !== null);
|
|
431
|
+
let bearer = null;
|
|
432
|
+
let refresh = null;
|
|
433
|
+
try {
|
|
434
|
+
const ct = res.headers.get('content-type') ?? '';
|
|
435
|
+
if (ct.includes('application/json')) {
|
|
436
|
+
const body = await res.clone().json();
|
|
437
|
+
bearer = extractBearer(body);
|
|
438
|
+
refresh = extractRefreshToken(body);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
catch {
|
|
442
|
+
// body wasn't JSON — that's fine, cookies may carry the session
|
|
443
|
+
}
|
|
444
|
+
if (cookies.length === 0 && !bearer) {
|
|
445
|
+
// No session captured even though response was 2xx — treat as failure.
|
|
446
|
+
return { error: `login ${kind} returned ${res.status} but no session cookie or token` };
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
session: {
|
|
450
|
+
asRole: role,
|
|
451
|
+
loginUrl,
|
|
452
|
+
bodyKind: kind,
|
|
453
|
+
cookies,
|
|
454
|
+
bearerToken: bearer,
|
|
455
|
+
refreshToken: refresh,
|
|
456
|
+
},
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return { error: 'login attempted with both JSON and form bodies; neither succeeded' };
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Probe the login endpoint with a deliberately wrong password. After a real
|
|
464
|
+
* login has already worked we know the endpoint is reachable and the body
|
|
465
|
+
* kind that the app expects, so we can fire a single targeted request and
|
|
466
|
+
* inspect the outcome. A 2xx with a session cookie/token = auth fail-open
|
|
467
|
+
* (critical). 4xx = correctly rejected (silent pass).
|
|
468
|
+
*
|
|
469
|
+
* Returns null if the probe couldn't be run (network error / unsupported
|
|
470
|
+
* scheme); the caller treats null as "inconclusive, no finding".
|
|
471
|
+
*/
|
|
472
|
+
export async function probeBadCredentials(loginUrl, email, bodyKind) {
|
|
473
|
+
// Use a CSPRNG (not Math.random) so the throwaway credential is unpredictable
|
|
474
|
+
// in this security-sensitive auth probe (CodeQL js/insecure-randomness).
|
|
475
|
+
const wrongPassword = '__testteam_definitely_wrong_password_' + randomBytes(6).toString('hex');
|
|
476
|
+
try {
|
|
477
|
+
const body = bodyKind === 'json'
|
|
478
|
+
? JSON.stringify({ email, password: wrongPassword, username: email })
|
|
479
|
+
: new URLSearchParams({ email, password: wrongPassword, username: email }).toString();
|
|
480
|
+
const headers = bodyKind === 'json'
|
|
481
|
+
? { 'Content-Type': 'application/json', Accept: 'application/json' }
|
|
482
|
+
: { 'Content-Type': 'application/x-www-form-urlencoded' };
|
|
483
|
+
const res = await fetch(loginUrl, {
|
|
484
|
+
method: 'POST',
|
|
485
|
+
headers,
|
|
486
|
+
body,
|
|
487
|
+
redirect: 'manual',
|
|
488
|
+
signal: AbortSignal.timeout(8_000),
|
|
489
|
+
});
|
|
490
|
+
const setCookies = typeof res.headers.getSetCookie === 'function' ? res.headers.getSetCookie() : [];
|
|
491
|
+
const cookies = setCookies.map(parseSetCookie).filter((c) => c !== null);
|
|
492
|
+
let bearer = null;
|
|
493
|
+
if ((res.headers.get('content-type') ?? '').includes('application/json')) {
|
|
494
|
+
try {
|
|
495
|
+
bearer = extractBearer(await res.clone().json());
|
|
496
|
+
}
|
|
497
|
+
catch {
|
|
498
|
+
// body wasn't JSON despite header — treat as no bearer
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return { status: res.status, capturedSession: cookies.length > 0 || bearer !== null };
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function sessionHeaders(session) {
|
|
508
|
+
if (!session)
|
|
509
|
+
return {};
|
|
510
|
+
const headers = {};
|
|
511
|
+
if (session.cookies.length > 0) {
|
|
512
|
+
headers.Cookie = session.cookies.map((c) => `${c.name}=${c.value}`).join('; ');
|
|
513
|
+
}
|
|
514
|
+
if (session.bearerToken) {
|
|
515
|
+
headers.Authorization = `Bearer ${session.bearerToken}`;
|
|
516
|
+
}
|
|
517
|
+
return headers;
|
|
518
|
+
}
|
|
519
|
+
function apiRoutesHint(routes) {
|
|
520
|
+
return routes.filter((r) => r.framework !== 'unknown').length;
|
|
521
|
+
}
|
|
522
|
+
export class LocalhostWalkthroughAgent extends BaseAgent {
|
|
523
|
+
agentId = 88;
|
|
524
|
+
agentName = 'Localhost Walkthrough';
|
|
525
|
+
/** Override hook for tests — defaults to real spawn. */
|
|
526
|
+
spawnImpl = spawn;
|
|
527
|
+
async preFlight() {
|
|
528
|
+
const root = this.config.projectRoot ?? process.cwd();
|
|
529
|
+
if (!fs.existsSync(root)) {
|
|
530
|
+
throw new Error(`projectRoot does not exist: ${root}`);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
async execute() {
|
|
534
|
+
const findings = [];
|
|
535
|
+
const projectRoot = this.config.projectRoot ?? process.cwd();
|
|
536
|
+
// Load the connection map from #87. Without it the walk has no targets.
|
|
537
|
+
const mapPath = path.join(this.runDir, 'evidence', 'connection-map.json');
|
|
538
|
+
const map = readJson(mapPath);
|
|
539
|
+
if (!map) {
|
|
540
|
+
findings.push({
|
|
541
|
+
id: `${this.agentId}-no-map`,
|
|
542
|
+
type: 'infra-issue',
|
|
543
|
+
severity: 'high',
|
|
544
|
+
agentId: this.agentId,
|
|
545
|
+
module: 'localhost-walkthrough',
|
|
546
|
+
description: 'connection-map.json not found in run directory. Localhost Walkthrough (#88) requires Connection Mapper (#87) to run first in the same phase.',
|
|
547
|
+
});
|
|
548
|
+
return findings;
|
|
549
|
+
}
|
|
550
|
+
const resolved = resolveDevServer(projectRoot, this.config.devServer);
|
|
551
|
+
if ('error' in resolved) {
|
|
552
|
+
findings.push({
|
|
553
|
+
id: `${this.agentId}-no-dev-server`,
|
|
554
|
+
type: 'infra-issue',
|
|
555
|
+
severity: 'high',
|
|
556
|
+
agentId: this.agentId,
|
|
557
|
+
module: 'localhost-walkthrough',
|
|
558
|
+
description: resolved.error + '. Add a `devServer` block to testteam.config.ts.',
|
|
559
|
+
});
|
|
560
|
+
return findings;
|
|
561
|
+
}
|
|
562
|
+
const telemetry = {
|
|
563
|
+
resolvedDevServer: resolved,
|
|
564
|
+
routesAttempted: 0,
|
|
565
|
+
routesPassed: 0,
|
|
566
|
+
routesFailed: 0,
|
|
567
|
+
uiModulesAttempted: 0,
|
|
568
|
+
uiModulesPassed: 0,
|
|
569
|
+
uiModulesFailed: 0,
|
|
570
|
+
stagehandFallbacks: 0,
|
|
571
|
+
};
|
|
572
|
+
let child = null;
|
|
573
|
+
try {
|
|
574
|
+
// Split the command into argv to use execFile-style spawn — never shell:true
|
|
575
|
+
// (a deliberate shell-injection guard). Note: npm-family launchers can't be
|
|
576
|
+
// started this way on Windows (`spawn('npm')` → ENOENT); that surfaces as a
|
|
577
|
+
// graceful finding below, and a Windows user can point devServer.command at
|
|
578
|
+
// a direct binary. We do NOT relax to shell:true (see the 'error' guard).
|
|
579
|
+
const [bin, ...args] = resolved.command.split(/\s+/);
|
|
580
|
+
// A spawn failure (ENOENT/EACCES/EINVAL/…) can surface ASYNCHRONOUSLY as an
|
|
581
|
+
// 'error' event, not a throw — with NO listener, Node crashes the whole
|
|
582
|
+
// pipeline. Capture it (and any synchronous throw, via the outer try) and
|
|
583
|
+
// degrade to a finding instead of dying.
|
|
584
|
+
let spawnError = null;
|
|
585
|
+
child = this.spawnImpl(bin, args, {
|
|
586
|
+
cwd: resolved.cwd,
|
|
587
|
+
env: { ...process.env, BROWSER: 'none', CI: '1' },
|
|
588
|
+
detached: process.platform !== 'win32',
|
|
589
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
590
|
+
});
|
|
591
|
+
child.on('error', (err) => {
|
|
592
|
+
spawnError = err;
|
|
593
|
+
});
|
|
594
|
+
const ready = await waitForReady(resolved.healthUrl, resolved.readyTimeoutMs, child, () => spawnError !== null);
|
|
595
|
+
// `spawnError` is assigned in the 'error' callback, which may have fired
|
|
596
|
+
// during the await above; the cast defeats CFA narrowing-to-null.
|
|
597
|
+
const failure = spawnError;
|
|
598
|
+
if (failure) {
|
|
599
|
+
findings.push({
|
|
600
|
+
id: `${this.agentId}-dev-server-spawn-failed`,
|
|
601
|
+
type: 'infra-issue',
|
|
602
|
+
severity: 'critical',
|
|
603
|
+
agentId: this.agentId,
|
|
604
|
+
module: 'localhost-walkthrough',
|
|
605
|
+
description: `Dev server (${resolved.command}) failed to start: ${failure.message}. Set a valid devServer.command in testteam.config.ts.`,
|
|
606
|
+
});
|
|
607
|
+
return findings;
|
|
608
|
+
}
|
|
609
|
+
if (!ready) {
|
|
610
|
+
findings.push({
|
|
611
|
+
id: `${this.agentId}-dev-server-not-ready`,
|
|
612
|
+
type: 'infra-issue',
|
|
613
|
+
severity: 'critical',
|
|
614
|
+
agentId: this.agentId,
|
|
615
|
+
module: 'localhost-walkthrough',
|
|
616
|
+
description: `Dev server (${resolved.command}) did not respond on ${resolved.healthUrl} within ${resolved.readyTimeoutMs}ms.`,
|
|
617
|
+
});
|
|
618
|
+
return findings;
|
|
619
|
+
}
|
|
620
|
+
// Attempt login before walking — gives downstream requests an authenticated
|
|
621
|
+
// session so #88 covers more than just public routes.
|
|
622
|
+
const baseUrl = new URL(resolved.healthUrl).origin;
|
|
623
|
+
const { session, attempt } = await this.tryLogin(map.routes, baseUrl);
|
|
624
|
+
this.persistAuthAttempt(attempt);
|
|
625
|
+
if (session) {
|
|
626
|
+
findings.push({
|
|
627
|
+
id: `${this.agentId}-auth-success`,
|
|
628
|
+
type: 'infra-issue',
|
|
629
|
+
severity: 'info',
|
|
630
|
+
agentId: this.agentId,
|
|
631
|
+
module: 'localhost-walkthrough',
|
|
632
|
+
description: `Logged in as "${session.asRole}" via ${session.bodyKind} POST to ${session.loginUrl}. Walking ${apiRoutesHint(map.routes)} routes with session attached.`,
|
|
633
|
+
});
|
|
634
|
+
// Fail-open probe: now that we know the login endpoint works, fire a
|
|
635
|
+
// wrong-password POST and verify it's rejected. A 2xx response with a
|
|
636
|
+
// session cookie/token means auth fails open — critical security bug.
|
|
637
|
+
const probe = await this.runBadCredentialsProbe(session);
|
|
638
|
+
if (probe) {
|
|
639
|
+
if (probe.capturedSession) {
|
|
640
|
+
findings.push({
|
|
641
|
+
id: `${this.agentId}-auth-fail-open`,
|
|
642
|
+
type: 'code-bug-security',
|
|
643
|
+
severity: 'critical',
|
|
644
|
+
agentId: this.agentId,
|
|
645
|
+
module: 'localhost-walkthrough',
|
|
646
|
+
description: `Login endpoint accepted a deliberately wrong password (status ${probe.status}) AND returned a valid session. Authentication is failing open — anyone can log in as "${session.asRole}".`,
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
else if (probe.status >= 200 && probe.status < 300) {
|
|
650
|
+
// 2xx without a session is suspicious but not conclusively broken —
|
|
651
|
+
// many apps return 200 with an error body for "wrong password".
|
|
652
|
+
findings.push({
|
|
653
|
+
id: `${this.agentId}-auth-soft-reject`,
|
|
654
|
+
type: 'code-bug-logic',
|
|
655
|
+
severity: 'medium',
|
|
656
|
+
agentId: this.agentId,
|
|
657
|
+
module: 'localhost-walkthrough',
|
|
658
|
+
description: `Login endpoint returned ${probe.status} on wrong password without a session. Convention is 401/403 — using 2xx with an error body breaks standard auth-handling tooling.`,
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
// 4xx/5xx/302 on a wrong password = correct behaviour; stay silent.
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
else if (attempt.outcome === 'failed') {
|
|
665
|
+
findings.push({
|
|
666
|
+
id: `${this.agentId}-auth-failed`,
|
|
667
|
+
type: 'code-bug-logic',
|
|
668
|
+
severity: 'high',
|
|
669
|
+
agentId: this.agentId,
|
|
670
|
+
module: 'localhost-walkthrough',
|
|
671
|
+
description: `Login attempt failed: ${attempt.reason}. The walk will continue but authenticated routes will return 401/403.`,
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
// Note: 'skipped' (no creds / no login URL) is intentionally silent — the
|
|
675
|
+
// user may be testing a public-only app.
|
|
676
|
+
const authHeaders = sessionHeaders(session);
|
|
677
|
+
// Walk HTTP routes deterministically.
|
|
678
|
+
const apiRoutes = map.routes
|
|
679
|
+
.filter((r) => r.framework !== 'unknown')
|
|
680
|
+
.slice(0, MAX_ROUTES_PER_RUN);
|
|
681
|
+
const captures = [];
|
|
682
|
+
for (const route of apiRoutes) {
|
|
683
|
+
telemetry.routesAttempted++;
|
|
684
|
+
try {
|
|
685
|
+
const url = baseUrl + (route.path.startsWith('/') ? route.path : `/${route.path}`);
|
|
686
|
+
const method = (route.method === 'ALL' ? 'GET' : route.method);
|
|
687
|
+
const res = await fetch(assertSafeFetchUrl(url), {
|
|
688
|
+
method,
|
|
689
|
+
headers: authHeaders,
|
|
690
|
+
signal: AbortSignal.timeout(ROUTE_REQUEST_TIMEOUT_MS),
|
|
691
|
+
});
|
|
692
|
+
const contentType = res.headers.get('content-type');
|
|
693
|
+
let shape = null;
|
|
694
|
+
if (contentType?.includes('application/json')) {
|
|
695
|
+
try {
|
|
696
|
+
const body = await res.clone().json();
|
|
697
|
+
shape = inferShape(body);
|
|
698
|
+
}
|
|
699
|
+
catch {
|
|
700
|
+
// body wasn't valid JSON despite the header — leave shape null
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
captures.push({
|
|
704
|
+
method: route.method,
|
|
705
|
+
path: route.path,
|
|
706
|
+
status: res.status,
|
|
707
|
+
contentType,
|
|
708
|
+
shape,
|
|
709
|
+
file: route.file,
|
|
710
|
+
line: route.line,
|
|
711
|
+
});
|
|
712
|
+
if (res.status >= 500) {
|
|
713
|
+
telemetry.routesFailed++;
|
|
714
|
+
findings.push({
|
|
715
|
+
id: `${this.agentId}-route-5xx-${route.method}-${route.path.replace(/[^\w]/g, '_')}`,
|
|
716
|
+
type: 'code-bug-logic',
|
|
717
|
+
severity: 'high',
|
|
718
|
+
agentId: this.agentId,
|
|
719
|
+
module: 'localhost-walkthrough',
|
|
720
|
+
description: `${route.method} ${route.path} returned ${res.status} (${route.file}:${route.line})`,
|
|
721
|
+
file: route.file,
|
|
722
|
+
line: route.line,
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
else if ((res.status === 401 || res.status === 403) && session) {
|
|
726
|
+
// We had a valid session attached but the route still rejected us.
|
|
727
|
+
// That's a likely authz bug or a mis-attached session, not a routing failure.
|
|
728
|
+
telemetry.routesFailed++;
|
|
729
|
+
findings.push({
|
|
730
|
+
id: `${this.agentId}-route-unauthorized-${route.method}-${route.path.replace(/[^\w]/g, '_')}`,
|
|
731
|
+
type: 'code-bug-logic',
|
|
732
|
+
severity: 'medium',
|
|
733
|
+
agentId: this.agentId,
|
|
734
|
+
module: 'localhost-walkthrough',
|
|
735
|
+
description: `${route.method} ${route.path} returned ${res.status} despite a logged-in session — possible authz misconfiguration (${route.file}:${route.line})`,
|
|
736
|
+
file: route.file,
|
|
737
|
+
line: route.line,
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
telemetry.routesPassed++;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
catch (err) {
|
|
745
|
+
telemetry.routesFailed++;
|
|
746
|
+
findings.push({
|
|
747
|
+
id: `${this.agentId}-route-error-${route.method}-${route.path.replace(/[^\w]/g, '_')}`,
|
|
748
|
+
type: 'code-bug-logic',
|
|
749
|
+
severity: 'medium',
|
|
750
|
+
agentId: this.agentId,
|
|
751
|
+
module: 'localhost-walkthrough',
|
|
752
|
+
description: `${route.method} ${route.path} failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
753
|
+
file: route.file,
|
|
754
|
+
line: route.line,
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
// Persist captures for Agent #90 (Response Shape Validator) to read.
|
|
759
|
+
try {
|
|
760
|
+
const evidenceDir = path.join(this.runDir, 'evidence');
|
|
761
|
+
fs.mkdirSync(evidenceDir, { recursive: true });
|
|
762
|
+
const responsesFile = {
|
|
763
|
+
version: 1,
|
|
764
|
+
generatedAt: new Date().toISOString(),
|
|
765
|
+
baseUrl,
|
|
766
|
+
captures,
|
|
767
|
+
};
|
|
768
|
+
fs.writeFileSync(path.join(evidenceDir, 'route-responses.json'), JSON.stringify(responsesFile, null, 2), 'utf-8');
|
|
769
|
+
this.addEvidence({
|
|
770
|
+
type: 'report',
|
|
771
|
+
path: 'evidence/route-responses.json',
|
|
772
|
+
description: `Route responses captured: ${captures.length} (for #90 drift detection)`,
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
catch {
|
|
776
|
+
// non-fatal — drift detection just won't have new data this run
|
|
777
|
+
}
|
|
778
|
+
// Multi-role authz-bypass probe. If more than one credential is
|
|
779
|
+
// configured, log in as each additional role and probe admin-shaped
|
|
780
|
+
// routes. A 2xx response from a non-first role is a likely
|
|
781
|
+
// authorization bypass — one of the OWASP Top 10 bug classes that's
|
|
782
|
+
// easy to miss because the happy path looks fine.
|
|
783
|
+
if (session) {
|
|
784
|
+
await this.runMultiRoleAuthzProbe(session.asRole, map.routes, baseUrl, findings);
|
|
785
|
+
}
|
|
786
|
+
// Refresh-token flow: exercise the refresh endpoint and verify a new
|
|
787
|
+
// access token is issued. Runs BEFORE logout (logout may revoke the
|
|
788
|
+
// refresh token).
|
|
789
|
+
if (session) {
|
|
790
|
+
await this.runRefreshTest(session, map.routes, baseUrl, findings);
|
|
791
|
+
}
|
|
792
|
+
// Logout flow: exercise the logout endpoint and verify the session
|
|
793
|
+
// is actually invalidated. Session-not-invalidated is a real security
|
|
794
|
+
// bug class — old cookies / tokens continuing to work after logout.
|
|
795
|
+
if (session) {
|
|
796
|
+
await this.runLogoutTest(session, map.routes, baseUrl, findings);
|
|
797
|
+
}
|
|
798
|
+
// Walk declared UI modules with Playwright if the project has any.
|
|
799
|
+
const uiModules = (this.config.modules ?? []).slice(0, MAX_UI_MODULES_PER_RUN);
|
|
800
|
+
if (uiModules.length > 0) {
|
|
801
|
+
const { chromium } = await import('playwright');
|
|
802
|
+
let browser = null;
|
|
803
|
+
let screencast = null;
|
|
804
|
+
try {
|
|
805
|
+
browser = await chromium.launch(launchOptions(this.runMode));
|
|
806
|
+
const context = await browser.newContext();
|
|
807
|
+
if (session && session.cookies.length > 0) {
|
|
808
|
+
const host = new URL(baseUrl).hostname;
|
|
809
|
+
await context.addCookies(session.cookies.map((c) => ({
|
|
810
|
+
name: c.name,
|
|
811
|
+
value: c.value,
|
|
812
|
+
domain: host,
|
|
813
|
+
path: '/',
|
|
814
|
+
})));
|
|
815
|
+
}
|
|
816
|
+
if (session && session.bearerToken) {
|
|
817
|
+
await context.setExtraHTTPHeaders({ Authorization: `Bearer ${session.bearerToken}` });
|
|
818
|
+
}
|
|
819
|
+
const page = await context.newPage();
|
|
820
|
+
screencast = this.frames ? startScreencast(page, this.frames) : null;
|
|
821
|
+
const consoleErrors = [];
|
|
822
|
+
page.on('console', (msg) => {
|
|
823
|
+
if (msg.type() === 'error')
|
|
824
|
+
consoleErrors.push(msg.text());
|
|
825
|
+
});
|
|
826
|
+
page.on('pageerror', (err) => consoleErrors.push(err.message));
|
|
827
|
+
for (const mod of uiModules) {
|
|
828
|
+
telemetry.uiModulesAttempted++;
|
|
829
|
+
const errorsBefore = consoleErrors.length;
|
|
830
|
+
const url = baseUrl + (mod.route.startsWith('/') ? mod.route : `/${mod.route}`);
|
|
831
|
+
try {
|
|
832
|
+
const response = await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 10_000 });
|
|
833
|
+
if (!response || response.status() >= 500) {
|
|
834
|
+
throw new Error(`navigated with status ${response?.status() ?? 'unknown'}`);
|
|
835
|
+
}
|
|
836
|
+
// Attempt to fill any visible forms — failure here is non-fatal.
|
|
837
|
+
try {
|
|
838
|
+
await fillForm(page, '');
|
|
839
|
+
}
|
|
840
|
+
catch {
|
|
841
|
+
// form-filler returns false on missing fields; ignore errors here
|
|
842
|
+
}
|
|
843
|
+
const newErrors = consoleErrors.length - errorsBefore;
|
|
844
|
+
if (newErrors > 0) {
|
|
845
|
+
findings.push({
|
|
846
|
+
id: `${this.agentId}-console-errors-${mod.id}`,
|
|
847
|
+
type: 'code-bug-logic',
|
|
848
|
+
severity: 'medium',
|
|
849
|
+
agentId: this.agentId,
|
|
850
|
+
module: 'localhost-walkthrough',
|
|
851
|
+
description: `${mod.id} (${mod.route}) produced ${newErrors} console error(s) during walk: ${consoleErrors
|
|
852
|
+
.slice(errorsBefore)
|
|
853
|
+
.slice(0, 3)
|
|
854
|
+
.join('; ')}`,
|
|
855
|
+
});
|
|
856
|
+
telemetry.uiModulesFailed++;
|
|
857
|
+
}
|
|
858
|
+
else {
|
|
859
|
+
telemetry.uiModulesPassed++;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
catch (err) {
|
|
863
|
+
telemetry.uiModulesFailed++;
|
|
864
|
+
const stagehandUsed = await this.tryStagehandFallback(url, mod.id);
|
|
865
|
+
if (stagehandUsed)
|
|
866
|
+
telemetry.stagehandFallbacks++;
|
|
867
|
+
findings.push({
|
|
868
|
+
id: `${this.agentId}-ui-failed-${mod.id}`,
|
|
869
|
+
type: 'code-bug-logic',
|
|
870
|
+
severity: 'high',
|
|
871
|
+
agentId: this.agentId,
|
|
872
|
+
module: 'localhost-walkthrough',
|
|
873
|
+
description: `${mod.id} (${mod.route}) failed deterministic walk: ${err instanceof Error ? err.message : String(err)}${stagehandUsed ? ' [Stagehand fallback attempted]' : ' [Stagehand fallback unavailable]'}`,
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
finally {
|
|
879
|
+
screencast?.stop();
|
|
880
|
+
if (browser)
|
|
881
|
+
await browser.close();
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
// Persist telemetry alongside the connection map.
|
|
885
|
+
const telemetryPath = path.join(this.runDir, 'evidence', 'walkthrough-telemetry.json');
|
|
886
|
+
try {
|
|
887
|
+
fs.writeFileSync(telemetryPath, JSON.stringify(telemetry, null, 2), 'utf-8');
|
|
888
|
+
this.addEvidence({
|
|
889
|
+
type: 'report',
|
|
890
|
+
path: 'evidence/walkthrough-telemetry.json',
|
|
891
|
+
description: `Walkthrough: ${telemetry.routesPassed}/${telemetry.routesAttempted} routes, ${telemetry.uiModulesPassed}/${telemetry.uiModulesAttempted} UI modules`,
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
catch {
|
|
895
|
+
// non-fatal
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
finally {
|
|
899
|
+
if (child)
|
|
900
|
+
killTree(child);
|
|
901
|
+
}
|
|
902
|
+
return findings;
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Pre-walk login attempt. Resolves the login URL (config first, then
|
|
906
|
+
* connection-map detection), picks the first credential entry, and tries
|
|
907
|
+
* JSON then form bodies. Returns null + an attempt record on every
|
|
908
|
+
* non-success path so the caller can surface findings consistently.
|
|
909
|
+
*
|
|
910
|
+
* Exposed as a protected method so tests can override it without spinning
|
|
911
|
+
* up a real dev server.
|
|
912
|
+
*/
|
|
913
|
+
async tryLogin(routes, baseUrl) {
|
|
914
|
+
const creds = pickFirstCredential(this.config.auth?.credentials);
|
|
915
|
+
if (!creds) {
|
|
916
|
+
return {
|
|
917
|
+
session: null,
|
|
918
|
+
attempt: {
|
|
919
|
+
version: 1,
|
|
920
|
+
attemptedAt: new Date().toISOString(),
|
|
921
|
+
outcome: 'skipped',
|
|
922
|
+
reason: 'no credentials configured under config.auth.credentials',
|
|
923
|
+
loginUrl: null,
|
|
924
|
+
asRole: null,
|
|
925
|
+
bodyKind: null,
|
|
926
|
+
sessionCaptured: false,
|
|
927
|
+
},
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
return this.loginAs(creds, routes, baseUrl);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Log in with an explicit credential. Same shape as tryLogin but the
|
|
934
|
+
* caller picks the role — used by the multi-role authz-bypass probe so
|
|
935
|
+
* we can drive logins as roles beyond the first.
|
|
936
|
+
*/
|
|
937
|
+
async loginAs(creds, routes, baseUrl) {
|
|
938
|
+
const loginUrl = findLoginUrl(this.config.auth?.loginUrl, routes, baseUrl);
|
|
939
|
+
if (!loginUrl) {
|
|
940
|
+
return {
|
|
941
|
+
session: null,
|
|
942
|
+
attempt: {
|
|
943
|
+
version: 1,
|
|
944
|
+
attemptedAt: new Date().toISOString(),
|
|
945
|
+
outcome: 'skipped',
|
|
946
|
+
reason: 'no config.auth.loginUrl and no login-shaped route in connection-map',
|
|
947
|
+
loginUrl: null,
|
|
948
|
+
asRole: creds.role,
|
|
949
|
+
bodyKind: null,
|
|
950
|
+
sessionCaptured: false,
|
|
951
|
+
},
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
const result = await attemptLogin(loginUrl, creds.role, creds.email, creds.password);
|
|
955
|
+
if ('error' in result) {
|
|
956
|
+
return {
|
|
957
|
+
session: null,
|
|
958
|
+
attempt: {
|
|
959
|
+
version: 1,
|
|
960
|
+
attemptedAt: new Date().toISOString(),
|
|
961
|
+
outcome: 'failed',
|
|
962
|
+
reason: result.error,
|
|
963
|
+
loginUrl,
|
|
964
|
+
asRole: creds.role,
|
|
965
|
+
bodyKind: null,
|
|
966
|
+
sessionCaptured: false,
|
|
967
|
+
},
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
return {
|
|
971
|
+
session: result.session,
|
|
972
|
+
attempt: {
|
|
973
|
+
version: 1,
|
|
974
|
+
attemptedAt: new Date().toISOString(),
|
|
975
|
+
outcome: 'success',
|
|
976
|
+
reason: `logged in via ${result.session.bodyKind} POST`,
|
|
977
|
+
loginUrl,
|
|
978
|
+
asRole: creds.role,
|
|
979
|
+
bodyKind: result.session.bodyKind,
|
|
980
|
+
sessionCaptured: result.session.cookies.length > 0 || result.session.bearerToken !== null,
|
|
981
|
+
},
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Log in as every role beyond the one used for the main walk, then hit
|
|
986
|
+
* any admin-shaped route discovered by #87. A 2xx response from a
|
|
987
|
+
* non-first role on an admin path = authorization bypass (high,
|
|
988
|
+
* code-bug-security). Persists `evidence/multi-role-walk.json` with
|
|
989
|
+
* per-role status per route for human review.
|
|
990
|
+
*
|
|
991
|
+
* Costs ~one extra fetch per (additional role × admin route). If no
|
|
992
|
+
* additional roles are configured or no admin routes were discovered,
|
|
993
|
+
* exits silently.
|
|
994
|
+
*/
|
|
995
|
+
async runMultiRoleAuthzProbe(primaryRole, routes, baseUrl, findings) {
|
|
996
|
+
const allCreds = listAllCredentials(this.config.auth?.credentials);
|
|
997
|
+
const additionalCreds = allCreds.filter((c) => c.role !== primaryRole);
|
|
998
|
+
if (additionalCreds.length === 0)
|
|
999
|
+
return;
|
|
1000
|
+
const adminRoutes = routes
|
|
1001
|
+
.filter((r) => r.framework !== 'unknown' && isAdminPath(r.path))
|
|
1002
|
+
.slice(0, MAX_ROUTES_PER_RUN);
|
|
1003
|
+
if (adminRoutes.length === 0)
|
|
1004
|
+
return;
|
|
1005
|
+
const perRoute = {};
|
|
1006
|
+
for (const cred of additionalCreds) {
|
|
1007
|
+
const { session } = await this.loginAs(cred, routes, baseUrl);
|
|
1008
|
+
if (!session)
|
|
1009
|
+
continue;
|
|
1010
|
+
const headers = sessionHeaders(session);
|
|
1011
|
+
for (const route of adminRoutes) {
|
|
1012
|
+
const url = baseUrl + (route.path.startsWith('/') ? route.path : `/${route.path}`);
|
|
1013
|
+
const method = (route.method === 'ALL' ? 'GET' : route.method);
|
|
1014
|
+
const key = `${route.method} ${route.path}`;
|
|
1015
|
+
try {
|
|
1016
|
+
const res = await fetch(assertSafeFetchUrl(url), {
|
|
1017
|
+
method,
|
|
1018
|
+
headers,
|
|
1019
|
+
signal: AbortSignal.timeout(ROUTE_REQUEST_TIMEOUT_MS),
|
|
1020
|
+
});
|
|
1021
|
+
if (!perRoute[key])
|
|
1022
|
+
perRoute[key] = {};
|
|
1023
|
+
perRoute[key][cred.role] = res.status;
|
|
1024
|
+
if (res.status >= 200 && res.status < 300) {
|
|
1025
|
+
findings.push({
|
|
1026
|
+
id: `${this.agentId}-authz-bypass-${cred.role}-${route.method}-${route.path.replace(/[^\w]/g, '_')}`,
|
|
1027
|
+
type: 'code-bug-security',
|
|
1028
|
+
severity: 'high',
|
|
1029
|
+
agentId: this.agentId,
|
|
1030
|
+
module: 'localhost-walkthrough',
|
|
1031
|
+
description: `${route.method} ${route.path} returned ${res.status} when logged in as "${cred.role}" — admin-shaped path is accessible to a non-primary role (${route.file}:${route.line})`,
|
|
1032
|
+
file: route.file,
|
|
1033
|
+
line: route.line,
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
catch {
|
|
1038
|
+
// network errors on the probe are non-fatal; don't flood findings
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
try {
|
|
1043
|
+
const evidenceDir = path.join(this.runDir, 'evidence');
|
|
1044
|
+
fs.mkdirSync(evidenceDir, { recursive: true });
|
|
1045
|
+
fs.writeFileSync(path.join(evidenceDir, 'multi-role-walk.json'), JSON.stringify({
|
|
1046
|
+
version: 1,
|
|
1047
|
+
generatedAt: new Date().toISOString(),
|
|
1048
|
+
primaryRole,
|
|
1049
|
+
additionalRoles: additionalCreds.map((c) => c.role),
|
|
1050
|
+
adminRoutesProbed: adminRoutes.map((r) => ({ method: r.method, path: r.path })),
|
|
1051
|
+
perRoute,
|
|
1052
|
+
}, null, 2), 'utf-8');
|
|
1053
|
+
this.addEvidence({
|
|
1054
|
+
type: 'report',
|
|
1055
|
+
path: 'evidence/multi-role-walk.json',
|
|
1056
|
+
description: `Multi-role probe: ${additionalCreds.length} additional role(s) × ${adminRoutes.length} admin routes`,
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
catch {
|
|
1060
|
+
// non-fatal
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Exercise the refresh-token endpoint and verify a fresh access token /
|
|
1065
|
+
* session is issued. Skipped silently when no refresh URL resolves, or
|
|
1066
|
+
* when no refresh URL was configured AND no refresh token was captured
|
|
1067
|
+
* at login (the common JWT-without-refresh case).
|
|
1068
|
+
*
|
|
1069
|
+
* Findings:
|
|
1070
|
+
* - 88-refresh-failed (medium, code-bug-logic): the refresh endpoint
|
|
1071
|
+
* returned non-2xx, or 2xx but issued no new token — the refresh
|
|
1072
|
+
* flow is broken and sessions can't be extended.
|
|
1073
|
+
*/
|
|
1074
|
+
async runRefreshTest(session, routes, baseUrl, findings) {
|
|
1075
|
+
const refreshUrl = findRefreshUrl(this.config.auth?.refreshUrl, routes, baseUrl);
|
|
1076
|
+
if (!refreshUrl)
|
|
1077
|
+
return;
|
|
1078
|
+
// If we're relying on auto-detection (no explicit config) and never
|
|
1079
|
+
// captured a refresh token, don't probe — many apps expose no refresh.
|
|
1080
|
+
if (!this.config.auth?.refreshUrl && !session.refreshToken)
|
|
1081
|
+
return;
|
|
1082
|
+
const result = await attemptRefresh(refreshUrl, session);
|
|
1083
|
+
if (!result)
|
|
1084
|
+
return; // network error — non-fatal
|
|
1085
|
+
const accepted = result.status >= 200 && result.status < 300;
|
|
1086
|
+
if (!accepted || !result.gotNewToken) {
|
|
1087
|
+
findings.push({
|
|
1088
|
+
id: `${this.agentId}-refresh-failed`,
|
|
1089
|
+
type: 'code-bug-logic',
|
|
1090
|
+
severity: 'medium',
|
|
1091
|
+
agentId: this.agentId,
|
|
1092
|
+
module: 'localhost-walkthrough',
|
|
1093
|
+
description: `Token refresh via ${refreshUrl} ${accepted ? `returned ${result.status} but issued no new access token / session cookie` : `failed with status ${result.status}`}. ` +
|
|
1094
|
+
`Sessions can't be extended — users will be logged out when the access token expires.`,
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
// Success (2xx + new token) is the happy path — stay silent.
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Exercise the logout endpoint with the live session attached, then
|
|
1101
|
+
* verify the session was actually invalidated. Skipped silently when
|
|
1102
|
+
* no logout URL can be resolved.
|
|
1103
|
+
*
|
|
1104
|
+
* Findings:
|
|
1105
|
+
* - 88-logout-failed (medium, code-bug-logic): logout endpoint
|
|
1106
|
+
* returned an unexpected status (anything not 2xx/302).
|
|
1107
|
+
* - 88-session-not-invalidated (high, code-bug-security): the OLD
|
|
1108
|
+
* session still works on the login URL after logout — the server
|
|
1109
|
+
* didn't destroy it. Real session-fixation / sticky-session bug.
|
|
1110
|
+
*/
|
|
1111
|
+
async runLogoutTest(session, routes, baseUrl, findings) {
|
|
1112
|
+
const logoutUrl = findLogoutUrl(this.config.auth?.logoutUrl, routes, baseUrl);
|
|
1113
|
+
if (!logoutUrl) {
|
|
1114
|
+
// Silent — the user may not have a logout endpoint at all (token-only auth).
|
|
1115
|
+
return;
|
|
1116
|
+
}
|
|
1117
|
+
const result = await attemptLogout(logoutUrl, session);
|
|
1118
|
+
if (!result) {
|
|
1119
|
+
// Network error — non-fatal, no finding.
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
const accepted = (result.status >= 200 && result.status < 300) || result.status === 302;
|
|
1123
|
+
if (!accepted) {
|
|
1124
|
+
findings.push({
|
|
1125
|
+
id: `${this.agentId}-logout-failed`,
|
|
1126
|
+
type: 'code-bug-logic',
|
|
1127
|
+
severity: 'medium',
|
|
1128
|
+
agentId: this.agentId,
|
|
1129
|
+
module: 'localhost-walkthrough',
|
|
1130
|
+
description: `Logout endpoint (${logoutUrl}) returned ${result.status} — expected 2xx or 302.`,
|
|
1131
|
+
});
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
// Logout was accepted. Re-attempt with the same (now-stale) session and
|
|
1135
|
+
// verify the server rejects it.
|
|
1136
|
+
const invalidated = await verifySessionInvalidated(session.loginUrl, session);
|
|
1137
|
+
if (invalidated === false) {
|
|
1138
|
+
findings.push({
|
|
1139
|
+
id: `${this.agentId}-session-not-invalidated`,
|
|
1140
|
+
type: 'code-bug-security',
|
|
1141
|
+
severity: 'high',
|
|
1142
|
+
agentId: this.agentId,
|
|
1143
|
+
module: 'localhost-walkthrough',
|
|
1144
|
+
description: `After successful logout via ${logoutUrl}, the original session cookie/token still authenticates against ${session.loginUrl}. ` +
|
|
1145
|
+
`The server isn't destroying sessions on logout — anyone who captured the cookie (logs, browser history, MITM) can keep using it.`,
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
// invalidated === true → all good (silent pass)
|
|
1149
|
+
// invalidated === null → network error verifying; don't flood findings
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Probe the login endpoint with a wrong password. Wraps the pure
|
|
1153
|
+
* `probeBadCredentials` helper so tests can stub the outcome without
|
|
1154
|
+
* standing up an HTTP server.
|
|
1155
|
+
*/
|
|
1156
|
+
async runBadCredentialsProbe(session) {
|
|
1157
|
+
const creds = pickFirstCredential(this.config.auth?.credentials);
|
|
1158
|
+
if (!creds)
|
|
1159
|
+
return null;
|
|
1160
|
+
return probeBadCredentials(session.loginUrl, creds.email, session.bodyKind);
|
|
1161
|
+
}
|
|
1162
|
+
persistAuthAttempt(attempt) {
|
|
1163
|
+
try {
|
|
1164
|
+
const evidenceDir = path.join(this.runDir, 'evidence');
|
|
1165
|
+
fs.mkdirSync(evidenceDir, { recursive: true });
|
|
1166
|
+
fs.writeFileSync(path.join(evidenceDir, 'auth-attempt.json'), JSON.stringify(attempt, null, 2), 'utf-8');
|
|
1167
|
+
this.addEvidence({
|
|
1168
|
+
type: 'report',
|
|
1169
|
+
path: 'evidence/auth-attempt.json',
|
|
1170
|
+
description: `Auth attempt: ${attempt.outcome} (${attempt.reason})`,
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
catch {
|
|
1174
|
+
// non-fatal — auth is best-effort
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Attempt a Stagehand-driven retry. Returns true if the runner was reachable,
|
|
1179
|
+
* false if Stagehand isn't installed / configured (the typical case in a
|
|
1180
|
+
* scaffold environment). This stays defensive — we never propagate Stagehand
|
|
1181
|
+
* import failures up to the caller.
|
|
1182
|
+
*/
|
|
1183
|
+
async tryStagehandFallback(url, moduleId) {
|
|
1184
|
+
try {
|
|
1185
|
+
const { createStagehandRunner, STAGEHAND_COST_CAP_USD } = await import('./stagehand-runner.js');
|
|
1186
|
+
const runner = await createStagehandRunner({
|
|
1187
|
+
phase: this.phase,
|
|
1188
|
+
costCapUsd: STAGEHAND_COST_CAP_USD,
|
|
1189
|
+
});
|
|
1190
|
+
// Scaffold: we acknowledge the fallback engaged but don't drive a full
|
|
1191
|
+
// act/observe loop here — that's #85's job. This is enough to record
|
|
1192
|
+
// that the dep is reachable for the eventual cutover.
|
|
1193
|
+
void url;
|
|
1194
|
+
void moduleId;
|
|
1195
|
+
void runner;
|
|
1196
|
+
return true;
|
|
1197
|
+
}
|
|
1198
|
+
catch {
|
|
1199
|
+
return false;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
//# sourceMappingURL=88-localhost-walkthrough.js.map
|