taphound 0.2.0-dev.1 → 0.2.0-dev.11
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 +500 -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 +561 -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 +349 -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 +34 -0
- package/dist/adapters/appium/appium-ui-snapshot-provider.js +240 -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/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/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.js +1 -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 +554 -174
- 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/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 +3 -0
- package/dist/application/ui/ui-stability-probe.js +8 -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 +186 -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/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 +273 -63
- package/dist/cli/dependencies.d.ts +125 -1
- package/dist/cli/dependencies.js +450 -51
- package/dist/cli/diff-verification.d.ts +41 -0
- package/dist/cli/diff-verification.js +192 -0
- package/dist/cli/main.js +49 -1
- package/dist/cli/output.d.ts +5 -3
- package/dist/cli/output.js +12 -0
- package/dist/cli/program.js +19 -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/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/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 +28 -0
- package/dist/domain/workspace.js +72 -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/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 +6 -1
- 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,28 @@
|
|
|
1
|
+
import { normalizeActivity } from "../../domain/activity.js";
|
|
2
|
+
import { withRuntimeSession } from "../../ports/runtime-backend.js";
|
|
3
|
+
import { coldLaunchApp } from "../runtime/cold-launch.js";
|
|
4
|
+
export class GenerationAppPreparer {
|
|
5
|
+
dependencies;
|
|
6
|
+
constructor(dependencies) {
|
|
7
|
+
this.dependencies = dependencies;
|
|
8
|
+
}
|
|
9
|
+
prepare(input) {
|
|
10
|
+
return withRuntimeSession(this.dependencies.sessions, input.deviceSerial, input.signal, (session) => this.coldLaunch(this.dependencies.sessionPorts(session).adb, input));
|
|
11
|
+
}
|
|
12
|
+
async coldLaunch(adb, input) {
|
|
13
|
+
const launched = await coldLaunchApp(adb, this.dependencies.clock, {
|
|
14
|
+
packageName: input.config.run.packageName,
|
|
15
|
+
activity: normalizeActivity(input.config.run.packageName, input.config.run.activity),
|
|
16
|
+
deviceSerial: input.deviceSerial,
|
|
17
|
+
pollIntervalMs: input.config.idle.pollIntervalMs,
|
|
18
|
+
timeoutMs: input.config.idle.timeoutMs,
|
|
19
|
+
signal: input.signal
|
|
20
|
+
});
|
|
21
|
+
if (launched.status === "cancelled") {
|
|
22
|
+
throw new Error("App launch was cancelled");
|
|
23
|
+
}
|
|
24
|
+
if (launched.status === "failed") {
|
|
25
|
+
throw new Error(launched.message);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type GenerationSession } from "../../domain/generation.js";
|
|
2
|
+
import { type TapHoundConfig } from "../../domain/config.js";
|
|
3
|
+
import type { GenerationSessionStore } from "../../ports/generation-session-store.js";
|
|
4
|
+
export interface GenerationIdlePolicyPatch {
|
|
5
|
+
strategy?: TapHoundConfig["idle"]["strategy"] | undefined;
|
|
6
|
+
pollIntervalMs?: number | undefined;
|
|
7
|
+
stablePolls?: number | undefined;
|
|
8
|
+
timeoutMs?: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
export interface GenerationConfigServiceDependencies {
|
|
11
|
+
store: Pick<GenerationSessionStore, "read" | "update">;
|
|
12
|
+
}
|
|
13
|
+
export declare class GenerationConfigService {
|
|
14
|
+
private readonly dependencies;
|
|
15
|
+
constructor(dependencies: GenerationConfigServiceDependencies);
|
|
16
|
+
readonly updateIdlePolicy: (input: {
|
|
17
|
+
generationId: string;
|
|
18
|
+
config: TapHoundConfig;
|
|
19
|
+
patch: GenerationIdlePolicyPatch;
|
|
20
|
+
}) => Promise<GenerationSession>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { GenerationSessionSchema } from "../../domain/generation.js";
|
|
2
|
+
import { IdlePolicySchema } from "../../domain/config.js";
|
|
3
|
+
import { GenerationOperationError } from "./generation-starter.js";
|
|
4
|
+
function hasPatch(patch) {
|
|
5
|
+
return patch.strategy !== undefined
|
|
6
|
+
|| patch.pollIntervalMs !== undefined
|
|
7
|
+
|| patch.stablePolls !== undefined
|
|
8
|
+
|| patch.timeoutMs !== undefined;
|
|
9
|
+
}
|
|
10
|
+
function assertUpdatable(session) {
|
|
11
|
+
if (session.state !== "active") {
|
|
12
|
+
throw new GenerationOperationError("CONFIG_INVALID", `Generation idle policy can only be updated on an active session (state: ${session.state})`);
|
|
13
|
+
}
|
|
14
|
+
if (session.inFlight !== null) {
|
|
15
|
+
throw new GenerationOperationError("CONFIG_INVALID", "Generation idle policy cannot change while a step is in flight");
|
|
16
|
+
}
|
|
17
|
+
if (session.pendingConfirmation !== null) {
|
|
18
|
+
throw new GenerationOperationError("CONFIG_INVALID", "Generation idle policy cannot change while a confirmation is pending");
|
|
19
|
+
}
|
|
20
|
+
if (session.verification.status !== "notRun") {
|
|
21
|
+
throw new GenerationOperationError("CONFIG_INVALID", "Generation idle policy cannot change once verification has started");
|
|
22
|
+
}
|
|
23
|
+
if (session.publication.status !== "notRun") {
|
|
24
|
+
throw new GenerationOperationError("CONFIG_INVALID", "Generation idle policy cannot change after publication");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export class GenerationConfigService {
|
|
28
|
+
dependencies;
|
|
29
|
+
constructor(dependencies) {
|
|
30
|
+
this.dependencies = dependencies;
|
|
31
|
+
}
|
|
32
|
+
updateIdlePolicy = async (input) => {
|
|
33
|
+
if (!hasPatch(input.patch)) {
|
|
34
|
+
throw new GenerationOperationError("CONFIG_INVALID", "Generation idle policy update requires at least one setting");
|
|
35
|
+
}
|
|
36
|
+
const session = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
|
|
37
|
+
assertUpdatable(session);
|
|
38
|
+
const base = session.idlePolicy ?? input.config.idle;
|
|
39
|
+
const idlePolicy = IdlePolicySchema.parse({
|
|
40
|
+
strategy: input.patch.strategy ?? base.strategy,
|
|
41
|
+
pollIntervalMs: input.patch.pollIntervalMs ?? base.pollIntervalMs,
|
|
42
|
+
stablePolls: input.patch.stablePolls ?? base.stablePolls,
|
|
43
|
+
timeoutMs: input.patch.timeoutMs ?? base.timeoutMs
|
|
44
|
+
});
|
|
45
|
+
const next = {
|
|
46
|
+
...session,
|
|
47
|
+
revision: session.revision + 1,
|
|
48
|
+
idlePolicy
|
|
49
|
+
};
|
|
50
|
+
await this.dependencies.store.update(input.generationId, session.revision, next);
|
|
51
|
+
return next;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -13,18 +13,22 @@ export interface GenerationConfirmationDependencies {
|
|
|
13
13
|
export interface ConfirmationRequestInput {
|
|
14
14
|
generationId: string;
|
|
15
15
|
proposal: ProposedStep;
|
|
16
|
-
snapshot
|
|
16
|
+
snapshot?: RuntimeSnapshot | undefined;
|
|
17
|
+
snapshotRef?: string | undefined;
|
|
17
18
|
source?: "planner" | "manualOverride" | undefined;
|
|
18
19
|
}
|
|
19
20
|
export interface ConfirmationApproveInput extends ConfirmationRequestInput {
|
|
20
21
|
challengeId: string;
|
|
22
|
+
decision?: ConfirmationDecision | undefined;
|
|
21
23
|
signal?: AbortSignal | undefined;
|
|
22
24
|
}
|
|
23
25
|
export interface StoredConfirmationApproveInput {
|
|
24
26
|
generationId: string;
|
|
25
27
|
challengeId: string;
|
|
28
|
+
decision?: ConfirmationDecision | undefined;
|
|
26
29
|
signal?: AbortSignal | undefined;
|
|
27
30
|
}
|
|
31
|
+
export type ConfirmationDecision = "approve" | "decline";
|
|
28
32
|
export interface ManualConfirmationRequestInput {
|
|
29
33
|
generationId: string;
|
|
30
34
|
snapshot: RuntimeSnapshot;
|
|
@@ -37,18 +41,22 @@ export interface PendingManualConfirmationInput {
|
|
|
37
41
|
}
|
|
38
42
|
export interface ConfirmationRequiredResult {
|
|
39
43
|
status: "confirmationRequired";
|
|
44
|
+
revision: number;
|
|
40
45
|
challenge: PendingConfirmation;
|
|
41
46
|
}
|
|
42
47
|
export type ConfirmationRequestResult = {
|
|
43
48
|
status: "approved";
|
|
44
49
|
proposal: ProposedStep;
|
|
50
|
+
snapshot: RuntimeSnapshot;
|
|
45
51
|
} | ConfirmationRequiredResult;
|
|
46
|
-
export
|
|
52
|
+
export type StoredConfirmationApproveResult = {
|
|
47
53
|
status: "approved";
|
|
48
54
|
proposal: ProposedStep;
|
|
49
55
|
snapshot: RuntimeSnapshot;
|
|
50
56
|
source: "planner" | "manualOverride";
|
|
51
|
-
}
|
|
57
|
+
} | {
|
|
58
|
+
status: "declined";
|
|
59
|
+
};
|
|
52
60
|
export declare function summarizeProposedStep(step: ProposedStep): string;
|
|
53
61
|
export declare function confirmationEvidencePath(challengeId: string): string;
|
|
54
62
|
export declare class GenerationConfirmationService {
|
|
@@ -63,6 +71,8 @@ export declare class GenerationConfirmationService {
|
|
|
63
71
|
readonly confirm: (input: ConfirmationApproveInput) => Promise<{
|
|
64
72
|
status: "approved";
|
|
65
73
|
proposal: ProposedStep;
|
|
74
|
+
} | {
|
|
75
|
+
status: "declined";
|
|
66
76
|
}>;
|
|
67
77
|
readonly clearApproved: (input: {
|
|
68
78
|
generationId: string;
|
|
@@ -73,4 +83,5 @@ export declare class GenerationConfirmationService {
|
|
|
73
83
|
private requireExactPendingChallenge;
|
|
74
84
|
private updateConfirmationReconciled;
|
|
75
85
|
private readStoredEvidence;
|
|
86
|
+
private resolveSnapshot;
|
|
76
87
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { GenerationConfirmationEvidenceSchema, GenerationSessionIdSchema, GenerationSessionSchema, hashGenerationConfirmationEvidence } from "../../domain/generation.js";
|
|
1
|
+
import { GenerationConfirmationEvidenceSchema, GenerationSessionIdSchema, GenerationSessionSchema, hashGenerationConfirmationEvidence, isGenerationConfirmationExpired } from "../../domain/generation.js";
|
|
2
2
|
import { ProposedStepSchema, hashProposedStep } from "../../domain/proposed-step.js";
|
|
3
3
|
import { RuntimeSnapshotSchema, hashRuntimeSnapshot } from "../../domain/runtime-snapshot.js";
|
|
4
4
|
import { GenerationPromptCancelledError } from "../../ports/generation-prompt.js";
|
|
5
|
+
import { parseSnapshotEvidenceReference } from "../../domain/workspace.js";
|
|
5
6
|
import { GenerationOperationError } from "./generation-starter.js";
|
|
6
7
|
import { ProposedStepValidator } from "./proposed-step-validator.js";
|
|
7
8
|
import { RiskEvaluator } from "./risk-evaluator.js";
|
|
@@ -11,6 +12,9 @@ function locatorSummary(step) {
|
|
|
11
12
|
|| step.action === "wait") {
|
|
12
13
|
return "";
|
|
13
14
|
}
|
|
15
|
+
if (step.action === "bridge") {
|
|
16
|
+
return JSON.stringify(step.triggerLocator);
|
|
17
|
+
}
|
|
14
18
|
return JSON.stringify(step.locator);
|
|
15
19
|
}
|
|
16
20
|
export function summarizeProposedStep(step) {
|
|
@@ -27,6 +31,9 @@ export function summarizeProposedStep(step) {
|
|
|
27
31
|
if (step.action === "scrollTo") {
|
|
28
32
|
return `Scroll ${step.direction} in ${JSON.stringify(step.container)} to ${locatorSummary(step)} on ${before}`;
|
|
29
33
|
}
|
|
34
|
+
if (step.action === "bridge") {
|
|
35
|
+
return `Bridge ${step.scenario} via ${locatorSummary(step)} on ${before}`;
|
|
36
|
+
}
|
|
30
37
|
return `${step.action} ${locatorSummary(step)} on ${before}`;
|
|
31
38
|
}
|
|
32
39
|
function bindingFailure(message) {
|
|
@@ -47,15 +54,23 @@ export class GenerationConfirmationService {
|
|
|
47
54
|
}
|
|
48
55
|
}
|
|
49
56
|
request = async (input) => {
|
|
57
|
+
const inputSnapshot = await this.resolveSnapshot(input);
|
|
50
58
|
const session = GenerationSessionSchema.parse(await this.dependencies.store.read(input.generationId));
|
|
51
59
|
const submittedEvidence = GenerationConfirmationEvidenceSchema.parse({
|
|
52
60
|
version: 1,
|
|
53
61
|
proposal: input.proposal,
|
|
54
|
-
snapshot:
|
|
62
|
+
snapshot: inputSnapshot,
|
|
55
63
|
source: input.source ?? "planner"
|
|
56
64
|
});
|
|
57
65
|
if (session.pendingConfirmation !== null
|
|
58
66
|
&& session.pendingConfirmation.status === "pending") {
|
|
67
|
+
if (isGenerationConfirmationExpired(session.pendingConfirmation, this.dependencies.now())) {
|
|
68
|
+
await this.clearExactChallenge(session.id, {
|
|
69
|
+
expectedRevision: session.revision,
|
|
70
|
+
expectedChallenge: session.pendingConfirmation
|
|
71
|
+
});
|
|
72
|
+
throw bindingFailure("Generation confirmation challenge expired and was cleared; observe again before proposing a step");
|
|
73
|
+
}
|
|
59
74
|
const storedEvidence = await this.readStoredEvidence({
|
|
60
75
|
generationId: session.id,
|
|
61
76
|
challengeId: session.pendingConfirmation.challengeId
|
|
@@ -64,19 +79,27 @@ export class GenerationConfirmationService {
|
|
|
64
79
|
throw bindingFailure("Pending generation confirmation does not match submitted evidence");
|
|
65
80
|
}
|
|
66
81
|
const challenge = this.requireExactPendingChallenge(session, storedEvidence);
|
|
67
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
status: "confirmationRequired",
|
|
84
|
+
revision: session.revision,
|
|
85
|
+
challenge
|
|
86
|
+
};
|
|
68
87
|
}
|
|
69
88
|
const proposal = this.validator.validate({
|
|
70
89
|
session,
|
|
71
90
|
snapshot: submittedEvidence.snapshot,
|
|
72
91
|
proposal: submittedEvidence.proposal
|
|
73
92
|
});
|
|
74
|
-
const risk = this.riskEvaluator.evaluate(proposal
|
|
93
|
+
const risk = this.riskEvaluator.evaluate(proposal, session.target.interactionPolicy, submittedEvidence.snapshot);
|
|
75
94
|
if (risk.effectiveRisk === "forbidden") {
|
|
76
95
|
throw new GenerationOperationError("ACTION_FORBIDDEN", `${proposal.action} is forbidden by the Core interaction policy`);
|
|
77
96
|
}
|
|
78
97
|
if (risk.effectiveRisk === "safe") {
|
|
79
|
-
return {
|
|
98
|
+
return {
|
|
99
|
+
status: "approved",
|
|
100
|
+
proposal,
|
|
101
|
+
snapshot: submittedEvidence.snapshot
|
|
102
|
+
};
|
|
80
103
|
}
|
|
81
104
|
if (session.revision === Number.MAX_SAFE_INTEGER) {
|
|
82
105
|
throw bindingFailure("Generation revision cannot create a challenge");
|
|
@@ -94,6 +117,7 @@ export class GenerationConfirmationService {
|
|
|
94
117
|
snapshotHash: proposal.binding.snapshotHash,
|
|
95
118
|
evidenceHash: hashGenerationConfirmationEvidence(evidence),
|
|
96
119
|
actionSummary: summarizeProposedStep(proposal),
|
|
120
|
+
...(risk.reason === undefined ? {} : { reason: risk.reason }),
|
|
97
121
|
expiresAt: new Date(this.dependencies.now().getTime()
|
|
98
122
|
+ this.dependencies.confirmationTtlMs).toISOString(),
|
|
99
123
|
status: "pending"
|
|
@@ -105,7 +129,11 @@ export class GenerationConfirmationService {
|
|
|
105
129
|
});
|
|
106
130
|
await this.dependencies.store.writeEvidence(session.id, confirmationEvidencePath(challenge.challengeId), evidence);
|
|
107
131
|
await this.updateConfirmationReconciled(session.id, session.revision, next);
|
|
108
|
-
return {
|
|
132
|
+
return {
|
|
133
|
+
status: "confirmationRequired",
|
|
134
|
+
revision: next.revision,
|
|
135
|
+
challenge
|
|
136
|
+
};
|
|
109
137
|
};
|
|
110
138
|
requestManual = async (input) => {
|
|
111
139
|
const proposal = await this.dependencies.prompt.buildManualProposal(input.manual, input.signal);
|
|
@@ -125,6 +153,13 @@ export class GenerationConfirmationService {
|
|
|
125
153
|
if (pending === null || pending.status !== "pending") {
|
|
126
154
|
return null;
|
|
127
155
|
}
|
|
156
|
+
if (isGenerationConfirmationExpired(pending, this.dependencies.now())) {
|
|
157
|
+
await this.clearExactChallenge(session.id, {
|
|
158
|
+
expectedRevision: session.revision,
|
|
159
|
+
expectedChallenge: pending
|
|
160
|
+
});
|
|
161
|
+
throw bindingFailure("Generation confirmation challenge expired and was cleared; observe again before manual takeover");
|
|
162
|
+
}
|
|
128
163
|
const evidence = await this.readStoredEvidence({
|
|
129
164
|
generationId: session.id,
|
|
130
165
|
challengeId: pending.challengeId
|
|
@@ -134,18 +169,28 @@ export class GenerationConfirmationService {
|
|
|
134
169
|
throw bindingFailure("Pending manual confirmation does not match the requested action");
|
|
135
170
|
}
|
|
136
171
|
const challenge = this.requireExactPendingChallenge(session, evidence);
|
|
137
|
-
return {
|
|
172
|
+
return {
|
|
173
|
+
status: "confirmationRequired",
|
|
174
|
+
revision: session.revision,
|
|
175
|
+
challenge
|
|
176
|
+
};
|
|
138
177
|
};
|
|
139
178
|
confirmStored = async (input) => {
|
|
140
179
|
const evidence = await this.readStoredEvidence(input);
|
|
141
|
-
await this.confirm({
|
|
180
|
+
const result = await this.confirm({
|
|
142
181
|
generationId: input.generationId,
|
|
143
182
|
challengeId: input.challengeId,
|
|
144
183
|
proposal: evidence.proposal,
|
|
145
184
|
snapshot: evidence.snapshot,
|
|
146
185
|
source: evidence.source,
|
|
186
|
+
...(input.decision === undefined
|
|
187
|
+
? {}
|
|
188
|
+
: { decision: input.decision }),
|
|
147
189
|
signal: input.signal
|
|
148
190
|
});
|
|
191
|
+
if (result.status === "declined") {
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
149
194
|
return {
|
|
150
195
|
status: "approved",
|
|
151
196
|
proposal: evidence.proposal,
|
|
@@ -174,9 +219,14 @@ export class GenerationConfirmationService {
|
|
|
174
219
|
expectedRevision,
|
|
175
220
|
expectedChallenge: challenge
|
|
176
221
|
};
|
|
177
|
-
const expired = this.dependencies.now()
|
|
178
|
-
>= new Date(challenge.expiresAt).getTime();
|
|
222
|
+
const expired = isGenerationConfirmationExpired(challenge, this.dependencies.now());
|
|
179
223
|
const challengeMatches = challenge.challengeId === input.challengeId;
|
|
224
|
+
if (input.decision === "decline") {
|
|
225
|
+
if (!challengeMatches || !await this.clearExactChallenge(session.id, cleanupToken)) {
|
|
226
|
+
throw bindingFailure("Generation confirmation binding is no longer authoritative");
|
|
227
|
+
}
|
|
228
|
+
return { status: "declined" };
|
|
229
|
+
}
|
|
180
230
|
const proposalMatches = challenge.proposalHash
|
|
181
231
|
=== hashProposedStep(proposal);
|
|
182
232
|
const evidenceMatches = challenge.evidenceHash === evidenceHash;
|
|
@@ -227,13 +277,15 @@ export class GenerationConfirmationService {
|
|
|
227
277
|
if (challenge.status === "approved") {
|
|
228
278
|
return { status: "approved", proposal };
|
|
229
279
|
}
|
|
230
|
-
let confirmed;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
280
|
+
let confirmed = input.decision === "approve";
|
|
281
|
+
if (input.decision === undefined) {
|
|
282
|
+
try {
|
|
283
|
+
confirmed = await this.dependencies.prompt.confirm(challenge, input.signal);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
await this.clearExactChallenge(session.id, cleanupToken);
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
237
289
|
}
|
|
238
290
|
if (input.signal?.aborted === true) {
|
|
239
291
|
await this.cancelPrompt(session.id, cleanupToken);
|
|
@@ -249,8 +301,7 @@ export class GenerationConfirmationService {
|
|
|
249
301
|
const stillAuthoritative = latest.revision === session.revision
|
|
250
302
|
&& JSON.stringify(latest.pendingConfirmation)
|
|
251
303
|
=== JSON.stringify(challenge)
|
|
252
|
-
&& this.dependencies.now()
|
|
253
|
-
< new Date(challenge.expiresAt).getTime();
|
|
304
|
+
&& !isGenerationConfirmationExpired(challenge, this.dependencies.now());
|
|
254
305
|
if (!stillAuthoritative) {
|
|
255
306
|
await this.clearExactChallenge(session.id, cleanupToken);
|
|
256
307
|
throw bindingFailure("Generation confirmation state changed while prompting");
|
|
@@ -267,7 +318,10 @@ export class GenerationConfirmationService {
|
|
|
267
318
|
revision: latest.revision + 1,
|
|
268
319
|
pendingConfirmation: {
|
|
269
320
|
...challenge,
|
|
270
|
-
status: "approved"
|
|
321
|
+
status: "approved",
|
|
322
|
+
approvalMode: input.decision === "approve"
|
|
323
|
+
? "delegated"
|
|
324
|
+
: "localTty"
|
|
271
325
|
}
|
|
272
326
|
});
|
|
273
327
|
await this.dependencies.store.updateConfirmation(latest.id, latest.revision, approved);
|
|
@@ -292,7 +346,7 @@ export class GenerationConfirmationService {
|
|
|
292
346
|
if (latest.revision !== token.expectedRevision
|
|
293
347
|
|| pending === null
|
|
294
348
|
|| JSON.stringify(pending) !== JSON.stringify(token.expectedChallenge)) {
|
|
295
|
-
return;
|
|
349
|
+
return false;
|
|
296
350
|
}
|
|
297
351
|
if (latest.revision === Number.MAX_SAFE_INTEGER) {
|
|
298
352
|
throw bindingFailure("Generation revision cannot clear challenge");
|
|
@@ -303,6 +357,7 @@ export class GenerationConfirmationService {
|
|
|
303
357
|
pendingConfirmation: null
|
|
304
358
|
});
|
|
305
359
|
await this.updateConfirmationReconciled(latest.id, latest.revision, cleared);
|
|
360
|
+
return true;
|
|
306
361
|
}
|
|
307
362
|
async cancelPrompt(generationId, token) {
|
|
308
363
|
await this.clearExactChallenge(generationId, token);
|
|
@@ -332,7 +387,7 @@ export class GenerationConfirmationService {
|
|
|
332
387
|
catch {
|
|
333
388
|
throw bindingFailure("Pending generation confirmation is no longer authoritative");
|
|
334
389
|
}
|
|
335
|
-
const risk = this.riskEvaluator.evaluate(proposal
|
|
390
|
+
const risk = this.riskEvaluator.evaluate(proposal, session.target.interactionPolicy, snapshot);
|
|
336
391
|
if (risk.effectiveRisk !== "confirmationRequired"
|
|
337
392
|
|| challenge.stepIndex !== session.candidateSteps.length
|
|
338
393
|
|| challenge.proposalHash !== hashProposedStep(proposal)
|
|
@@ -340,8 +395,7 @@ export class GenerationConfirmationService {
|
|
|
340
395
|
|| challenge.snapshotHash !== proposal.binding.snapshotHash
|
|
341
396
|
|| challenge.evidenceHash !== hashGenerationConfirmationEvidence(evidence)
|
|
342
397
|
|| challenge.actionSummary !== summarizeProposedStep(proposal)
|
|
343
|
-
|| this.dependencies.now()
|
|
344
|
-
>= new Date(challenge.expiresAt).getTime()) {
|
|
398
|
+
|| isGenerationConfirmationExpired(challenge, this.dependencies.now())) {
|
|
345
399
|
throw bindingFailure("Pending generation confirmation does not match stored evidence");
|
|
346
400
|
}
|
|
347
401
|
return challenge;
|
|
@@ -380,4 +434,35 @@ export class GenerationConfirmationService {
|
|
|
380
434
|
: "Generation confirmation evidence is unavailable");
|
|
381
435
|
}
|
|
382
436
|
}
|
|
437
|
+
async resolveSnapshot(input) {
|
|
438
|
+
if ((input.snapshot !== undefined) === (input.snapshotRef !== undefined)) {
|
|
439
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", "Provide exactly one of snapshot or snapshotRef");
|
|
440
|
+
}
|
|
441
|
+
if (input.snapshot !== undefined) {
|
|
442
|
+
return input.snapshot;
|
|
443
|
+
}
|
|
444
|
+
const reference = input.snapshotRef ?? "";
|
|
445
|
+
const evidencePath = parseSnapshotEvidenceReference(reference, input.generationId);
|
|
446
|
+
if (evidencePath === null) {
|
|
447
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", `Snapshot reference is not a valid evidence binding for generation ${input.generationId}: ${reference}`);
|
|
448
|
+
}
|
|
449
|
+
let bytes;
|
|
450
|
+
try {
|
|
451
|
+
bytes = await this.dependencies.store.readEvidence(input.generationId, evidencePath);
|
|
452
|
+
}
|
|
453
|
+
catch (error) {
|
|
454
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", `Referenced snapshot evidence is unavailable: ${reference} (${error instanceof Error ? error.message : "read failed"})`);
|
|
455
|
+
}
|
|
456
|
+
let snapshot;
|
|
457
|
+
try {
|
|
458
|
+
snapshot = RuntimeSnapshotSchema.parse(JSON.parse(bytes.toString("utf8")));
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", `Referenced snapshot evidence is not a valid RuntimeSnapshot: ${reference}`);
|
|
462
|
+
}
|
|
463
|
+
if (snapshot.generationId !== input.generationId) {
|
|
464
|
+
throw new GenerationOperationError("SNAPSHOT_STALE", `Referenced snapshot belongs to another generation: ${reference}`);
|
|
465
|
+
}
|
|
466
|
+
return snapshot;
|
|
467
|
+
}
|
|
383
468
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ResolvedProjectContext } from "../../domain/project-context.js";
|
|
2
|
+
import { type GenerationSessionStore } from "../../ports/generation-session-store.js";
|
|
3
|
+
export interface GenerationContextSnapshotDependencies {
|
|
4
|
+
store: Pick<GenerationSessionStore, "read" | "readEvidence">;
|
|
5
|
+
}
|
|
6
|
+
export declare const readGenerationContextSnapshot: (dependencies: GenerationContextSnapshotDependencies, sessionId: string) => Promise<ResolvedProjectContext>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ResolvedProjectContextSchema } from "../../domain/project-context.js";
|
|
2
|
+
import { GENERATION_CONTEXT_SNAPSHOT_PATH } from "../../domain/workspace.js";
|
|
3
|
+
import { GenerationSessionStoreError } from "../../ports/generation-session-store.js";
|
|
4
|
+
import { GenerationOperationError, hashGenerationBinding } from "./generation-starter.js";
|
|
5
|
+
export const readGenerationContextSnapshot = async (dependencies, sessionId) => {
|
|
6
|
+
let bytes;
|
|
7
|
+
try {
|
|
8
|
+
bytes = await dependencies.store.readEvidence(sessionId, GENERATION_CONTEXT_SNAPSHOT_PATH);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (error instanceof GenerationSessionStoreError
|
|
12
|
+
&& error.code === "EVIDENCE_NOT_FOUND") {
|
|
13
|
+
throw new GenerationOperationError("CONTEXT_INVALID", "Generation session has no stored context snapshot; start a new session");
|
|
14
|
+
}
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
let context;
|
|
18
|
+
try {
|
|
19
|
+
context = ResolvedProjectContextSchema.parse(JSON.parse(bytes.toString("utf8")));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new GenerationOperationError("CONTEXT_INVALID", "Stored context snapshot is unreadable");
|
|
23
|
+
}
|
|
24
|
+
const session = await dependencies.store.read(sessionId);
|
|
25
|
+
if (hashGenerationBinding(context) !== session.bindings.contextHash) {
|
|
26
|
+
throw new GenerationOperationError("CONTEXT_INVALID", "Stored context snapshot does not match the session context binding");
|
|
27
|
+
}
|
|
28
|
+
return context;
|
|
29
|
+
};
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { type GenerationErrorCode, type GenerationMeta } from "../../domain/generation.js";
|
|
2
|
+
import { type GenerationErrorCode, type GenerationMeta, type VerificationPhase } from "../../domain/generation.js";
|
|
3
3
|
import { type Journey } from "../../domain/journey.js";
|
|
4
|
-
import { type
|
|
4
|
+
import { type ResolvedProjectContext } from "../../domain/project-context.js";
|
|
5
5
|
import { type TapHoundConfig } from "../../domain/config.js";
|
|
6
|
-
import type { AdbPort } from "../../ports/adb.js";
|
|
7
6
|
import { type GenerationSessionStore } from "../../ports/generation-session-store.js";
|
|
8
|
-
import type { ContextValidator } from "../context/context-validator.js";
|
|
9
7
|
import type { ProjectDescription } from "../project/project-describer.js";
|
|
10
8
|
import type { VerifyRuntime } from "../runtime/verify-runtime.js";
|
|
11
9
|
import { GenerationPublisher } from "./generation-publisher.js";
|
|
@@ -15,28 +13,34 @@ export declare class GenerationFinalizationError extends Error {
|
|
|
15
13
|
readonly code: GenerationErrorCode;
|
|
16
14
|
readonly stage: GenerationFinalizationStage;
|
|
17
15
|
readonly recoverable: boolean;
|
|
16
|
+
readonly details?: unknown | undefined;
|
|
18
17
|
readonly name = "GenerationFinalizationError";
|
|
19
|
-
constructor(code: GenerationErrorCode, stage: GenerationFinalizationStage, recoverable: boolean, message: string, options?: ErrorOptions);
|
|
18
|
+
constructor(code: GenerationErrorCode, stage: GenerationFinalizationStage, recoverable: boolean, message: string, options?: ErrorOptions, details?: unknown | undefined);
|
|
20
19
|
}
|
|
21
20
|
export interface GenerationFinalizeInput {
|
|
22
21
|
generationId: string;
|
|
23
22
|
projectRoot: string;
|
|
24
23
|
config: TapHoundConfig;
|
|
25
|
-
context:
|
|
24
|
+
context: ResolvedProjectContext;
|
|
26
25
|
project: ProjectDescription;
|
|
27
26
|
outputPath: string;
|
|
28
27
|
name?: string | undefined;
|
|
29
28
|
deviceSerial: string;
|
|
29
|
+
manualReplay?: boolean | undefined;
|
|
30
30
|
toolVersions: Record<string, string>;
|
|
31
31
|
signal?: AbortSignal | undefined;
|
|
32
32
|
}
|
|
33
33
|
export interface GenerationFinalizerDependencies {
|
|
34
|
-
store: Pick<GenerationSessionStore, "read" | "beginVerification" | "completeVerification" | "failVerification" | "markBundlePublishable" | "writeTextEvidence" | "readEvidence">;
|
|
35
|
-
contextValidator: Pick<ContextValidator, "validate">;
|
|
36
|
-
adb: Pick<AdbPort, "forceStop">;
|
|
34
|
+
store: Pick<GenerationSessionStore, "read" | "beginVerification" | "updateVerificationPhase" | "abortVerification" | "completeVerification" | "failVerification" | "markBundlePublishable" | "writeTextEvidence" | "readEvidence">;
|
|
37
35
|
verifyRuntime: Pick<VerifyRuntime, "verify">;
|
|
38
36
|
publisher: GenerationPublisher;
|
|
39
37
|
generateAttemptId: () => string;
|
|
38
|
+
owner?: {
|
|
39
|
+
pid: number;
|
|
40
|
+
now: () => Date;
|
|
41
|
+
} | undefined;
|
|
42
|
+
progress?: ((stage: GenerationFinalizationStage) => void) | undefined;
|
|
43
|
+
replayProgress?: ((phase: VerificationPhase) => void) | undefined;
|
|
40
44
|
}
|
|
41
45
|
export interface GenerationFinalizeResult {
|
|
42
46
|
status: "verified";
|
|
@@ -51,6 +55,7 @@ export declare class GenerationFinalizer {
|
|
|
51
55
|
private readonly dependencies;
|
|
52
56
|
constructor(dependencies: GenerationFinalizerDependencies);
|
|
53
57
|
readonly finalize: (input: GenerationFinalizeInput) => Promise<GenerationFinalizeResult>;
|
|
58
|
+
private bridgeReplayProgress;
|
|
54
59
|
private assertBindings;
|
|
55
60
|
private revalidate;
|
|
56
61
|
private beginVerification;
|
|
@@ -60,6 +65,7 @@ export declare class GenerationFinalizer {
|
|
|
60
65
|
private receiptMatches;
|
|
61
66
|
private persistPassedVerification;
|
|
62
67
|
private reconcilePassedVerification;
|
|
68
|
+
private tryAbortVerification;
|
|
63
69
|
private persistFailedVerification;
|
|
64
70
|
private readVerifiedReport;
|
|
65
71
|
private buildMeta;
|