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
|
@@ -2,9 +2,14 @@ import { z } from "zod";
|
|
|
2
2
|
import { primaryAppPid } from "../../domain/app-process.js";
|
|
3
3
|
import { GenerationSessionIdSchema, GenerationSessionSchema } from "../../domain/generation.js";
|
|
4
4
|
import { LayoutElementSchema } from "../../domain/layout.js";
|
|
5
|
+
import { uiBackendIdAsSelection } from "../../domain/ui-backend.js";
|
|
5
6
|
import { ProposalBindingSchema } from "../../domain/proposed-step.js";
|
|
6
7
|
import { RuntimeSnapshotSchema, hashRuntimeSnapshot } from "../../domain/runtime-snapshot.js";
|
|
8
|
+
import { assessWindowHierarchy } from "../../domain/window-hierarchy.js";
|
|
9
|
+
import { withIdleAdvice } from "../wait/idle-advice.js";
|
|
7
10
|
import { GenerationOperationError } from "./generation-starter.js";
|
|
11
|
+
import { closeUiSnapshotProvider } from "../ui/ui-snapshot-lifecycle.js";
|
|
12
|
+
import { uiStabilityProbe } from "../ui/ui-stability-probe.js";
|
|
8
13
|
function failedCapture(result) {
|
|
9
14
|
return result.exitCode !== 0
|
|
10
15
|
|| result.timedOut
|
|
@@ -15,9 +20,11 @@ function revisionPath(revision) {
|
|
|
15
20
|
return `evidence/snapshots/revision-${String(revision).padStart(6, "0")}`;
|
|
16
21
|
}
|
|
17
22
|
function assertObservable(session) {
|
|
23
|
+
if (session.pendingConfirmation !== null) {
|
|
24
|
+
throw new GenerationOperationError("RISK_CONFIRMATION_REQUIRED", `Generation confirmation ${session.pendingConfirmation.challengeId} must be resolved before observation`, { challenge: session.pendingConfirmation });
|
|
25
|
+
}
|
|
18
26
|
if (session.state !== "active"
|
|
19
|
-
|| session.inFlight !== null
|
|
20
|
-
|| session.pendingConfirmation !== null) {
|
|
27
|
+
|| session.inFlight !== null) {
|
|
21
28
|
throw new Error("Generation session must be active and idle to observe");
|
|
22
29
|
}
|
|
23
30
|
if (session.revision === Number.MAX_SAFE_INTEGER) {
|
|
@@ -30,17 +37,45 @@ async function collectRuntime(dependencies, session, signal) {
|
|
|
30
37
|
deviceSerial: session.target.deviceSerial,
|
|
31
38
|
...(signal === undefined ? {} : { signal })
|
|
32
39
|
};
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
const [foregroundResult, processesResult, topologyResult, snapshotResult] = await Promise.allSettled([
|
|
41
|
+
dependencies.adb.foregroundComponent(identity),
|
|
42
|
+
dependencies.adb.appProcesses(identity),
|
|
43
|
+
dependencies.adb.windowTopology(identity),
|
|
44
|
+
dependencies.uiSnapshotProvider.capture({
|
|
45
|
+
reason: "evidence",
|
|
46
|
+
timeoutMs: dependencies.uiSnapshotTimeoutMs,
|
|
47
|
+
...(signal === undefined ? {} : { signal })
|
|
48
|
+
})
|
|
49
|
+
]);
|
|
50
|
+
const settledValue = (result) => {
|
|
51
|
+
if (result.status === "fulfilled") {
|
|
52
|
+
return result.value;
|
|
53
|
+
}
|
|
54
|
+
const reason = result.reason;
|
|
55
|
+
if (reason instanceof Error) {
|
|
56
|
+
throw reason;
|
|
57
|
+
}
|
|
58
|
+
throw new Error("Runtime observation failed");
|
|
59
|
+
};
|
|
60
|
+
const foreground = settledValue(foregroundResult);
|
|
61
|
+
const processes = settledValue(processesResult);
|
|
62
|
+
const topology = settledValue(topologyResult);
|
|
63
|
+
const uiSnapshot = settledValue(snapshotResult);
|
|
64
|
+
const pid = primaryAppPid(processes, session.target.packageName);
|
|
65
|
+
const layout = z.array(LayoutElementSchema).parse(uiSnapshot.roots);
|
|
39
66
|
return {
|
|
40
67
|
foregroundPackageName: foreground.packageName,
|
|
41
68
|
activity: foreground.activity,
|
|
42
69
|
pid,
|
|
43
|
-
layout
|
|
70
|
+
layout,
|
|
71
|
+
uiSnapshot: {
|
|
72
|
+
observationId: uiSnapshot.observationId,
|
|
73
|
+
capturedAt: uiSnapshot.capturedAt,
|
|
74
|
+
durationMs: uiSnapshot.durationMs,
|
|
75
|
+
backend: uiSnapshot.backend,
|
|
76
|
+
viewport: uiSnapshot.viewport
|
|
77
|
+
},
|
|
78
|
+
windowHierarchy: assessWindowHierarchy(topology, layout)
|
|
44
79
|
};
|
|
45
80
|
}
|
|
46
81
|
export class RuntimeObserver {
|
|
@@ -51,16 +86,101 @@ export class RuntimeObserver {
|
|
|
51
86
|
observe = async (input) => {
|
|
52
87
|
const current = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
|
|
53
88
|
assertObservable(current);
|
|
54
|
-
const
|
|
89
|
+
const idle = current.idlePolicy === undefined
|
|
90
|
+
? input.idle
|
|
91
|
+
: current.idlePolicy;
|
|
92
|
+
const session = await this.dependencies.sessions.openSession({
|
|
93
|
+
deviceSerial: current.target.deviceSerial,
|
|
94
|
+
...(input.signal === undefined ? {} : { signal: input.signal })
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
const views = this.dependencies.sessionPorts(session);
|
|
98
|
+
const boundBackendSelection = uiBackendIdAsSelection(current.bindings.uiBackend.id);
|
|
99
|
+
const uiSnapshotProvider = await session.openUiSnapshots({
|
|
100
|
+
timeoutMs: idle?.timeoutMs ?? 5000,
|
|
101
|
+
...(boundBackendSelection === undefined
|
|
102
|
+
? {}
|
|
103
|
+
: { backend: boundBackendSelection }),
|
|
104
|
+
...(this.dependencies.uiCacheEnabled === undefined
|
|
105
|
+
? {}
|
|
106
|
+
: { cacheEnabled: this.dependencies.uiCacheEnabled }),
|
|
107
|
+
...(input.signal === undefined ? {} : { signal: input.signal })
|
|
108
|
+
});
|
|
109
|
+
let runtime;
|
|
110
|
+
try {
|
|
111
|
+
if (JSON.stringify(current.bindings.uiBackend)
|
|
112
|
+
!== JSON.stringify(uiSnapshotProvider.descriptor)) {
|
|
113
|
+
throw new GenerationOperationError("CONFIG_INVALID", "Generation UI backend does not match the authoritative session");
|
|
114
|
+
}
|
|
115
|
+
if (idle !== undefined
|
|
116
|
+
&& this.dependencies.waitUntilIdle !== undefined) {
|
|
117
|
+
const idleResult = await this.dependencies.waitUntilIdle(current.target.deviceSerial, idle, input.signal, current.target.packageName, uiStabilityProbe(uiSnapshotProvider, views.uiStability), views.adb);
|
|
118
|
+
if (idleResult.status !== "stable") {
|
|
119
|
+
throw new GenerationOperationError(idleResult.status === "cancelled" ? "RECOVERY_REQUIRED" : "IDLE_TIMEOUT", idleResult.status === "cancelled"
|
|
120
|
+
? "Runtime observation was cancelled while waiting for layout stability"
|
|
121
|
+
: withIdleAdvice("Layout did not become stable before observation", idleResult), idleResult.status === "cancelled"
|
|
122
|
+
? undefined
|
|
123
|
+
: {
|
|
124
|
+
idle: {
|
|
125
|
+
strategy: idleResult.strategy,
|
|
126
|
+
...(idleResult.backend === undefined
|
|
127
|
+
? {}
|
|
128
|
+
: { backend: idleResult.backend }),
|
|
129
|
+
polls: idleResult.polls,
|
|
130
|
+
durationMs: idleResult.durationMs,
|
|
131
|
+
samplingDurationMs: idleResult.samplingDurationMs,
|
|
132
|
+
fallbackUsed: idleResult.fallbackUsed,
|
|
133
|
+
frameActivityDetected: idleResult.frameActivityDetected,
|
|
134
|
+
lastDiff: idleResult.lastDiff
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
runtime = await collectRuntime({
|
|
140
|
+
adb: views.adb,
|
|
141
|
+
uiSnapshotProvider,
|
|
142
|
+
uiSnapshotTimeoutMs: this.dependencies.uiSnapshotTimeoutMs ?? 5000
|
|
143
|
+
}, current, input.signal);
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
await closeUiSnapshotProvider(uiSnapshotProvider);
|
|
147
|
+
}
|
|
148
|
+
return await this.commit(current, runtime, views, input.signal);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
await session.close();
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
observeCollected = async (input) => {
|
|
155
|
+
const current = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
|
|
156
|
+
assertObservable(current);
|
|
157
|
+
if (input.runtime.foregroundPackageName !== current.target.packageName
|
|
158
|
+
|| input.runtime.pid === null) {
|
|
159
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", "Collected post-action runtime is not a valid target-app state");
|
|
160
|
+
}
|
|
161
|
+
const session = await this.dependencies.sessions.openSession({
|
|
162
|
+
deviceSerial: current.target.deviceSerial,
|
|
163
|
+
...(input.signal === undefined ? {} : { signal: input.signal })
|
|
164
|
+
});
|
|
165
|
+
try {
|
|
166
|
+
const views = this.dependencies.sessionPorts(session);
|
|
167
|
+
return await this.commit(current, input.runtime, views, input.signal);
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
await session.close();
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
async commit(current, runtime, views, signal) {
|
|
55
174
|
const baseRevision = current.revision + 1;
|
|
56
175
|
const attemptId = GenerationSessionIdSchema.parse(this.dependencies.createAttemptId());
|
|
57
176
|
const evidenceDirectory = `${revisionPath(baseRevision)}/${attemptId}`;
|
|
58
177
|
const screenshotPath = `${evidenceDirectory}/screen.png`;
|
|
178
|
+
const snapshotPath = `${evidenceDirectory}/snapshot.json`;
|
|
59
179
|
await this.dependencies.store.produceEvidence(current.id, screenshotPath, async (temporaryPath) => {
|
|
60
|
-
const capture = await
|
|
180
|
+
const capture = await views.screenshots.capture({
|
|
61
181
|
outputPath: temporaryPath,
|
|
62
182
|
deviceSerial: current.target.deviceSerial,
|
|
63
|
-
...(
|
|
183
|
+
...(signal === undefined ? {} : { signal })
|
|
64
184
|
});
|
|
65
185
|
if (failedCapture(capture)) {
|
|
66
186
|
throw new Error(capture.stderr.trim()
|
|
@@ -68,8 +188,23 @@ export class RuntimeObserver {
|
|
|
68
188
|
|| "Runtime screenshot capture failed");
|
|
69
189
|
}
|
|
70
190
|
});
|
|
191
|
+
const identity = {
|
|
192
|
+
packageName: current.target.packageName,
|
|
193
|
+
deviceSerial: current.target.deviceSerial,
|
|
194
|
+
...(signal === undefined ? {} : { signal })
|
|
195
|
+
};
|
|
196
|
+
const [confirmedForeground, confirmedProcesses] = await Promise.all([
|
|
197
|
+
views.adb.foregroundComponent(identity),
|
|
198
|
+
views.adb.appProcesses(identity)
|
|
199
|
+
]);
|
|
200
|
+
const confirmedPid = primaryAppPid(confirmedProcesses, current.target.packageName);
|
|
201
|
+
if (confirmedForeground.packageName !== runtime.foregroundPackageName
|
|
202
|
+
|| confirmedForeground.activity !== runtime.activity
|
|
203
|
+
|| confirmedPid !== runtime.pid) {
|
|
204
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", "Runtime identity changed while snapshot evidence was captured");
|
|
205
|
+
}
|
|
71
206
|
const snapshot = RuntimeSnapshotSchema.parse({
|
|
72
|
-
version:
|
|
207
|
+
version: 2,
|
|
73
208
|
generationId: current.id,
|
|
74
209
|
baseRevision,
|
|
75
210
|
deviceSerial: current.target.deviceSerial,
|
|
@@ -77,21 +212,28 @@ export class RuntimeObserver {
|
|
|
77
212
|
foregroundPackageName: runtime.foregroundPackageName,
|
|
78
213
|
activity: runtime.activity,
|
|
79
214
|
pid: runtime.pid,
|
|
80
|
-
capturedAt:
|
|
215
|
+
capturedAt: runtime.uiSnapshot.capturedAt,
|
|
81
216
|
screenshotPath,
|
|
82
|
-
layout: runtime.layout
|
|
217
|
+
layout: runtime.layout,
|
|
218
|
+
windowHierarchy: runtime.windowHierarchy,
|
|
219
|
+
uiBackend: runtime.uiSnapshot.backend,
|
|
220
|
+
uiObservationId: runtime.uiSnapshot.observationId,
|
|
221
|
+
uiCaptureDurationMs: runtime.uiSnapshot.durationMs,
|
|
222
|
+
viewport: runtime.uiSnapshot.viewport
|
|
83
223
|
});
|
|
84
224
|
const snapshotHash = hashRuntimeSnapshot(snapshot);
|
|
85
|
-
await this.dependencies.store.writeEvidence(current.id,
|
|
225
|
+
await this.dependencies.store.writeEvidence(current.id, snapshotPath, snapshot);
|
|
86
226
|
const next = GenerationSessionSchema.parse({
|
|
87
227
|
...current,
|
|
88
228
|
revision: baseRevision,
|
|
89
229
|
bindings: {
|
|
90
230
|
...current.bindings,
|
|
91
|
-
snapshotHash
|
|
231
|
+
snapshotHash,
|
|
232
|
+
uiBackend: runtime.uiSnapshot.backend
|
|
92
233
|
}
|
|
93
234
|
});
|
|
94
235
|
await this.dependencies.store.commitSnapshot(current.id, current.revision, next);
|
|
236
|
+
const snapshotRef = await this.dependencies.store.evidenceReference(current.id, snapshotPath);
|
|
95
237
|
return {
|
|
96
238
|
binding: {
|
|
97
239
|
generationId: current.id,
|
|
@@ -99,16 +241,17 @@ export class RuntimeObserver {
|
|
|
99
241
|
snapshotHash
|
|
100
242
|
},
|
|
101
243
|
snapshot,
|
|
102
|
-
snapshotHash
|
|
244
|
+
snapshotHash,
|
|
245
|
+
snapshotRef
|
|
103
246
|
};
|
|
104
|
-
}
|
|
247
|
+
}
|
|
105
248
|
}
|
|
106
249
|
export class SnapshotReobservationGuard {
|
|
107
250
|
dependencies;
|
|
108
251
|
constructor(dependencies) {
|
|
109
252
|
this.dependencies = dependencies;
|
|
110
253
|
}
|
|
111
|
-
assertFresh = async (input, signal, approvedConfirmation) => {
|
|
254
|
+
assertFresh = async (input, signal, approvedConfirmation, tolerance) => {
|
|
112
255
|
try {
|
|
113
256
|
const binding = ProposalBindingSchema.parse(input);
|
|
114
257
|
const session = GenerationSessionSchema.parse(await this.dependencies.store.read(binding.generationId));
|
|
@@ -127,9 +270,17 @@ export class SnapshotReobservationGuard {
|
|
|
127
270
|
!== JSON.stringify(approvedConfirmation)))) {
|
|
128
271
|
throw new GenerationOperationError("SNAPSHOT_STALE", "Proposal snapshot binding is no longer authoritative");
|
|
129
272
|
}
|
|
130
|
-
|
|
273
|
+
if (JSON.stringify(session.bindings.uiBackend)
|
|
274
|
+
!== JSON.stringify(this.dependencies.uiSnapshotProvider.descriptor)) {
|
|
275
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", "Generation UI backend changed after snapshot binding");
|
|
276
|
+
}
|
|
277
|
+
const runtime = await collectRuntime({
|
|
278
|
+
adb: this.dependencies.adb,
|
|
279
|
+
uiSnapshotProvider: this.dependencies.uiSnapshotProvider,
|
|
280
|
+
uiSnapshotTimeoutMs: this.dependencies.uiSnapshotTimeoutMs ?? 5000
|
|
281
|
+
}, session, signal);
|
|
131
282
|
const snapshot = RuntimeSnapshotSchema.parse({
|
|
132
|
-
version:
|
|
283
|
+
version: 2,
|
|
133
284
|
generationId: session.id,
|
|
134
285
|
baseRevision: binding.baseRevision,
|
|
135
286
|
deviceSerial: session.target.deviceSerial,
|
|
@@ -137,11 +288,29 @@ export class SnapshotReobservationGuard {
|
|
|
137
288
|
foregroundPackageName: runtime.foregroundPackageName,
|
|
138
289
|
activity: runtime.activity,
|
|
139
290
|
pid: runtime.pid,
|
|
140
|
-
capturedAt:
|
|
291
|
+
capturedAt: runtime.uiSnapshot.capturedAt,
|
|
141
292
|
screenshotPath: "non-authoritative://runtime-reobservation",
|
|
142
|
-
layout: runtime.layout
|
|
293
|
+
layout: runtime.layout,
|
|
294
|
+
windowHierarchy: runtime.windowHierarchy,
|
|
295
|
+
uiBackend: runtime.uiSnapshot.backend,
|
|
296
|
+
uiObservationId: runtime.uiSnapshot.observationId,
|
|
297
|
+
uiCaptureDurationMs: runtime.uiSnapshot.durationMs,
|
|
298
|
+
viewport: runtime.uiSnapshot.viewport
|
|
143
299
|
});
|
|
144
300
|
if (hashRuntimeSnapshot(snapshot) !== binding.snapshotHash) {
|
|
301
|
+
// A targetless proposal (wait) does not consume the Layout, so a
|
|
302
|
+
// pure Layout change (for example a loading indicator that
|
|
303
|
+
// disappeared between binding and execution) is tolerated when the
|
|
304
|
+
// caller hands back the authoritative bound Snapshot and every
|
|
305
|
+
// other hashed field still matches. Any other drift stays
|
|
306
|
+
// fail-closed.
|
|
307
|
+
const bound = tolerance?.layoutChangeFrom;
|
|
308
|
+
if (bound !== undefined
|
|
309
|
+
&& hashRuntimeSnapshot(bound) === binding.snapshotHash
|
|
310
|
+
&& hashRuntimeSnapshot({ ...snapshot, layout: [] })
|
|
311
|
+
=== hashRuntimeSnapshot({ ...bound, layout: [] })) {
|
|
312
|
+
return snapshot;
|
|
313
|
+
}
|
|
145
314
|
throw new GenerationOperationError("SNAPSHOT_STALE", "Runtime snapshot changed after proposal");
|
|
146
315
|
}
|
|
147
316
|
return snapshot;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type ChangeSet, type ImpactSet } from "../../domain/impact.js";
|
|
2
|
+
import type { Journey } from "../../domain/journey.js";
|
|
3
|
+
import type { ProjectContextModule, ResolvedProjectContext } from "../../domain/project-context.js";
|
|
4
|
+
import type { LoadedKnowledgeBundle } from "../../ports/knowledge-registry.js";
|
|
5
|
+
export interface ImpactResolverDependencies {
|
|
6
|
+
loadContext: (input: {
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
}) => Promise<{
|
|
9
|
+
context: ResolvedProjectContext;
|
|
10
|
+
modules: ProjectContextModule[];
|
|
11
|
+
}>;
|
|
12
|
+
loadKnowledge: (input: {
|
|
13
|
+
projectRoot: string;
|
|
14
|
+
packageName: string;
|
|
15
|
+
}) => Promise<LoadedKnowledgeBundle>;
|
|
16
|
+
listJourneyPaths: (input: {
|
|
17
|
+
projectRoot: string;
|
|
18
|
+
}) => Promise<readonly string[]>;
|
|
19
|
+
readJourney: (input: {
|
|
20
|
+
projectRoot: string;
|
|
21
|
+
path: string;
|
|
22
|
+
}) => Promise<Journey | null>;
|
|
23
|
+
}
|
|
24
|
+
export declare class ImpactResolver {
|
|
25
|
+
private readonly dependencies;
|
|
26
|
+
constructor(dependencies: ImpactResolverDependencies);
|
|
27
|
+
readonly resolve: (input: {
|
|
28
|
+
projectRoot: string;
|
|
29
|
+
packageName: string;
|
|
30
|
+
changeSet: ChangeSet;
|
|
31
|
+
}) => Promise<ImpactSet>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { ImpactSetSchema } from "../../domain/impact.js";
|
|
3
|
+
function unique(values) {
|
|
4
|
+
return [...new Set(values)];
|
|
5
|
+
}
|
|
6
|
+
function contextEvidenceHash(context, modules) {
|
|
7
|
+
const canonicalModules = modules
|
|
8
|
+
.map((module) => ({
|
|
9
|
+
moduleId: module.moduleId,
|
|
10
|
+
projectDir: module.projectDir,
|
|
11
|
+
inventory: module.inventory,
|
|
12
|
+
manifest: module.manifest
|
|
13
|
+
}))
|
|
14
|
+
.sort((left, right) => left.moduleId.localeCompare(right.moduleId));
|
|
15
|
+
const canonical = JSON.stringify({
|
|
16
|
+
selection: context.selection,
|
|
17
|
+
modules: canonicalModules
|
|
18
|
+
});
|
|
19
|
+
return createHash("sha256").update(canonical).digest("hex");
|
|
20
|
+
}
|
|
21
|
+
function journeyAnchorIds(journey) {
|
|
22
|
+
return journey.steps
|
|
23
|
+
.map((step) => ("anchor" in step && step.anchor !== undefined ? step.anchor : undefined))
|
|
24
|
+
.filter((id) => id !== undefined);
|
|
25
|
+
}
|
|
26
|
+
function moduleForChangedFiles(modules, changeSet) {
|
|
27
|
+
const changed = changeSet.files.flatMap((file) => [
|
|
28
|
+
file.path,
|
|
29
|
+
...(file.oldPath === undefined ? [] : [file.oldPath])
|
|
30
|
+
]);
|
|
31
|
+
const result = [];
|
|
32
|
+
for (const module of modules) {
|
|
33
|
+
const evidencePaths = new Set(module.manifest.files.map((file) => file.path));
|
|
34
|
+
const touched = changed.some((path) => (evidencePaths.has(path)
|
|
35
|
+
|| (module.projectDir !== "."
|
|
36
|
+
&& path.startsWith(`${module.projectDir}/`))));
|
|
37
|
+
if (touched) {
|
|
38
|
+
result.push(module.moduleId);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
export class ImpactResolver {
|
|
44
|
+
dependencies;
|
|
45
|
+
constructor(dependencies) {
|
|
46
|
+
this.dependencies = dependencies;
|
|
47
|
+
}
|
|
48
|
+
resolve = async (input) => {
|
|
49
|
+
const { projectRoot, packageName, changeSet } = input;
|
|
50
|
+
const [context, knowledge, journeyPaths] = await Promise.all([
|
|
51
|
+
this.dependencies.loadContext({
|
|
52
|
+
projectRoot
|
|
53
|
+
}),
|
|
54
|
+
this.dependencies.loadKnowledge({
|
|
55
|
+
projectRoot,
|
|
56
|
+
packageName
|
|
57
|
+
}),
|
|
58
|
+
this.dependencies.listJourneyPaths({
|
|
59
|
+
projectRoot
|
|
60
|
+
})
|
|
61
|
+
]);
|
|
62
|
+
const contextModules = context.modules;
|
|
63
|
+
const changedPathSet = new Set(changeSet.files.flatMap((file) => [
|
|
64
|
+
file.path,
|
|
65
|
+
...(file.oldPath === undefined ? [] : [file.oldPath])
|
|
66
|
+
]));
|
|
67
|
+
const affectedModules = unique(moduleForChangedFiles(contextModules, changeSet));
|
|
68
|
+
const affectedAnchors = unique(knowledge.anchors
|
|
69
|
+
.filter((anchor) => ((anchor.sourceFiles ?? []).some((path) => changedPathSet.has(path))))
|
|
70
|
+
.map((anchor) => anchor.id));
|
|
71
|
+
const affectedAnchorsSet = new Set(affectedAnchors);
|
|
72
|
+
const affectedScreens = unique(knowledge.screens
|
|
73
|
+
.filter((screen) => ((screen.sourceFiles ?? []).some((path) => changedPathSet.has(path))
|
|
74
|
+
|| screen.requiredAnchors.some((id) => affectedAnchorsSet.has(id))
|
|
75
|
+
|| screen.optionalAnchors.some((id) => affectedAnchorsSet.has(id))
|
|
76
|
+
|| screen.forbiddenAnchors.some((id) => affectedAnchorsSet.has(id))
|
|
77
|
+
|| screen.predicates.some((predicate) => ("anchorId" in predicate
|
|
78
|
+
&& affectedAnchorsSet.has(predicate.anchorId)))))
|
|
79
|
+
.map((screen) => screen.id));
|
|
80
|
+
const affectedScreensSet = new Set(affectedScreens);
|
|
81
|
+
const affectedModulesSet = new Set(affectedModules);
|
|
82
|
+
const affectedFeatures = unique(contextModules
|
|
83
|
+
.filter((module) => affectedModulesSet.has(module.moduleId))
|
|
84
|
+
.flatMap((module) => module.summary.features));
|
|
85
|
+
const p0 = [];
|
|
86
|
+
const p1 = [];
|
|
87
|
+
const p2 = [];
|
|
88
|
+
const skipped = [];
|
|
89
|
+
for (const path of journeyPaths) {
|
|
90
|
+
const journey = await this.dependencies.readJourney({
|
|
91
|
+
projectRoot,
|
|
92
|
+
path
|
|
93
|
+
});
|
|
94
|
+
if (journey === null) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const anchorsInJourney = journeyAnchorIds(journey);
|
|
98
|
+
const directAnchor = anchorsInJourney.find((id) => (affectedAnchorsSet.has(id)));
|
|
99
|
+
if (directAnchor !== undefined) {
|
|
100
|
+
p0.push({
|
|
101
|
+
id: path,
|
|
102
|
+
reason: `journey resolves affected Knowledge anchor ${directAnchor}`
|
|
103
|
+
});
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const affectedAnchorByScreen = anchorsInJourney.find((id) => (knowledge.screens.some((screen) => (affectedScreensSet.has(screen.id)
|
|
107
|
+
&& (screen.requiredAnchors.includes(id)
|
|
108
|
+
|| screen.optionalAnchors.includes(id)
|
|
109
|
+
|| screen.forbiddenAnchors.includes(id))))));
|
|
110
|
+
if (affectedAnchorByScreen !== undefined) {
|
|
111
|
+
p1.push({
|
|
112
|
+
id: path,
|
|
113
|
+
reason: `journey anchors share a screen with the affected change ${affectedAnchorByScreen}`
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (anchorsInJourney.length === 0) {
|
|
118
|
+
if (affectedModules.length > 0) {
|
|
119
|
+
p1.push({
|
|
120
|
+
id: path,
|
|
121
|
+
reason: "affected module requires conservative coverage for a locator-only journey"
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
skipped.push({
|
|
126
|
+
id: path,
|
|
127
|
+
reason: "journey uses only runtime locators; no semantic anchor binding"
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (affectedModules.length > 0) {
|
|
133
|
+
p1.push({
|
|
134
|
+
id: path,
|
|
135
|
+
reason: "affected module requires conservative semantic journey coverage"
|
|
136
|
+
});
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
p2.push({
|
|
140
|
+
id: path,
|
|
141
|
+
reason: "journey anchors do not resolve affected anchor/screen ids"
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return ImpactSetSchema.parse({
|
|
145
|
+
version: 1,
|
|
146
|
+
base: changeSet.base,
|
|
147
|
+
head: changeSet.head,
|
|
148
|
+
affectedModules,
|
|
149
|
+
affectedFeatures,
|
|
150
|
+
affectedScreens,
|
|
151
|
+
affectedAnchors,
|
|
152
|
+
selectedJourneys: { p0, p1, p2 },
|
|
153
|
+
skippedJourneys: skipped,
|
|
154
|
+
provenance: {
|
|
155
|
+
contextHash: contextEvidenceHash(context.context, contextModules),
|
|
156
|
+
knowledgeHash: knowledge.knowledgeHash
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -9,34 +9,47 @@ export class InitService {
|
|
|
9
9
|
if (input.agents.length === 0) {
|
|
10
10
|
throw new NoAgentsSelectedError();
|
|
11
11
|
}
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const allAgents = [];
|
|
12
|
+
const skillNames = await this.deps.installer.listSkillNames();
|
|
13
|
+
const targets = resolveTargetPaths(skillNames, input.agents, input.global, this.deps.cwd, this.deps.homedir);
|
|
14
|
+
const groupMap = new Map();
|
|
16
15
|
for (const target of targets) {
|
|
17
|
-
const result = await this.deps.installer.installTo(target.absolutePath);
|
|
16
|
+
const result = await this.deps.installer.installTo(target.skillName, target.absolutePath);
|
|
17
|
+
let group = groupMap.get(target.skillName);
|
|
18
|
+
if (group === undefined) {
|
|
19
|
+
group = { name: target.skillName, paths: [], skipped: [] };
|
|
20
|
+
groupMap.set(target.skillName, group);
|
|
21
|
+
}
|
|
18
22
|
if (result.skipped) {
|
|
19
|
-
|
|
23
|
+
group.skipped.push(target.relativePath);
|
|
20
24
|
}
|
|
21
25
|
else {
|
|
22
|
-
|
|
26
|
+
group.paths.push(target.relativePath);
|
|
23
27
|
}
|
|
28
|
+
}
|
|
29
|
+
const allAgents = [];
|
|
30
|
+
for (const target of targets) {
|
|
24
31
|
for (const agent of target.agents) {
|
|
25
32
|
if (!allAgents.includes(agent)) {
|
|
26
33
|
allAgents.push(agent);
|
|
27
34
|
}
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
|
-
const
|
|
37
|
+
const skills = [...groupMap.values()].map((group) => {
|
|
38
|
+
const skill = {
|
|
39
|
+
name: group.name,
|
|
40
|
+
paths: group.paths
|
|
41
|
+
};
|
|
42
|
+
if (group.skipped.length > 0) {
|
|
43
|
+
skill.skipped = group.skipped;
|
|
44
|
+
}
|
|
45
|
+
return skill;
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
31
48
|
status: "installed",
|
|
32
49
|
exitCode: 0,
|
|
33
50
|
agents: allAgents,
|
|
34
|
-
|
|
51
|
+
skills
|
|
35
52
|
};
|
|
36
|
-
if (skippedPaths.length > 0) {
|
|
37
|
-
return { ...result, skipped: skippedPaths };
|
|
38
|
-
}
|
|
39
|
-
return result;
|
|
40
53
|
}
|
|
41
54
|
}
|
|
42
55
|
export function defaultHomedir() {
|
|
@@ -2,7 +2,7 @@ import type { FailureCode } from "../../domain/failure.js";
|
|
|
2
2
|
import type { JourneyStep } from "../../domain/journey.js";
|
|
3
3
|
import type { Bounds } from "../../domain/layout.js";
|
|
4
4
|
import type { AdbPort } from "../../ports/adb.js";
|
|
5
|
-
import type { Point } from "../../
|
|
5
|
+
import type { Point } from "../../domain/geometry.js";
|
|
6
6
|
export interface ActionTarget {
|
|
7
7
|
point: Point;
|
|
8
8
|
bounds?: Bounds | undefined;
|
|
@@ -17,7 +17,8 @@ export type ActionExecutionResult = {
|
|
|
17
17
|
export declare class ActionExecutor {
|
|
18
18
|
private readonly adb;
|
|
19
19
|
private readonly deviceSerial;
|
|
20
|
-
|
|
20
|
+
private readonly beforeMutation?;
|
|
21
|
+
constructor(adb: AdbPort, deviceSerial: string, beforeMutation?: (() => void) | undefined);
|
|
21
22
|
execute(step: JourneyStep, target?: ActionTarget, signal?: AbortSignal): Promise<ActionExecutionResult>;
|
|
22
23
|
swipeBounds(bounds: Bounds, direction: Extract<JourneyStep, {
|
|
23
24
|
action: "swipe";
|
|
@@ -52,9 +52,11 @@ function swipePoints(bounds, direction, distancePercent) {
|
|
|
52
52
|
export class ActionExecutor {
|
|
53
53
|
adb;
|
|
54
54
|
deviceSerial;
|
|
55
|
-
|
|
55
|
+
beforeMutation;
|
|
56
|
+
constructor(adb, deviceSerial, beforeMutation) {
|
|
56
57
|
this.adb = adb;
|
|
57
58
|
this.deviceSerial = deviceSerial;
|
|
59
|
+
this.beforeMutation = beforeMutation;
|
|
58
60
|
}
|
|
59
61
|
async execute(step, target, signal) {
|
|
60
62
|
let result;
|
|
@@ -63,15 +65,18 @@ export class ActionExecutor {
|
|
|
63
65
|
if (target === undefined) {
|
|
64
66
|
return failed("click requires a resolved target");
|
|
65
67
|
}
|
|
68
|
+
this.beforeMutation?.();
|
|
66
69
|
result = await this.adb.tap(target.point, this.deviceSerial, signal);
|
|
67
70
|
break;
|
|
68
71
|
case "longClick":
|
|
69
72
|
if (target === undefined) {
|
|
70
73
|
return failed("longClick requires a resolved target");
|
|
71
74
|
}
|
|
75
|
+
this.beforeMutation?.();
|
|
72
76
|
result = await this.adb.longClick(target.point, step.durationMs, this.deviceSerial, signal);
|
|
73
77
|
break;
|
|
74
78
|
case "inputText":
|
|
79
|
+
this.beforeMutation?.();
|
|
75
80
|
result = await this.adb.inputText(step.text, this.deviceSerial, signal);
|
|
76
81
|
break;
|
|
77
82
|
case "swipe": {
|
|
@@ -82,12 +87,16 @@ export class ActionExecutor {
|
|
|
82
87
|
return failed("swipe requires target bounds from a scrollable element");
|
|
83
88
|
}
|
|
84
89
|
const points = swipePoints(target.bounds, step.direction, step.distancePercent);
|
|
90
|
+
this.beforeMutation?.();
|
|
85
91
|
result = await this.adb.swipe(points.from, points.to, step.durationMs, this.deviceSerial, signal);
|
|
86
92
|
break;
|
|
87
93
|
}
|
|
88
94
|
case "scrollTo":
|
|
89
95
|
return failed("scrollTo is not executed via ActionExecutor");
|
|
96
|
+
case "bridge":
|
|
97
|
+
return failed("bridge is not executed via ActionExecutor");
|
|
90
98
|
case "back":
|
|
99
|
+
this.beforeMutation?.();
|
|
91
100
|
result = await this.adb.back(this.deviceSerial, signal);
|
|
92
101
|
break;
|
|
93
102
|
case "wait":
|
|
@@ -97,6 +106,7 @@ export class ActionExecutor {
|
|
|
97
106
|
}
|
|
98
107
|
async swipeBounds(bounds, direction, distancePercent, durationMs, signal) {
|
|
99
108
|
const points = swipePoints(bounds, direction, distancePercent);
|
|
109
|
+
this.beforeMutation?.();
|
|
100
110
|
const result = await this.adb.swipe(points.from, points.to, durationMs, this.deviceSerial, signal);
|
|
101
111
|
return commandResult(result);
|
|
102
112
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DisplayViewport } from "../../domain/geometry.js";
|
|
2
|
+
import type { LayoutElement, Locator } from "../../domain/layout.js";
|
|
3
|
+
import { type LocatedTarget, type LocatorFailure } from "../locator/locator-resolver.js";
|
|
4
|
+
import type { ActionTarget } from "./action-executor.js";
|
|
5
|
+
export type TargetedAction = "click" | "longClick" | "swipe";
|
|
6
|
+
export type ActionTargetResolution = {
|
|
7
|
+
status: "found";
|
|
8
|
+
target: ActionTarget;
|
|
9
|
+
located: LocatedTarget;
|
|
10
|
+
} | LocatorFailure;
|
|
11
|
+
/**
|
|
12
|
+
* The element an action acts on, with the capability semantics Generation,
|
|
13
|
+
* generated Replay, and External Flow steps share: a click or longClick
|
|
14
|
+
* reaches the nearest ancestor with that capability (touching the matched
|
|
15
|
+
* element itself), and a swipe needs a scrollable element with bounds.
|
|
16
|
+
*/
|
|
17
|
+
export declare function resolveActionTarget(layout: readonly LayoutElement[], action: TargetedAction, locator: Locator, viewport: DisplayViewport | undefined): ActionTargetResolution;
|