taphound 0.2.0-dev.1 → 0.2.0-dev.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -149
- package/README.zh-CN.md +47 -147
- package/assets/skills/taphound-case-suite/SKILL.md +363 -0
- package/assets/skills/taphound-case-suite/schemas/base-flow-record.schema.json +22 -0
- package/assets/skills/taphound-case-suite/schemas/case-catalog.schema.json +26 -0
- package/assets/skills/taphound-case-suite/schemas/case-ledger.schema.json +158 -0
- package/assets/skills/taphound-case-suite/schemas/suite-input.schema.json +41 -0
- package/assets/skills/taphound-case-suite/schemas/transition.schema.json +61 -0
- package/assets/skills/taphound-case-suite/scripts/ledger.mjs +1207 -0
- package/assets/skills/taphound-case-suite/templates/base-flow-record.example.json +20 -0
- package/assets/skills/taphound-case-suite/templates/suite-input.example.json +27 -0
- package/assets/skills/taphound-case-suite/templates/transition.example.json +8 -0
- package/assets/skills/taphound-flash/SKILL.md +115 -0
- package/assets/skills/taphound-flash/scripts/flash.mjs +585 -0
- package/assets/skills/taphound-flash/templates/flash-plan.example.json +15 -0
- package/assets/skills/taphound-journey-brief-author/CONTEXT-GUIDE.md +471 -0
- package/assets/skills/taphound-journey-brief-author/SKILL.md +494 -0
- package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.md +96 -0
- package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.zh-CN.md +80 -0
- package/assets/skills/taphound-journey-brief-author/prompts/context-analyze-project.md +309 -0
- package/assets/skills/taphound-journey-brief-author/schemas/context-refresh-result.json +123 -0
- package/assets/skills/taphound-journey-brief-author/schemas/project-context-module.json +192 -0
- package/assets/skills/taphound-journey-brief-author/schemas/project-context.json +152 -0
- package/assets/skills/taphound-journey-brief-author/templates/project-context-module.example.json +58 -0
- package/assets/skills/taphound-journey-brief-author/templates/project-context.example.json +51 -0
- package/assets/skills/taphound-journey-brief-author/templates/taphound-journey-brief.template.md +63 -0
- package/assets/skills/taphound-journey-generator/SKILL.md +507 -0
- package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/prompts/check-completion.md +3 -0
- package/assets/skills/taphound-journey-generator/prompts/consume-journey-brief.md +52 -0
- package/assets/skills/taphound-journey-generator/prompts/generate-step.md +211 -0
- package/assets/skills/taphound-journey-generator/prompts/select-flow.md +91 -0
- package/assets/skills/taphound-journey-generator/references/bridge.md +35 -0
- package/assets/skills/taphound-journey-generator/references/mid-session.md +44 -0
- package/assets/skills/taphound-journey-generator/schemas/external-flow.json +37 -0
- package/assets/skills/taphound-journey-generator/schemas/flow.json +28 -0
- package/assets/skills/taphound-journey-generator/schemas/journey-source.json +25 -0
- package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/observe-output.json +13 -4
- package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/proposed-step-envelope.json +127 -5
- package/assets/skills/taphound-journey-generator/scripts/envelope.mjs +578 -0
- package/assets/skills/taphound-journey-generator/templates/external-flow.example.json +22 -0
- package/assets/skills/taphound-journey-generator/templates/flow.example.json +22 -0
- package/assets/skills/taphound-journey-generator/templates/journey-source.example.json +17 -0
- package/assets/skills/taphound-journey-generator/templates/taphound-journey-brief.example.md +70 -0
- package/assets/skills/taphound-verify-change/SKILL.md +91 -0
- package/assets/skills/taphound-verify-change/references/accept.md +38 -0
- package/assets/skills/taphound-verify-change/references/preserve.md +357 -0
- package/assets/skills/taphound-verify-change/schemas/workflow-manifest.schema.json +295 -0
- package/assets/skills/taphound-verify-change/scripts/handoff.mjs +482 -0
- package/assets/skills/taphound-verify-change/scripts/ui-refactor.mjs +505 -0
- package/dist/adapters/adb/adb-adapter.d.ts +16 -2
- package/dist/adapters/adb/adb-adapter.js +199 -0
- package/dist/adapters/adb/system-uiautomator-snapshot-provider.d.ts +13 -0
- package/dist/adapters/adb/system-uiautomator-snapshot-provider.js +122 -0
- package/dist/adapters/adb/ui-automator-parser.d.ts +3 -0
- package/dist/adapters/adb/ui-automator-parser.js +160 -0
- package/dist/adapters/adb/window-topology-parser.d.ts +2 -0
- package/dist/adapters/adb/window-topology-parser.js +101 -0
- package/dist/adapters/android-cli/android-cli-adapter.d.ts +16 -8
- package/dist/adapters/android-cli/android-cli-adapter.js +137 -15
- package/dist/adapters/android-cli/android-cli-snapshot-provider.d.ts +9 -0
- package/dist/adapters/android-cli/android-cli-snapshot-provider.js +99 -0
- package/dist/adapters/android-cli/layout-parser.js +12 -8
- package/dist/adapters/appium/appium-doctor.d.ts +7 -0
- package/dist/adapters/appium/appium-doctor.js +128 -0
- package/dist/adapters/appium/appium-ui-snapshot-provider.d.ts +42 -0
- package/dist/adapters/appium/appium-ui-snapshot-provider.js +309 -0
- package/dist/adapters/camera/camera-probe-adapter.d.ts +18 -0
- package/dist/adapters/camera/camera-probe-adapter.js +286 -0
- package/dist/adapters/filesystem/artifact-store.js +40 -1
- package/dist/adapters/filesystem/context-document-writer.d.ts +15 -0
- package/dist/adapters/filesystem/context-document-writer.js +112 -0
- package/dist/adapters/filesystem/diagnostics-journal.d.ts +17 -0
- package/dist/adapters/filesystem/diagnostics-journal.js +130 -0
- package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
- package/dist/adapters/filesystem/external-flow-registry.js +325 -0
- package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
- package/dist/adapters/filesystem/generation-session-store.js +281 -855
- package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
- package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
- package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
- package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
- package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
- package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
- package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
- package/dist/adapters/filesystem/journey-composition-store.js +151 -0
- package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
- package/dist/adapters/filesystem/knowledge-registry.js +223 -0
- package/dist/adapters/filesystem/project-bound-file.js +3 -5
- package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
- package/dist/adapters/filesystem/project-file-inspector.js +57 -28
- package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
- package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
- package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
- package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
- package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
- package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
- package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
- package/dist/adapters/filesystem/skill-installer.js +40 -11
- package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
- package/dist/adapters/filesystem/workspace-layout.js +57 -0
- package/dist/adapters/git/node-git-diff.d.ts +17 -0
- package/dist/adapters/git/node-git-diff.js +114 -0
- package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
- package/dist/adapters/process/node-detached-process-launcher.js +96 -0
- package/dist/adapters/process/node-process-runner.js +11 -2
- package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
- package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
- package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
- package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
- package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
- package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
- package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
- package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
- package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
- package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
- package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
- package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
- package/dist/adapters/runtime/session-adb-view.js +193 -0
- package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
- package/dist/adapters/runtime/session-backed-ports.js +43 -0
- package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
- package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
- package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
- package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
- package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
- package/dist/adapters/ui/device-layout-temp.js +18 -0
- package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
- package/dist/adapters/ui/device-ui-environment.js +81 -0
- package/dist/adapters/ui/layout-normalization.d.ts +9 -0
- package/dist/adapters/ui/layout-normalization.js +44 -0
- package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
- package/dist/adapters/ui/ui-snapshot-error.js +12 -0
- package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
- package/dist/adapters/ui/ui-snapshot-support.js +12 -0
- package/dist/application/align/align-service.d.ts +42 -0
- package/dist/application/align/align-service.js +106 -0
- package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
- package/dist/application/assertion/expectation-evaluator.js +156 -18
- package/dist/application/assertion/guarded-expectation.d.ts +45 -0
- package/dist/application/assertion/guarded-expectation.js +74 -0
- package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
- package/dist/application/checkpoint/baseline-capturer.js +163 -0
- package/dist/application/checkpoint/baseline-error.d.ts +5 -0
- package/dist/application/checkpoint/baseline-error.js +8 -0
- package/dist/application/checkpoint/baseline-service.d.ts +31 -0
- package/dist/application/checkpoint/baseline-service.js +147 -0
- package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
- package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
- package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
- package/dist/application/checkpoint/regression-comparator.js +192 -0
- package/dist/application/collector/logcat-collector.d.ts +22 -1
- package/dist/application/collector/logcat-collector.js +103 -15
- package/dist/application/collector/logcat-event.d.ts +8 -0
- package/dist/application/collector/logcat-event.js +79 -0
- package/dist/application/collector/logcat-stop.d.ts +2 -0
- package/dist/application/collector/logcat-stop.js +11 -0
- package/dist/application/context/context-generator.d.ts +45 -0
- package/dist/application/context/context-generator.js +228 -0
- package/dist/application/context/context-loader.d.ts +40 -0
- package/dist/application/context/context-loader.js +223 -0
- package/dist/application/context/context-refresher.d.ts +59 -0
- package/dist/application/context/context-refresher.js +349 -0
- package/dist/application/context/context-rehasher.d.ts +36 -0
- package/dist/application/context/context-rehasher.js +110 -0
- package/dist/application/context/context-validator.d.ts +23 -1
- package/dist/application/context/context-validator.js +116 -9
- package/dist/application/context/evidence-hash.d.ts +1 -0
- package/dist/application/context/evidence-hash.js +125 -0
- package/dist/application/context/evidence-match.d.ts +9 -0
- package/dist/application/context/evidence-match.js +8 -0
- package/dist/application/context/shard-identity.d.ts +2 -0
- package/dist/application/context/shard-identity.js +7 -0
- package/dist/application/contract/contract-loader.d.ts +25 -0
- package/dist/application/contract/contract-loader.js +68 -0
- package/dist/application/contract/contract-review.d.ts +25 -0
- package/dist/application/contract/contract-review.js +51 -0
- package/dist/application/contract/contract-verifier.d.ts +53 -0
- package/dist/application/contract/contract-verifier.js +645 -0
- package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
- package/dist/application/devices/resolve-device-assignments.js +60 -0
- package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
- package/dist/application/diagnosis/failure-classifier.js +179 -0
- package/dist/application/diagnostics/diagnostics-exporter.d.ts +29 -0
- package/dist/application/diagnostics/diagnostics-exporter.js +283 -0
- package/dist/application/diagnostics/ui-capture-telemetry.d.ts +16 -0
- package/dist/application/diagnostics/ui-capture-telemetry.js +81 -0
- package/dist/application/doctor/doctor-service.d.ts +36 -3
- package/dist/application/doctor/doctor-service.js +255 -25
- package/dist/application/generation/generation-app-preparer.d.ts +20 -0
- package/dist/application/generation/generation-app-preparer.js +28 -0
- package/dist/application/generation/generation-config-service.d.ts +21 -0
- package/dist/application/generation/generation-config-service.js +53 -0
- package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
- package/dist/application/generation/generation-confirmation-service.js +109 -24
- package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
- package/dist/application/generation/generation-context-snapshot.js +29 -0
- package/dist/application/generation/generation-finalizer.d.ts +15 -9
- package/dist/application/generation/generation-finalizer.js +167 -70
- package/dist/application/generation/generation-publisher.js +12 -8
- package/dist/application/generation/generation-recovery-service.d.ts +35 -0
- package/dist/application/generation/generation-recovery-service.js +144 -0
- package/dist/application/generation/generation-reopen-service.d.ts +15 -0
- package/dist/application/generation/generation-reopen-service.js +37 -0
- package/dist/application/generation/generation-replace-service.d.ts +32 -0
- package/dist/application/generation/generation-replace-service.js +116 -0
- package/dist/application/generation/generation-starter.d.ts +44 -4
- package/dist/application/generation/generation-starter.js +175 -8
- package/dist/application/generation/generation-step-executor.d.ts +67 -5
- package/dist/application/generation/generation-step-executor.js +471 -108
- package/dist/application/generation/proposed-step-validator.js +96 -30
- package/dist/application/generation/replay-policy-loader.d.ts +16 -0
- package/dist/application/generation/replay-policy-loader.js +29 -0
- package/dist/application/generation/risk-evaluator.d.ts +4 -1
- package/dist/application/generation/risk-evaluator.js +118 -3
- package/dist/application/generation/runtime-observer.d.ts +39 -7
- package/dist/application/generation/runtime-observer.js +193 -24
- package/dist/application/impact/impact-resolver.d.ts +32 -0
- package/dist/application/impact/impact-resolver.js +160 -0
- package/dist/application/init/init-service.js +26 -13
- package/dist/application/interaction/action-executor.d.ts +3 -2
- package/dist/application/interaction/action-executor.js +11 -1
- package/dist/application/interaction/action-target.d.ts +17 -0
- package/dist/application/interaction/action-target.js +40 -0
- package/dist/application/interaction/external-step-runner.d.ts +153 -0
- package/dist/application/interaction/external-step-runner.js +332 -0
- package/dist/application/interaction/fallback-resolver.d.ts +6 -3
- package/dist/application/interaction/fallback-resolver.js +7 -5
- package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
- package/dist/application/interaction/scroll-to-executor.js +118 -36
- package/dist/application/journey/external-flow-resolver.d.ts +25 -0
- package/dist/application/journey/external-flow-resolver.js +22 -0
- package/dist/application/journey/journey-check-service.d.ts +54 -0
- package/dist/application/journey/journey-check-service.js +207 -0
- package/dist/application/journey/journey-promoter.d.ts +26 -0
- package/dist/application/journey/journey-promoter.js +123 -0
- package/dist/application/journey/journey-resolver.d.ts +42 -0
- package/dist/application/journey/journey-resolver.js +239 -0
- package/dist/application/journey/journey-retirer.d.ts +25 -0
- package/dist/application/journey/journey-retirer.js +87 -0
- package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
- package/dist/application/knowledge/anchor-resolver.js +110 -0
- package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
- package/dist/application/knowledge/knowledge-loader.js +36 -0
- package/dist/application/locator/layout-failure-summary.d.ts +2 -0
- package/dist/application/locator/layout-failure-summary.js +67 -0
- package/dist/application/locator/layout-traversal.d.ts +11 -0
- package/dist/application/locator/layout-traversal.js +18 -0
- package/dist/application/locator/locator-resolver.d.ts +13 -1
- package/dist/application/locator/locator-resolver.js +182 -18
- package/dist/application/observe/observe-service.d.ts +20 -0
- package/dist/application/observe/observe-service.js +91 -0
- package/dist/application/project/project-describer.d.ts +14 -6
- package/dist/application/project/project-describer.js +38 -5
- package/dist/application/recognition/screen-detector.d.ts +28 -0
- package/dist/application/recognition/screen-detector.js +111 -0
- package/dist/application/recorder/locator-selector.js +151 -17
- package/dist/application/recorder/recorder-service.d.ts +16 -4
- package/dist/application/recorder/recorder-service.js +420 -128
- package/dist/application/report/report-writer.d.ts +5 -0
- package/dist/application/report/report-writer.js +17 -1
- package/dist/application/runtime/cold-launch.d.ts +28 -0
- package/dist/application/runtime/cold-launch.js +59 -0
- package/dist/application/runtime/step-runner.d.ts +49 -4
- package/dist/application/runtime/step-runner.js +721 -130
- package/dist/application/runtime/verify-runtime.d.ts +57 -7
- package/dist/application/runtime/verify-runtime.js +577 -175
- package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
- package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
- package/dist/application/ui/observed-ui-snapshot-provider.d.ts +15 -0
- package/dist/application/ui/observed-ui-snapshot-provider.js +66 -0
- package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
- package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
- package/dist/application/ui/ui-stability-probe.d.ts +9 -0
- package/dist/application/ui/ui-stability-probe.js +24 -0
- package/dist/application/wait/idle-advice.d.ts +6 -0
- package/dist/application/wait/idle-advice.js +27 -0
- package/dist/application/wait/idle-profiles.d.ts +15 -0
- package/dist/application/wait/idle-profiles.js +75 -0
- package/dist/application/wait/idle-waiter.d.ts +28 -4
- package/dist/application/wait/idle-waiter.js +201 -15
- package/dist/cli/commands/align.d.ts +3 -0
- package/dist/cli/commands/align.js +124 -0
- package/dist/cli/commands/baseline.d.ts +3 -0
- package/dist/cli/commands/baseline.js +130 -0
- package/dist/cli/commands/context.js +300 -27
- package/dist/cli/commands/contract.d.ts +3 -0
- package/dist/cli/commands/contract.js +120 -0
- package/dist/cli/commands/diagnose.d.ts +3 -0
- package/dist/cli/commands/diagnose.js +84 -0
- package/dist/cli/commands/doctor.js +16 -9
- package/dist/cli/commands/failure.d.ts +3 -0
- package/dist/cli/commands/failure.js +63 -0
- package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
- package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
- package/dist/cli/commands/generation/session-commands.d.ts +11 -0
- package/dist/cli/commands/generation/session-commands.js +472 -0
- package/dist/cli/commands/generation/shared.d.ts +1414 -0
- package/dist/cli/commands/generation/shared.js +291 -0
- package/dist/cli/commands/generation/step-commands.d.ts +8 -0
- package/dist/cli/commands/generation/step-commands.js +315 -0
- package/dist/cli/commands/generation.js +10 -507
- package/dist/cli/commands/impact.d.ts +3 -0
- package/dist/cli/commands/impact.js +87 -0
- package/dist/cli/commands/init.js +13 -6
- package/dist/cli/commands/journey.d.ts +3 -0
- package/dist/cli/commands/journey.js +382 -0
- package/dist/cli/commands/knowledge.d.ts +3 -0
- package/dist/cli/commands/knowledge.js +93 -0
- package/dist/cli/commands/observe.d.ts +3 -0
- package/dist/cli/commands/observe.js +127 -0
- package/dist/cli/commands/project.js +2 -1
- package/dist/cli/commands/record.js +18 -5
- package/dist/cli/commands/verify.js +326 -64
- package/dist/cli/dependencies.d.ts +136 -1
- package/dist/cli/dependencies.js +504 -52
- package/dist/cli/diagnostics-recorder.d.ts +31 -0
- package/dist/cli/diagnostics-recorder.js +82 -0
- package/dist/cli/diff-verification.d.ts +41 -0
- package/dist/cli/diff-verification.js +192 -0
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.js +107 -2
- package/dist/cli/output.d.ts +5 -3
- package/dist/cli/output.js +12 -0
- package/dist/cli/program.js +21 -1
- package/dist/cli/project-root.d.ts +1 -0
- package/dist/cli/project-root.js +6 -0
- package/dist/cli/runtime-selection.d.ts +22 -0
- package/dist/cli/runtime-selection.js +92 -0
- package/dist/cli/version.d.ts +1 -0
- package/dist/cli/version.js +14 -0
- package/dist/cli/workspace-guard.d.ts +2 -0
- package/dist/cli/workspace-guard.js +3 -0
- package/dist/domain/binding-reference.d.ts +4 -0
- package/dist/domain/binding-reference.js +23 -0
- package/dist/domain/checkpoint.d.ts +404 -0
- package/dist/domain/checkpoint.js +297 -0
- package/dist/domain/config.d.ts +107 -1
- package/dist/domain/config.js +52 -6
- package/dist/domain/contract.d.ts +413 -0
- package/dist/domain/contract.js +196 -0
- package/dist/domain/diagnostics.d.ts +1396 -0
- package/dist/domain/diagnostics.js +193 -0
- package/dist/domain/external-flow.d.ts +493 -0
- package/dist/domain/external-flow.js +15 -0
- package/dist/domain/failure-classification.d.ts +176 -0
- package/dist/domain/failure-classification.js +169 -0
- package/dist/domain/failure.d.ts +2 -1
- package/dist/domain/failure.js +123 -0
- package/dist/domain/generation.d.ts +1671 -132
- package/dist/domain/generation.js +202 -13
- package/dist/domain/geometry.d.ts +13 -0
- package/dist/domain/geometry.js +16 -0
- package/dist/domain/impact.d.ts +71 -0
- package/dist/domain/impact.js +76 -0
- package/dist/domain/init.d.ts +12 -4
- package/dist/domain/init.js +24 -18
- package/dist/domain/journey-composition.d.ts +2285 -0
- package/dist/domain/journey-composition.js +85 -0
- package/dist/domain/journey-lifecycle.d.ts +10 -0
- package/dist/domain/journey-lifecycle.js +9 -0
- package/dist/domain/journey.d.ts +2419 -212
- package/dist/domain/journey.js +384 -14
- package/dist/domain/knowledge.d.ts +165 -0
- package/dist/domain/knowledge.js +188 -0
- package/dist/domain/layout.d.ts +34 -5
- package/dist/domain/layout.js +64 -6
- package/dist/domain/locator-evidence.d.ts +3 -0
- package/dist/domain/locator-evidence.js +36 -0
- package/dist/domain/logcat-event.d.ts +54 -0
- package/dist/domain/logcat-event.js +40 -0
- package/dist/domain/observation.d.ts +33 -0
- package/dist/domain/observation.js +18 -0
- package/dist/domain/project-context.d.ts +219 -1
- package/dist/domain/project-context.js +209 -6
- package/dist/domain/proposed-step.d.ts +340 -60
- package/dist/domain/proposed-step.js +23 -3
- package/dist/domain/report.d.ts +1455 -28
- package/dist/domain/report.js +211 -14
- package/dist/domain/runtime-snapshot.d.ts +58 -1
- package/dist/domain/runtime-snapshot.js +14 -3
- package/dist/domain/runtime.d.ts +50 -0
- package/dist/domain/runtime.js +36 -0
- package/dist/domain/system-app-profiles.d.ts +6 -0
- package/dist/domain/system-app-profiles.js +43 -0
- package/dist/domain/ui-backend.d.ts +28 -0
- package/dist/domain/ui-backend.js +33 -0
- package/dist/domain/ui-cache.d.ts +11 -0
- package/dist/domain/ui-cache.js +10 -0
- package/dist/domain/verify-receipt.d.ts +17 -0
- package/dist/domain/verify-receipt.js +17 -0
- package/dist/domain/window-hierarchy.d.ts +84 -0
- package/dist/domain/window-hierarchy.js +172 -0
- package/dist/domain/workflow-manifest.d.ts +77 -0
- package/dist/domain/workflow-manifest.js +136 -0
- package/dist/domain/workspace.d.ts +30 -0
- package/dist/domain/workspace.js +74 -0
- package/dist/ports/adb.d.ts +34 -1
- package/dist/ports/align-prompt.d.ts +11 -0
- package/dist/ports/align-prompt.js +6 -0
- package/dist/ports/anchor-resolver.d.ts +30 -0
- package/dist/ports/anchor-resolver.js +1 -0
- package/dist/ports/annotated-screen-resolver.d.ts +4 -0
- package/dist/ports/annotated-screen-resolver.js +1 -0
- package/dist/ports/camera-probe.d.ts +23 -0
- package/dist/ports/camera-probe.js +8 -0
- package/dist/ports/context-document-writer.d.ts +24 -0
- package/dist/ports/context-document-writer.js +1 -0
- package/dist/ports/detached-process-launcher.d.ts +12 -0
- package/dist/ports/detached-process-launcher.js +1 -0
- package/dist/ports/diagnostics.d.ts +15 -0
- package/dist/ports/diagnostics.js +1 -0
- package/dist/ports/external-flow-registry.d.ts +37 -0
- package/dist/ports/external-flow-registry.js +1 -0
- package/dist/ports/generation-prompt.d.ts +2 -1
- package/dist/ports/generation-session-store.d.ts +12 -2
- package/dist/ports/git-diff.d.ts +9 -0
- package/dist/ports/git-diff.js +1 -0
- package/dist/ports/journey-composition-store.d.ts +17 -0
- package/dist/ports/journey-composition-store.js +1 -0
- package/dist/ports/knowledge-registry.d.ts +20 -0
- package/dist/ports/knowledge-registry.js +1 -0
- package/dist/ports/process-runner.d.ts +7 -0
- package/dist/ports/project-file-inspector.d.ts +1 -0
- package/dist/ports/project-identity-inspector.d.ts +24 -0
- package/dist/ports/project-identity-inspector.js +1 -0
- package/dist/ports/project-inventory-inspector.d.ts +21 -0
- package/dist/ports/project-inventory-inspector.js +1 -0
- package/dist/ports/project-module-discoverer.d.ts +26 -0
- package/dist/ports/project-module-discoverer.js +1 -0
- package/dist/ports/recorder-prompt.d.ts +10 -1
- package/dist/ports/runtime-backend.d.ts +89 -0
- package/dist/ports/runtime-backend.js +13 -0
- package/dist/ports/runtime-capability.d.ts +12 -0
- package/dist/ports/runtime-capability.js +20 -0
- package/dist/ports/runtime-session-ports.d.ts +25 -0
- package/dist/ports/runtime-session-ports.js +1 -0
- package/dist/ports/screenshot.d.ts +11 -0
- package/dist/ports/screenshot.js +1 -0
- package/dist/ports/skill-installer.d.ts +2 -2
- package/dist/ports/ui-snapshot.d.ts +35 -0
- package/dist/ports/ui-snapshot.js +1 -0
- package/dist/ports/ui-stability.d.ts +19 -0
- package/dist/ports/ui-stability.js +1 -0
- package/dist/ports/workspace-layout.d.ts +4 -0
- package/dist/ports/workspace-layout.js +1 -0
- package/dist/shared/errors.d.ts +2 -0
- package/dist/shared/errors.js +22 -0
- package/dist/shared/paths.d.ts +2 -0
- package/dist/shared/paths.js +24 -0
- package/dist/shared/strings.d.ts +2 -0
- package/dist/shared/strings.js +16 -0
- package/package.json +7 -2
- package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
- package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
- package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
- package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
- package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
- package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
- package/dist/ports/android-cli.d.ts +0 -21
- /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DisplayViewport } from "../../domain/geometry.js";
|
|
2
|
+
import type { LayoutElement } from "../../domain/layout.js";
|
|
3
|
+
import type { UiBackendDescriptor } from "../../domain/ui-backend.js";
|
|
4
|
+
import type { UiSnapshot } from "../../ports/ui-snapshot.js";
|
|
5
|
+
export interface UiSnapshotTiming {
|
|
6
|
+
now?: (() => Date) | undefined;
|
|
7
|
+
createObservationId?: (() => string) | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare function snapshotFromCapture(input: {
|
|
10
|
+
startedAt: number;
|
|
11
|
+
roots: readonly LayoutElement[];
|
|
12
|
+
backend: UiBackendDescriptor;
|
|
13
|
+
viewport: DisplayViewport;
|
|
14
|
+
timing: UiSnapshotTiming;
|
|
15
|
+
}): UiSnapshot;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { performance } from "node:perf_hooks";
|
|
3
|
+
export function snapshotFromCapture(input) {
|
|
4
|
+
return {
|
|
5
|
+
observationId: (input.timing.createObservationId ?? randomUUID)(),
|
|
6
|
+
capturedAt: (input.timing.now ?? (() => new Date()))().toISOString(),
|
|
7
|
+
durationMs: performance.now() - input.startedAt,
|
|
8
|
+
backend: input.backend,
|
|
9
|
+
viewport: input.viewport,
|
|
10
|
+
roots: input.roots
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { FailureCode } from "../../domain/failure.js";
|
|
2
|
+
import type { AdbPort } from "../../ports/adb.js";
|
|
3
|
+
import type { AlignPromptPort } from "../../ports/align-prompt.js";
|
|
4
|
+
import type { CameraProbePort, CameraProbeResult } from "../../ports/camera-probe.js";
|
|
5
|
+
import type { ExternalFlowRegistry, WriteExternalFlowResult } from "../../ports/external-flow-registry.js";
|
|
6
|
+
export declare class AlignError extends Error {
|
|
7
|
+
readonly code: FailureCode;
|
|
8
|
+
constructor(code: FailureCode, message: string);
|
|
9
|
+
}
|
|
10
|
+
export interface AlignServiceDeps {
|
|
11
|
+
adb: Pick<AdbPort, "devices">;
|
|
12
|
+
probe: CameraProbePort;
|
|
13
|
+
prompt: AlignPromptPort;
|
|
14
|
+
registry: ExternalFlowRegistry;
|
|
15
|
+
}
|
|
16
|
+
export interface AlignCameraInput {
|
|
17
|
+
projectRoot: string;
|
|
18
|
+
deviceSerial?: string | undefined;
|
|
19
|
+
force?: boolean | undefined;
|
|
20
|
+
json: boolean;
|
|
21
|
+
signal?: AbortSignal | undefined;
|
|
22
|
+
}
|
|
23
|
+
export interface AlignCameraWrittenResult {
|
|
24
|
+
status: "written";
|
|
25
|
+
exitCode: 0;
|
|
26
|
+
flow: WriteExternalFlowResult & {
|
|
27
|
+
name: string;
|
|
28
|
+
steps: number;
|
|
29
|
+
};
|
|
30
|
+
probe: CameraProbeResult;
|
|
31
|
+
deviceSerial: string;
|
|
32
|
+
}
|
|
33
|
+
export interface AlignCameraCancelledResult {
|
|
34
|
+
status: "cancelled";
|
|
35
|
+
exitCode: 2;
|
|
36
|
+
}
|
|
37
|
+
export type AlignCameraResult = AlignCameraWrittenResult | AlignCameraCancelledResult;
|
|
38
|
+
export declare class AlignService {
|
|
39
|
+
private readonly deps;
|
|
40
|
+
constructor(deps: AlignServiceDeps);
|
|
41
|
+
alignCamera(input: AlignCameraInput): Promise<AlignCameraResult>;
|
|
42
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { CameraProbeError } from "../../ports/camera-probe.js";
|
|
2
|
+
export class AlignError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "AlignError";
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const FLOW_NAME = "camera/photo-capture";
|
|
11
|
+
function selectDevice(devices, requested) {
|
|
12
|
+
const online = devices.filter((device) => device.status === "device");
|
|
13
|
+
if (requested !== undefined) {
|
|
14
|
+
return online.find((device) => device.serial === requested)?.serial;
|
|
15
|
+
}
|
|
16
|
+
return online.length === 1 ? online[0]?.serial : undefined;
|
|
17
|
+
}
|
|
18
|
+
function buildFlow(probeResult, deviceSerial) {
|
|
19
|
+
const steps = [
|
|
20
|
+
{ action: "wait", expectedActivity: probeResult.activityName },
|
|
21
|
+
{
|
|
22
|
+
action: "click",
|
|
23
|
+
locator: { resourceId: probeResult.shutterResourceId },
|
|
24
|
+
expectedActivity: probeResult.activityName
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
if (probeResult.confirmResourceId !== undefined) {
|
|
28
|
+
steps.push({
|
|
29
|
+
action: "click",
|
|
30
|
+
locator: { resourceId: probeResult.confirmResourceId },
|
|
31
|
+
expectedActivity: probeResult.confirmActivityName
|
|
32
|
+
?? probeResult.activityName
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
version: 1,
|
|
37
|
+
kind: "externalFlow",
|
|
38
|
+
name: FLOW_NAME,
|
|
39
|
+
description: `Auto-generated by \`taphound align camera\` for ${probeResult.packageName} on ${deviceSerial}`,
|
|
40
|
+
escapedPackageName: probeResult.packageName,
|
|
41
|
+
expectedEscapeActivity: probeResult.activityName,
|
|
42
|
+
includes: [],
|
|
43
|
+
steps
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export class AlignService {
|
|
47
|
+
deps;
|
|
48
|
+
constructor(deps) {
|
|
49
|
+
this.deps = deps;
|
|
50
|
+
}
|
|
51
|
+
async alignCamera(input) {
|
|
52
|
+
const devices = await this.deps.adb.devices(input.signal);
|
|
53
|
+
const deviceSerial = selectDevice(devices, input.deviceSerial);
|
|
54
|
+
if (deviceSerial === undefined) {
|
|
55
|
+
throw new AlignError("ALIGN_DEVICE_UNAVAILABLE", input.deviceSerial === undefined
|
|
56
|
+
? `Expected exactly one online device, found ${String(devices.filter((d) => d.status === "device").length)}`
|
|
57
|
+
: `Requested device is not online: ${input.deviceSerial}`);
|
|
58
|
+
}
|
|
59
|
+
let probeResult;
|
|
60
|
+
try {
|
|
61
|
+
probeResult = await this.deps.probe.probe({
|
|
62
|
+
deviceSerial,
|
|
63
|
+
...(input.signal === undefined ? {} : { signal: input.signal })
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (error instanceof CameraProbeError) {
|
|
68
|
+
throw new AlignError(error.code, error.message);
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
if (!input.json) {
|
|
73
|
+
const confirmed = await this.deps.prompt.confirmWrite({
|
|
74
|
+
values: probeResult,
|
|
75
|
+
targetPath: `.taphound/flows/external/${FLOW_NAME}.json`
|
|
76
|
+
});
|
|
77
|
+
if (!confirmed) {
|
|
78
|
+
return { status: "cancelled", exitCode: 2 };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const flow = buildFlow(probeResult, deviceSerial);
|
|
82
|
+
let writeResult;
|
|
83
|
+
try {
|
|
84
|
+
writeResult = await this.deps.registry.write({
|
|
85
|
+
projectRoot: input.projectRoot,
|
|
86
|
+
name: FLOW_NAME,
|
|
87
|
+
flow,
|
|
88
|
+
...(input.force === undefined ? {} : { force: input.force })
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
93
|
+
if (/already exists/i.test(message)) {
|
|
94
|
+
throw new AlignError("ALIGN_FLOW_EXISTS", `External Flow already exists: ${FLOW_NAME} (use --force to overwrite)`);
|
|
95
|
+
}
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
status: "written",
|
|
100
|
+
exitCode: 0,
|
|
101
|
+
flow: { ...writeResult, name: FLOW_NAME, steps: flow.steps.length },
|
|
102
|
+
probe: probeResult,
|
|
103
|
+
deviceSerial
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import type { FailureCode } from "../../domain/failure.js";
|
|
2
2
|
import type { Expectation } from "../../domain/journey.js";
|
|
3
|
+
import type { StepReport } from "../../domain/report.js";
|
|
3
4
|
import type { LayoutElement } from "../../domain/layout.js";
|
|
4
5
|
import type { AdbPort } from "../../ports/adb.js";
|
|
5
|
-
import type { AndroidCliPort } from "../../ports/android-cli.js";
|
|
6
6
|
import type { Clock } from "../../ports/clock.js";
|
|
7
|
-
import type {
|
|
7
|
+
import type { UiSnapshotProvider } from "../../ports/ui-snapshot.js";
|
|
8
|
+
import type { LogcatCollector, LogcatLine } from "../collector/logcat-collector.js";
|
|
8
9
|
export interface ExpectationContext {
|
|
9
10
|
packageName: string;
|
|
10
11
|
deviceSerial: string;
|
|
11
12
|
stepStartedAt: number;
|
|
13
|
+
runStartedAt?: number | undefined;
|
|
14
|
+
markers?: ReadonlyMap<string, number> | undefined;
|
|
12
15
|
}
|
|
13
16
|
export interface ExpectationObservationInput {
|
|
14
17
|
timeoutMs: number;
|
|
@@ -38,24 +41,34 @@ export type ExpectationResult = {
|
|
|
38
41
|
durationMs: number;
|
|
39
42
|
actual?: string | undefined;
|
|
40
43
|
matchedLine?: string | undefined;
|
|
44
|
+
logcatEvent?: NonNullable<StepReport["expectation"]>["logcatEvent"];
|
|
41
45
|
} | {
|
|
42
46
|
status: "failed";
|
|
43
47
|
type: Expectation["type"];
|
|
44
|
-
code: Extract<FailureCode, "EXPECT_ACTIVITY_FAILED" | "EXPECT_ELEMENT_FAILED" | "EXPECT_LOGCAT_FAILED">;
|
|
48
|
+
code: Extract<FailureCode, "EXPECT_ACTIVITY_FAILED" | "EXPECT_ELEMENT_FAILED" | "EXPECT_LOGCAT_FAILED" | "EXPECT_LOGCAT_AMBIGUOUS">;
|
|
45
49
|
message: string;
|
|
46
50
|
durationMs: number;
|
|
47
51
|
actual?: string | undefined;
|
|
52
|
+
logcatEvent?: NonNullable<StepReport["expectation"]>["logcatEvent"];
|
|
48
53
|
} | {
|
|
49
54
|
status: "cancelled";
|
|
50
55
|
type: Expectation["type"];
|
|
51
56
|
durationMs: number;
|
|
52
57
|
};
|
|
58
|
+
type ElementExpectation = Extract<Expectation, {
|
|
59
|
+
type: "element";
|
|
60
|
+
}>;
|
|
61
|
+
export declare function elementPredicateMismatch(element: LayoutElement, expectation: ElementExpectation): string | undefined;
|
|
53
62
|
export declare class ExpectationEvaluator {
|
|
54
63
|
private readonly adb;
|
|
55
|
-
private readonly
|
|
64
|
+
private readonly uiSnapshotProvider;
|
|
56
65
|
private readonly logcat;
|
|
57
66
|
private readonly clock;
|
|
58
67
|
private readonly pollIntervalMs;
|
|
59
|
-
|
|
68
|
+
private readonly matchedEvents;
|
|
69
|
+
constructor(adb: AdbPort, uiSnapshotProvider: UiSnapshotProvider, logcat: LogcatCollector, clock: Clock, pollIntervalMs?: number);
|
|
70
|
+
/** Internal runtime-only evidence, deliberately absent from JSON results. */
|
|
71
|
+
matchedEventFor(result: ExpectationResult): LogcatLine | undefined;
|
|
60
72
|
evaluate(expectation: Expectation, context: ExpectationContext, signal?: AbortSignal, observations?: ExpectationObservationBoundary): Promise<ExpectationResult>;
|
|
61
73
|
}
|
|
74
|
+
export {};
|
|
@@ -1,7 +1,18 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { matchesLogcatEvent, requestErrorClassFor } from "../collector/logcat-event.js";
|
|
1
3
|
import { resolveLocator } from "../locator/locator-resolver.js";
|
|
2
|
-
function
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
export function elementPredicateMismatch(element, expectation) {
|
|
5
|
+
if (expectation.enabled !== undefined
|
|
6
|
+
&& element.enabled !== expectation.enabled) {
|
|
7
|
+
return `element ${element.id} enabled=${element.enabled ? "true" : "false"}`
|
|
8
|
+
+ `, expected enabled=${expectation.enabled ? "true" : "false"}`;
|
|
9
|
+
}
|
|
10
|
+
if (expectation.clickable !== undefined
|
|
11
|
+
&& (element.clickable === true) !== expectation.clickable) {
|
|
12
|
+
return `element ${element.id} clickable=${element.clickable === true ? "true" : "false"}`
|
|
13
|
+
+ `, expected clickable=${expectation.clickable ? "true" : "false"}`;
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
5
16
|
}
|
|
6
17
|
function matchesLogcat(line, expectation, pattern) {
|
|
7
18
|
if (line.tag !== expectation.tag
|
|
@@ -19,17 +30,22 @@ function isAborted(signal) {
|
|
|
19
30
|
}
|
|
20
31
|
export class ExpectationEvaluator {
|
|
21
32
|
adb;
|
|
22
|
-
|
|
33
|
+
uiSnapshotProvider;
|
|
23
34
|
logcat;
|
|
24
35
|
clock;
|
|
25
36
|
pollIntervalMs;
|
|
26
|
-
|
|
37
|
+
matchedEvents = new WeakMap();
|
|
38
|
+
constructor(adb, uiSnapshotProvider, logcat, clock, pollIntervalMs = 100) {
|
|
27
39
|
this.adb = adb;
|
|
28
|
-
this.
|
|
40
|
+
this.uiSnapshotProvider = uiSnapshotProvider;
|
|
29
41
|
this.logcat = logcat;
|
|
30
42
|
this.clock = clock;
|
|
31
43
|
this.pollIntervalMs = pollIntervalMs;
|
|
32
44
|
}
|
|
45
|
+
/** Internal runtime-only evidence, deliberately absent from JSON results. */
|
|
46
|
+
matchedEventFor(result) {
|
|
47
|
+
return this.matchedEvents.get(result);
|
|
48
|
+
}
|
|
33
49
|
async evaluate(expectation, context, signal, observations = {}) {
|
|
34
50
|
const startedAt = this.clock.now();
|
|
35
51
|
const logPattern = expectation.type === "logcat"
|
|
@@ -38,6 +54,43 @@ export class ExpectationEvaluator {
|
|
|
38
54
|
: expectation.pattern)
|
|
39
55
|
: undefined;
|
|
40
56
|
let actual;
|
|
57
|
+
let elementObservation;
|
|
58
|
+
const window = expectation.type === "logcatEvent"
|
|
59
|
+
? expectation.window
|
|
60
|
+
: undefined;
|
|
61
|
+
const windowStart = window === undefined
|
|
62
|
+
? undefined
|
|
63
|
+
: window.from === "stepStart"
|
|
64
|
+
? context.stepStartedAt
|
|
65
|
+
: window.from === "runStart"
|
|
66
|
+
? context.runStartedAt
|
|
67
|
+
: context.markers?.get(window.markerId);
|
|
68
|
+
if (window !== undefined && windowStart === undefined) {
|
|
69
|
+
return {
|
|
70
|
+
status: "failed",
|
|
71
|
+
type: "logcatEvent",
|
|
72
|
+
code: "EXPECT_LOGCAT_FAILED",
|
|
73
|
+
message: "Logcat event window source is unavailable",
|
|
74
|
+
durationMs: 0
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const eventEvidence = (matched) => window === undefined || windowStart === undefined
|
|
78
|
+
? undefined
|
|
79
|
+
: {
|
|
80
|
+
matchedCount: matched.length,
|
|
81
|
+
...(matched.length !== 1 || matched[0] === undefined
|
|
82
|
+
? {}
|
|
83
|
+
: {
|
|
84
|
+
matchedLineSha256: createHash("sha256")
|
|
85
|
+
.update(matched[0].raw)
|
|
86
|
+
.digest("hex"),
|
|
87
|
+
...(requestErrorClassFor(matched[0]) === undefined
|
|
88
|
+
? {} : { requestErrorClass: requestErrorClassFor(matched[0]) })
|
|
89
|
+
}),
|
|
90
|
+
window,
|
|
91
|
+
startedAtMs: windowStart
|
|
92
|
+
};
|
|
93
|
+
let eventMatches = [];
|
|
41
94
|
for (;;) {
|
|
42
95
|
if (isAborted(signal)) {
|
|
43
96
|
return {
|
|
@@ -95,11 +148,12 @@ export class ExpectationEvaluator {
|
|
|
95
148
|
const observation = observations.layout === undefined
|
|
96
149
|
? {
|
|
97
150
|
status: "observed",
|
|
98
|
-
layout: await this.
|
|
99
|
-
|
|
151
|
+
layout: (await this.uiSnapshotProvider.capture({
|
|
152
|
+
reason: "expect",
|
|
153
|
+
freshness: "sameMutationEpoch",
|
|
100
154
|
...(signal === undefined ? {} : { signal }),
|
|
101
155
|
timeoutMs: commandTimeoutMs
|
|
102
|
-
})
|
|
156
|
+
})).roots
|
|
103
157
|
}
|
|
104
158
|
: await observations.layout({
|
|
105
159
|
timeoutMs: commandTimeoutMs,
|
|
@@ -121,12 +175,34 @@ export class ExpectationEvaluator {
|
|
|
121
175
|
durationMs: this.clock.now() - startedAt
|
|
122
176
|
};
|
|
123
177
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
178
|
+
const resolution = resolveLocator(observation.layout, expectation.locator, { requireEnabled: false });
|
|
179
|
+
if (expectation.absent === true) {
|
|
180
|
+
if (resolution.status === "failed"
|
|
181
|
+
&& resolution.code === "LOCATOR_NOT_FOUND"
|
|
182
|
+
&& resolution.evidenceMismatch !== true) {
|
|
183
|
+
return {
|
|
184
|
+
status: "passed",
|
|
185
|
+
type: expectation.type,
|
|
186
|
+
durationMs: this.clock.now() - startedAt
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
elementObservation = resolution.status === "found"
|
|
190
|
+
? `expected absent element matched by ${resolution.matchedBy}`
|
|
191
|
+
: `expected absent element still resolvable: ${resolution.message}`;
|
|
192
|
+
}
|
|
193
|
+
else if (resolution.status === "found") {
|
|
194
|
+
const mismatch = elementPredicateMismatch(resolution.element, expectation);
|
|
195
|
+
if (mismatch === undefined) {
|
|
196
|
+
return {
|
|
197
|
+
status: "passed",
|
|
198
|
+
type: expectation.type,
|
|
199
|
+
durationMs: this.clock.now() - startedAt
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
elementObservation = mismatch;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
elementObservation = resolution.message;
|
|
130
206
|
}
|
|
131
207
|
break;
|
|
132
208
|
}
|
|
@@ -142,6 +218,45 @@ export class ExpectationEvaluator {
|
|
|
142
218
|
matchedLine: matched.raw
|
|
143
219
|
};
|
|
144
220
|
}
|
|
221
|
+
if (!this.logcat.completeSince(context.stepStartedAt)) {
|
|
222
|
+
const metadata = this.logcat.metadata();
|
|
223
|
+
return {
|
|
224
|
+
status: "failed",
|
|
225
|
+
type: expectation.type,
|
|
226
|
+
code: "EXPECT_LOGCAT_FAILED",
|
|
227
|
+
message: "Logcat evidence is incomplete in the step window"
|
|
228
|
+
+ ` (droppedLines=${String(metadata.droppedLines ?? 0)},`
|
|
229
|
+
+ ` droppedBytes=${String(metadata.droppedBytes ?? 0)},`
|
|
230
|
+
+ ` lastDroppedAtMs=${String(metadata.lastDroppedAtMs ?? "unknown")})`,
|
|
231
|
+
durationMs: this.clock.now() - startedAt
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
case "logcatEvent": {
|
|
237
|
+
if (windowStart === undefined || !this.logcat.completeSince(windowStart)) {
|
|
238
|
+
return {
|
|
239
|
+
status: "failed",
|
|
240
|
+
type: expectation.type,
|
|
241
|
+
code: "EXPECT_LOGCAT_FAILED",
|
|
242
|
+
message: "Logcat event evidence is incomplete in the declared window",
|
|
243
|
+
durationMs: this.clock.now() - startedAt,
|
|
244
|
+
logcatEvent: eventEvidence(eventMatches)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
eventMatches = this.logcat
|
|
248
|
+
.linesBetween(windowStart, Math.min(this.clock.now(), startedAt + expectation.timeoutMs))
|
|
249
|
+
.filter((line) => matchesLogcatEvent(line, expectation));
|
|
250
|
+
if (eventMatches.length > 1) {
|
|
251
|
+
return {
|
|
252
|
+
status: "failed",
|
|
253
|
+
type: expectation.type,
|
|
254
|
+
code: "EXPECT_LOGCAT_AMBIGUOUS",
|
|
255
|
+
message: "Logcat event appeared more than once in the declared window",
|
|
256
|
+
durationMs: this.clock.now() - startedAt,
|
|
257
|
+
logcatEvent: eventEvidence(eventMatches)
|
|
258
|
+
};
|
|
259
|
+
}
|
|
145
260
|
break;
|
|
146
261
|
}
|
|
147
262
|
}
|
|
@@ -159,7 +274,8 @@ export class ExpectationEvaluator {
|
|
|
159
274
|
const codes = {
|
|
160
275
|
activity: "EXPECT_ACTIVITY_FAILED",
|
|
161
276
|
element: "EXPECT_ELEMENT_FAILED",
|
|
162
|
-
logcat: "EXPECT_LOGCAT_FAILED"
|
|
277
|
+
logcat: "EXPECT_LOGCAT_FAILED",
|
|
278
|
+
logcatEvent: "EXPECT_LOGCAT_FAILED"
|
|
163
279
|
};
|
|
164
280
|
return {
|
|
165
281
|
status: "failed",
|
|
@@ -177,14 +293,36 @@ export class ExpectationEvaluator {
|
|
|
177
293
|
const codes = {
|
|
178
294
|
activity: "EXPECT_ACTIVITY_FAILED",
|
|
179
295
|
element: "EXPECT_ELEMENT_FAILED",
|
|
180
|
-
logcat: "EXPECT_LOGCAT_FAILED"
|
|
296
|
+
logcat: "EXPECT_LOGCAT_FAILED",
|
|
297
|
+
logcatEvent: "EXPECT_LOGCAT_FAILED"
|
|
181
298
|
};
|
|
299
|
+
if (expectation.type === "logcatEvent" && eventMatches.length === 1) {
|
|
300
|
+
const result = {
|
|
301
|
+
status: "passed",
|
|
302
|
+
type: expectation.type,
|
|
303
|
+
durationMs: elapsed,
|
|
304
|
+
logcatEvent: eventEvidence(eventMatches)
|
|
305
|
+
};
|
|
306
|
+
if (eventMatches[0] !== undefined) {
|
|
307
|
+
this.matchedEvents.set(result, eventMatches[0]);
|
|
308
|
+
}
|
|
309
|
+
return result;
|
|
310
|
+
}
|
|
182
311
|
return {
|
|
183
312
|
status: "failed",
|
|
184
313
|
type: expectation.type,
|
|
185
314
|
code: codes[expectation.type],
|
|
186
|
-
message:
|
|
315
|
+
message: expectation.type === "logcatEvent"
|
|
316
|
+
? "Logcat event did not appear before timeout"
|
|
317
|
+
: expectation.type === "element"
|
|
318
|
+
? elementObservation === undefined
|
|
319
|
+
? "element Expect did not match before timeout"
|
|
320
|
+
: `element Expect did not match before timeout: ${elementObservation}`
|
|
321
|
+
: `${expectation.type} Expect did not match before timeout`,
|
|
187
322
|
durationMs: elapsed,
|
|
323
|
+
...(expectation.type === "logcatEvent"
|
|
324
|
+
? { logcatEvent: eventEvidence(eventMatches) }
|
|
325
|
+
: {}),
|
|
188
326
|
...(actual === undefined ? {} : { actual })
|
|
189
327
|
};
|
|
190
328
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Expectation } from "../../domain/journey.js";
|
|
2
|
+
import type { LayoutElement } from "../../domain/layout.js";
|
|
3
|
+
import type { ExpectationObservationBoundary, ExpectationObservationInput } from "./expectation-evaluator.js";
|
|
4
|
+
/**
|
|
5
|
+
* Engine-specific observation of the App under a bound identity. Each call
|
|
6
|
+
* re-checks the foreground package and process identity and throws when they
|
|
7
|
+
* no longer match; `layout` also re-checks them after the capture.
|
|
8
|
+
*/
|
|
9
|
+
export interface GuardedExpectationProbe<TObservation extends {
|
|
10
|
+
layout: readonly LayoutElement[];
|
|
11
|
+
}> {
|
|
12
|
+
activity: (input: ExpectationObservationInput) => Promise<string>;
|
|
13
|
+
layout: (input: ExpectationObservationInput) => Promise<TObservation>;
|
|
14
|
+
/** Errors that must propagate instead of failing the observation. */
|
|
15
|
+
rethrow?: (error: unknown) => boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Expectation observations shared by generated Replay and Generation. A guard
|
|
19
|
+
* violation becomes a failed observation, which the evaluator reports as
|
|
20
|
+
* `EXPECT_ACTIVITY_FAILED` or `EXPECT_ELEMENT_FAILED`. The first Layout
|
|
21
|
+
* observation reuses the settled post-action Layout, which the engine has
|
|
22
|
+
* already guarded, instead of capturing the same screen again.
|
|
23
|
+
*/
|
|
24
|
+
export declare class GuardedExpectationObservations<TObservation extends {
|
|
25
|
+
layout: readonly LayoutElement[];
|
|
26
|
+
}> {
|
|
27
|
+
private readonly probe;
|
|
28
|
+
private seed;
|
|
29
|
+
private last;
|
|
30
|
+
constructor(probe: GuardedExpectationProbe<TObservation>, settled?: TObservation);
|
|
31
|
+
boundary(): ExpectationObservationBoundary;
|
|
32
|
+
/** The Layout observation the element expectation last resolved against. */
|
|
33
|
+
lastLayoutObservation(): TObservation | undefined;
|
|
34
|
+
private failed;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The foreground a passing expectation leaves behind. An `element`
|
|
38
|
+
* expectation is proven on the guarded Layout it resolved against and an
|
|
39
|
+
* `activity` expectation on the guarded Activity it matched; log expectations
|
|
40
|
+
* prove nothing about the screen, so the foreground must be re-checked.
|
|
41
|
+
*/
|
|
42
|
+
export declare function settledExpectationForeground(expectation: Expectation, afterActivity: string): {
|
|
43
|
+
activity: string;
|
|
44
|
+
proven: boolean;
|
|
45
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expectation observations shared by generated Replay and Generation. A guard
|
|
3
|
+
* violation becomes a failed observation, which the evaluator reports as
|
|
4
|
+
* `EXPECT_ACTIVITY_FAILED` or `EXPECT_ELEMENT_FAILED`. The first Layout
|
|
5
|
+
* observation reuses the settled post-action Layout, which the engine has
|
|
6
|
+
* already guarded, instead of capturing the same screen again.
|
|
7
|
+
*/
|
|
8
|
+
export class GuardedExpectationObservations {
|
|
9
|
+
probe;
|
|
10
|
+
seed;
|
|
11
|
+
last;
|
|
12
|
+
constructor(probe, settled) {
|
|
13
|
+
this.probe = probe;
|
|
14
|
+
this.seed = settled;
|
|
15
|
+
}
|
|
16
|
+
boundary() {
|
|
17
|
+
return {
|
|
18
|
+
activity: async (input) => {
|
|
19
|
+
try {
|
|
20
|
+
return {
|
|
21
|
+
status: "observed",
|
|
22
|
+
activity: await this.probe.activity(input)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return this.failed(error, "Expect Activity observation failed");
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
layout: async (input) => {
|
|
30
|
+
if (this.seed !== undefined) {
|
|
31
|
+
this.last = this.seed;
|
|
32
|
+
this.seed = undefined;
|
|
33
|
+
return { status: "observed", layout: this.last.layout };
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
this.last = await this.probe.layout(input);
|
|
37
|
+
return { status: "observed", layout: this.last.layout };
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return this.failed(error, "Expect Layout observation failed");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** The Layout observation the element expectation last resolved against. */
|
|
46
|
+
lastLayoutObservation() {
|
|
47
|
+
return this.last;
|
|
48
|
+
}
|
|
49
|
+
failed(error, fallback) {
|
|
50
|
+
if (this.probe.rethrow?.(error) === true)
|
|
51
|
+
throw error;
|
|
52
|
+
return {
|
|
53
|
+
status: "failed",
|
|
54
|
+
message: error instanceof Error ? error.message : fallback
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The foreground a passing expectation leaves behind. An `element`
|
|
60
|
+
* expectation is proven on the guarded Layout it resolved against and an
|
|
61
|
+
* `activity` expectation on the guarded Activity it matched; log expectations
|
|
62
|
+
* prove nothing about the screen, so the foreground must be re-checked.
|
|
63
|
+
*/
|
|
64
|
+
export function settledExpectationForeground(expectation, afterActivity) {
|
|
65
|
+
switch (expectation.type) {
|
|
66
|
+
case "activity":
|
|
67
|
+
return { activity: expectation.value, proven: true };
|
|
68
|
+
case "element":
|
|
69
|
+
return { activity: afterActivity, proven: true };
|
|
70
|
+
case "logcat":
|
|
71
|
+
case "logcatEvent":
|
|
72
|
+
return { activity: afterActivity, proven: false };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Baseline } from "../../domain/checkpoint.js";
|
|
2
|
+
import type { VerifyResult } from "../runtime/verify-runtime.js";
|
|
3
|
+
export interface BaselineCaptureInput {
|
|
4
|
+
id: string;
|
|
5
|
+
journeySha256: string;
|
|
6
|
+
contractSha256?: string | undefined;
|
|
7
|
+
includeScreenFacts?: boolean | undefined;
|
|
8
|
+
capturedAt: string;
|
|
9
|
+
runId: string;
|
|
10
|
+
packageName: string;
|
|
11
|
+
result: Pick<VerifyResult, "report" | "hookOutcomes" | "status" | "reportPath">;
|
|
12
|
+
}
|
|
13
|
+
export interface BaselineCapturerDependencies {
|
|
14
|
+
now: () => Date;
|
|
15
|
+
createBaselineId?: (() => string) | undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Captures a Baseline from a completed (passing) verification run. The
|
|
19
|
+
* capture is read-only with respect to the device: it derives deterministic
|
|
20
|
+
* facts from the published report and hook outcomes.
|
|
21
|
+
*/
|
|
22
|
+
export declare class BaselineCapturer {
|
|
23
|
+
private readonly dependencies;
|
|
24
|
+
constructor(dependencies: BaselineCapturerDependencies);
|
|
25
|
+
readonly capture: (input: BaselineCaptureInput) => Baseline;
|
|
26
|
+
}
|