taphound 0.2.0-dev.1 → 0.2.0-dev.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -149
- package/README.zh-CN.md +47 -147
- package/assets/skills/taphound-case-suite/SKILL.md +363 -0
- package/assets/skills/taphound-case-suite/schemas/base-flow-record.schema.json +22 -0
- package/assets/skills/taphound-case-suite/schemas/case-catalog.schema.json +26 -0
- package/assets/skills/taphound-case-suite/schemas/case-ledger.schema.json +158 -0
- package/assets/skills/taphound-case-suite/schemas/suite-input.schema.json +41 -0
- package/assets/skills/taphound-case-suite/schemas/transition.schema.json +61 -0
- package/assets/skills/taphound-case-suite/scripts/ledger.mjs +1207 -0
- package/assets/skills/taphound-case-suite/templates/base-flow-record.example.json +20 -0
- package/assets/skills/taphound-case-suite/templates/suite-input.example.json +27 -0
- package/assets/skills/taphound-case-suite/templates/transition.example.json +8 -0
- package/assets/skills/taphound-flash/SKILL.md +115 -0
- package/assets/skills/taphound-flash/scripts/flash.mjs +585 -0
- package/assets/skills/taphound-flash/templates/flash-plan.example.json +15 -0
- package/assets/skills/taphound-journey-brief-author/CONTEXT-GUIDE.md +471 -0
- package/assets/skills/taphound-journey-brief-author/SKILL.md +494 -0
- package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.md +96 -0
- package/assets/skills/taphound-journey-brief-author/prompts/brief-author-role.zh-CN.md +80 -0
- package/assets/skills/taphound-journey-brief-author/prompts/context-analyze-project.md +309 -0
- package/assets/skills/taphound-journey-brief-author/schemas/context-refresh-result.json +123 -0
- package/assets/skills/taphound-journey-brief-author/schemas/project-context-module.json +192 -0
- package/assets/skills/taphound-journey-brief-author/schemas/project-context.json +152 -0
- package/assets/skills/taphound-journey-brief-author/templates/project-context-module.example.json +58 -0
- package/assets/skills/taphound-journey-brief-author/templates/project-context.example.json +51 -0
- package/assets/skills/taphound-journey-brief-author/templates/taphound-journey-brief.template.md +63 -0
- package/assets/skills/taphound-journey-generator/SKILL.md +507 -0
- package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/prompts/check-completion.md +3 -0
- package/assets/skills/taphound-journey-generator/prompts/consume-journey-brief.md +52 -0
- package/assets/skills/taphound-journey-generator/prompts/generate-step.md +211 -0
- package/assets/skills/taphound-journey-generator/prompts/select-flow.md +91 -0
- package/assets/skills/taphound-journey-generator/references/bridge.md +35 -0
- package/assets/skills/taphound-journey-generator/references/mid-session.md +44 -0
- package/assets/skills/taphound-journey-generator/schemas/external-flow.json +37 -0
- package/assets/skills/taphound-journey-generator/schemas/flow.json +28 -0
- package/assets/skills/taphound-journey-generator/schemas/journey-source.json +25 -0
- package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/observe-output.json +13 -4
- package/assets/skills/{taphound-ai-journey → taphound-journey-generator}/schemas/proposed-step-envelope.json +127 -5
- package/assets/skills/taphound-journey-generator/scripts/envelope.mjs +578 -0
- package/assets/skills/taphound-journey-generator/templates/external-flow.example.json +22 -0
- package/assets/skills/taphound-journey-generator/templates/flow.example.json +22 -0
- package/assets/skills/taphound-journey-generator/templates/journey-source.example.json +17 -0
- package/assets/skills/taphound-journey-generator/templates/taphound-journey-brief.example.md +70 -0
- package/assets/skills/taphound-verify-change/SKILL.md +91 -0
- package/assets/skills/taphound-verify-change/references/accept.md +38 -0
- package/assets/skills/taphound-verify-change/references/preserve.md +357 -0
- package/assets/skills/taphound-verify-change/schemas/workflow-manifest.schema.json +295 -0
- package/assets/skills/taphound-verify-change/scripts/handoff.mjs +482 -0
- package/assets/skills/taphound-verify-change/scripts/ui-refactor.mjs +505 -0
- package/dist/adapters/adb/adb-adapter.d.ts +16 -2
- package/dist/adapters/adb/adb-adapter.js +199 -0
- package/dist/adapters/adb/system-uiautomator-snapshot-provider.d.ts +13 -0
- package/dist/adapters/adb/system-uiautomator-snapshot-provider.js +122 -0
- package/dist/adapters/adb/ui-automator-parser.d.ts +3 -0
- package/dist/adapters/adb/ui-automator-parser.js +160 -0
- package/dist/adapters/adb/window-topology-parser.d.ts +2 -0
- package/dist/adapters/adb/window-topology-parser.js +101 -0
- package/dist/adapters/android-cli/android-cli-adapter.d.ts +16 -8
- package/dist/adapters/android-cli/android-cli-adapter.js +137 -15
- package/dist/adapters/android-cli/android-cli-snapshot-provider.d.ts +9 -0
- package/dist/adapters/android-cli/android-cli-snapshot-provider.js +99 -0
- package/dist/adapters/android-cli/layout-parser.js +12 -8
- package/dist/adapters/appium/appium-doctor.d.ts +7 -0
- package/dist/adapters/appium/appium-doctor.js +128 -0
- package/dist/adapters/appium/appium-ui-snapshot-provider.d.ts +42 -0
- package/dist/adapters/appium/appium-ui-snapshot-provider.js +309 -0
- package/dist/adapters/camera/camera-probe-adapter.d.ts +18 -0
- package/dist/adapters/camera/camera-probe-adapter.js +286 -0
- package/dist/adapters/filesystem/artifact-store.js +40 -1
- package/dist/adapters/filesystem/context-document-writer.d.ts +15 -0
- package/dist/adapters/filesystem/context-document-writer.js +112 -0
- package/dist/adapters/filesystem/diagnostics-journal.d.ts +17 -0
- package/dist/adapters/filesystem/diagnostics-journal.js +130 -0
- package/dist/adapters/filesystem/external-flow-registry.d.ts +17 -0
- package/dist/adapters/filesystem/external-flow-registry.js +325 -0
- package/dist/adapters/filesystem/generation-session-store.d.ts +17 -11
- package/dist/adapters/filesystem/generation-session-store.js +281 -855
- package/dist/adapters/filesystem/generation-store/session-lock.d.ts +29 -0
- package/dist/adapters/filesystem/generation-store/session-lock.js +202 -0
- package/dist/adapters/filesystem/generation-store/session-transitions.d.ts +24 -0
- package/dist/adapters/filesystem/generation-store/session-transitions.js +340 -0
- package/dist/adapters/filesystem/generation-store/store-files.d.ts +50 -0
- package/dist/adapters/filesystem/generation-store/store-files.js +363 -0
- package/dist/adapters/filesystem/journey-composition-store.d.ts +23 -0
- package/dist/adapters/filesystem/journey-composition-store.js +151 -0
- package/dist/adapters/filesystem/knowledge-registry.d.ts +12 -0
- package/dist/adapters/filesystem/knowledge-registry.js +223 -0
- package/dist/adapters/filesystem/project-bound-file.js +3 -5
- package/dist/adapters/filesystem/project-file-inspector.d.ts +2 -0
- package/dist/adapters/filesystem/project-file-inspector.js +57 -28
- package/dist/adapters/filesystem/project-identity-inspector.d.ts +7 -0
- package/dist/adapters/filesystem/project-identity-inspector.js +215 -0
- package/dist/adapters/filesystem/project-inventory-inspector.d.ts +8 -0
- package/dist/adapters/filesystem/project-inventory-inspector.js +93 -0
- package/dist/adapters/filesystem/project-module-discoverer.d.ts +6 -0
- package/dist/adapters/filesystem/project-module-discoverer.js +158 -0
- package/dist/adapters/filesystem/skill-installer.d.ts +7 -2
- package/dist/adapters/filesystem/skill-installer.js +40 -11
- package/dist/adapters/filesystem/workspace-layout.d.ts +7 -0
- package/dist/adapters/filesystem/workspace-layout.js +57 -0
- package/dist/adapters/git/node-git-diff.d.ts +17 -0
- package/dist/adapters/git/node-git-diff.js +114 -0
- package/dist/adapters/process/node-detached-process-launcher.d.ts +6 -0
- package/dist/adapters/process/node-detached-process-launcher.js +96 -0
- package/dist/adapters/process/node-process-runner.js +11 -2
- package/dist/adapters/prompt/inquirer-align-prompt.d.ts +27 -0
- package/dist/adapters/prompt/inquirer-align-prompt.js +65 -0
- package/dist/adapters/prompt/inquirer-generation-prompt.js +3 -0
- package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +9 -1
- package/dist/adapters/prompt/inquirer-recorder-prompt.js +63 -0
- package/dist/adapters/runtime/adb-runtime-backend.d.ts +67 -0
- package/dist/adapters/runtime/adb-runtime-backend.js +206 -0
- package/dist/adapters/runtime/fake-runtime-backend.d.ts +87 -0
- package/dist/adapters/runtime/fake-runtime-backend.js +240 -0
- package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.d.ts +45 -0
- package/dist/adapters/runtime/mobile-mcp/mcp-tool-client.js +153 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.d.ts +23 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-errors.js +39 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.d.ts +20 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-responses.js +180 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.d.ts +78 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-runtime-backend.js +379 -0
- package/dist/adapters/runtime/mobile-mcp/mobile-mcp-tools.d.ts +46 -0
- package/dist/adapters/runtime/session-adb-view.d.ts +53 -0
- package/dist/adapters/runtime/session-adb-view.js +193 -0
- package/dist/adapters/runtime/session-backed-ports.d.ts +21 -0
- package/dist/adapters/runtime/session-backed-ports.js +43 -0
- package/dist/adapters/runtime/shared-session-runtime-backend.d.ts +12 -0
- package/dist/adapters/runtime/shared-session-runtime-backend.js +64 -0
- package/dist/adapters/ui/auto-ui-snapshot-provider.d.ts +8 -0
- package/dist/adapters/ui/auto-ui-snapshot-provider.js +48 -0
- package/dist/adapters/ui/device-layout-temp.d.ts +6 -0
- package/dist/adapters/ui/device-layout-temp.js +18 -0
- package/dist/adapters/ui/device-ui-environment.d.ts +13 -0
- package/dist/adapters/ui/device-ui-environment.js +81 -0
- package/dist/adapters/ui/layout-normalization.d.ts +9 -0
- package/dist/adapters/ui/layout-normalization.js +44 -0
- package/dist/adapters/ui/ui-snapshot-error.d.ts +11 -0
- package/dist/adapters/ui/ui-snapshot-error.js +12 -0
- package/dist/adapters/ui/ui-snapshot-support.d.ts +15 -0
- package/dist/adapters/ui/ui-snapshot-support.js +12 -0
- package/dist/application/align/align-service.d.ts +42 -0
- package/dist/application/align/align-service.js +106 -0
- package/dist/application/assertion/expectation-evaluator.d.ts +18 -5
- package/dist/application/assertion/expectation-evaluator.js +156 -18
- package/dist/application/assertion/guarded-expectation.d.ts +45 -0
- package/dist/application/assertion/guarded-expectation.js +74 -0
- package/dist/application/checkpoint/baseline-capturer.d.ts +26 -0
- package/dist/application/checkpoint/baseline-capturer.js +163 -0
- package/dist/application/checkpoint/baseline-error.d.ts +5 -0
- package/dist/application/checkpoint/baseline-error.js +8 -0
- package/dist/application/checkpoint/baseline-service.d.ts +31 -0
- package/dist/application/checkpoint/baseline-service.js +147 -0
- package/dist/application/checkpoint/checkpoint-evaluator.d.ts +35 -0
- package/dist/application/checkpoint/checkpoint-evaluator.js +415 -0
- package/dist/application/checkpoint/regression-comparator.d.ts +18 -0
- package/dist/application/checkpoint/regression-comparator.js +192 -0
- package/dist/application/collector/logcat-collector.d.ts +22 -1
- package/dist/application/collector/logcat-collector.js +103 -15
- package/dist/application/collector/logcat-event.d.ts +8 -0
- package/dist/application/collector/logcat-event.js +79 -0
- package/dist/application/collector/logcat-stop.d.ts +2 -0
- package/dist/application/collector/logcat-stop.js +11 -0
- package/dist/application/context/context-generator.d.ts +45 -0
- package/dist/application/context/context-generator.js +228 -0
- package/dist/application/context/context-loader.d.ts +40 -0
- package/dist/application/context/context-loader.js +223 -0
- package/dist/application/context/context-refresher.d.ts +59 -0
- package/dist/application/context/context-refresher.js +349 -0
- package/dist/application/context/context-rehasher.d.ts +36 -0
- package/dist/application/context/context-rehasher.js +110 -0
- package/dist/application/context/context-validator.d.ts +23 -1
- package/dist/application/context/context-validator.js +116 -9
- package/dist/application/context/evidence-hash.d.ts +1 -0
- package/dist/application/context/evidence-hash.js +125 -0
- package/dist/application/context/evidence-match.d.ts +9 -0
- package/dist/application/context/evidence-match.js +8 -0
- package/dist/application/context/shard-identity.d.ts +2 -0
- package/dist/application/context/shard-identity.js +7 -0
- package/dist/application/contract/contract-loader.d.ts +25 -0
- package/dist/application/contract/contract-loader.js +68 -0
- package/dist/application/contract/contract-review.d.ts +25 -0
- package/dist/application/contract/contract-review.js +51 -0
- package/dist/application/contract/contract-verifier.d.ts +53 -0
- package/dist/application/contract/contract-verifier.js +645 -0
- package/dist/application/devices/resolve-device-assignments.d.ts +21 -0
- package/dist/application/devices/resolve-device-assignments.js +60 -0
- package/dist/application/diagnosis/failure-classifier.d.ts +23 -0
- package/dist/application/diagnosis/failure-classifier.js +179 -0
- package/dist/application/diagnostics/diagnostics-exporter.d.ts +29 -0
- package/dist/application/diagnostics/diagnostics-exporter.js +283 -0
- package/dist/application/diagnostics/ui-capture-telemetry.d.ts +16 -0
- package/dist/application/diagnostics/ui-capture-telemetry.js +81 -0
- package/dist/application/doctor/doctor-service.d.ts +36 -3
- package/dist/application/doctor/doctor-service.js +255 -25
- package/dist/application/generation/generation-app-preparer.d.ts +20 -0
- package/dist/application/generation/generation-app-preparer.js +28 -0
- package/dist/application/generation/generation-config-service.d.ts +21 -0
- package/dist/application/generation/generation-config-service.js +53 -0
- package/dist/application/generation/generation-confirmation-service.d.ts +14 -3
- package/dist/application/generation/generation-confirmation-service.js +109 -24
- package/dist/application/generation/generation-context-snapshot.d.ts +6 -0
- package/dist/application/generation/generation-context-snapshot.js +29 -0
- package/dist/application/generation/generation-finalizer.d.ts +15 -9
- package/dist/application/generation/generation-finalizer.js +167 -70
- package/dist/application/generation/generation-publisher.js +12 -8
- package/dist/application/generation/generation-recovery-service.d.ts +35 -0
- package/dist/application/generation/generation-recovery-service.js +144 -0
- package/dist/application/generation/generation-reopen-service.d.ts +15 -0
- package/dist/application/generation/generation-reopen-service.js +37 -0
- package/dist/application/generation/generation-replace-service.d.ts +32 -0
- package/dist/application/generation/generation-replace-service.js +116 -0
- package/dist/application/generation/generation-starter.d.ts +44 -4
- package/dist/application/generation/generation-starter.js +175 -8
- package/dist/application/generation/generation-step-executor.d.ts +67 -5
- package/dist/application/generation/generation-step-executor.js +471 -108
- package/dist/application/generation/proposed-step-validator.js +96 -30
- package/dist/application/generation/replay-policy-loader.d.ts +16 -0
- package/dist/application/generation/replay-policy-loader.js +29 -0
- package/dist/application/generation/risk-evaluator.d.ts +4 -1
- package/dist/application/generation/risk-evaluator.js +118 -3
- package/dist/application/generation/runtime-observer.d.ts +39 -7
- package/dist/application/generation/runtime-observer.js +193 -24
- package/dist/application/impact/impact-resolver.d.ts +32 -0
- package/dist/application/impact/impact-resolver.js +160 -0
- package/dist/application/init/init-service.js +26 -13
- package/dist/application/interaction/action-executor.d.ts +3 -2
- package/dist/application/interaction/action-executor.js +11 -1
- package/dist/application/interaction/action-target.d.ts +17 -0
- package/dist/application/interaction/action-target.js +40 -0
- package/dist/application/interaction/external-step-runner.d.ts +153 -0
- package/dist/application/interaction/external-step-runner.js +332 -0
- package/dist/application/interaction/fallback-resolver.d.ts +6 -3
- package/dist/application/interaction/fallback-resolver.js +7 -5
- package/dist/application/interaction/scroll-to-executor.d.ts +17 -3
- package/dist/application/interaction/scroll-to-executor.js +118 -36
- package/dist/application/journey/external-flow-resolver.d.ts +25 -0
- package/dist/application/journey/external-flow-resolver.js +22 -0
- package/dist/application/journey/journey-check-service.d.ts +54 -0
- package/dist/application/journey/journey-check-service.js +207 -0
- package/dist/application/journey/journey-promoter.d.ts +26 -0
- package/dist/application/journey/journey-promoter.js +123 -0
- package/dist/application/journey/journey-resolver.d.ts +42 -0
- package/dist/application/journey/journey-resolver.js +239 -0
- package/dist/application/journey/journey-retirer.d.ts +25 -0
- package/dist/application/journey/journey-retirer.js +87 -0
- package/dist/application/knowledge/anchor-resolver.d.ts +36 -0
- package/dist/application/knowledge/anchor-resolver.js +110 -0
- package/dist/application/knowledge/knowledge-loader.d.ts +16 -0
- package/dist/application/knowledge/knowledge-loader.js +36 -0
- package/dist/application/locator/layout-failure-summary.d.ts +2 -0
- package/dist/application/locator/layout-failure-summary.js +67 -0
- package/dist/application/locator/layout-traversal.d.ts +11 -0
- package/dist/application/locator/layout-traversal.js +18 -0
- package/dist/application/locator/locator-resolver.d.ts +13 -1
- package/dist/application/locator/locator-resolver.js +182 -18
- package/dist/application/observe/observe-service.d.ts +20 -0
- package/dist/application/observe/observe-service.js +91 -0
- package/dist/application/project/project-describer.d.ts +14 -6
- package/dist/application/project/project-describer.js +38 -5
- package/dist/application/recognition/screen-detector.d.ts +28 -0
- package/dist/application/recognition/screen-detector.js +111 -0
- package/dist/application/recorder/locator-selector.js +151 -17
- package/dist/application/recorder/recorder-service.d.ts +16 -4
- package/dist/application/recorder/recorder-service.js +420 -128
- package/dist/application/report/report-writer.d.ts +5 -0
- package/dist/application/report/report-writer.js +17 -1
- package/dist/application/runtime/cold-launch.d.ts +28 -0
- package/dist/application/runtime/cold-launch.js +59 -0
- package/dist/application/runtime/step-runner.d.ts +49 -4
- package/dist/application/runtime/step-runner.js +721 -130
- package/dist/application/runtime/verify-runtime.d.ts +57 -7
- package/dist/application/runtime/verify-runtime.js +577 -175
- package/dist/application/ui/cached-ui-snapshot-provider.d.ts +45 -0
- package/dist/application/ui/cached-ui-snapshot-provider.js +111 -0
- package/dist/application/ui/observed-ui-snapshot-provider.d.ts +15 -0
- package/dist/application/ui/observed-ui-snapshot-provider.js +66 -0
- package/dist/application/ui/ui-snapshot-lifecycle.d.ts +2 -0
- package/dist/application/ui/ui-snapshot-lifecycle.js +8 -0
- package/dist/application/ui/ui-stability-probe.d.ts +9 -0
- package/dist/application/ui/ui-stability-probe.js +24 -0
- package/dist/application/wait/idle-advice.d.ts +6 -0
- package/dist/application/wait/idle-advice.js +27 -0
- package/dist/application/wait/idle-profiles.d.ts +15 -0
- package/dist/application/wait/idle-profiles.js +75 -0
- package/dist/application/wait/idle-waiter.d.ts +28 -4
- package/dist/application/wait/idle-waiter.js +201 -15
- package/dist/cli/commands/align.d.ts +3 -0
- package/dist/cli/commands/align.js +124 -0
- package/dist/cli/commands/baseline.d.ts +3 -0
- package/dist/cli/commands/baseline.js +130 -0
- package/dist/cli/commands/context.js +300 -27
- package/dist/cli/commands/contract.d.ts +3 -0
- package/dist/cli/commands/contract.js +120 -0
- package/dist/cli/commands/diagnose.d.ts +3 -0
- package/dist/cli/commands/diagnose.js +84 -0
- package/dist/cli/commands/doctor.js +16 -9
- package/dist/cli/commands/failure.d.ts +3 -0
- package/dist/cli/commands/failure.js +63 -0
- package/dist/cli/commands/generation/lifecycle-commands.d.ts +5 -0
- package/dist/cli/commands/generation/lifecycle-commands.js +211 -0
- package/dist/cli/commands/generation/session-commands.d.ts +11 -0
- package/dist/cli/commands/generation/session-commands.js +472 -0
- package/dist/cli/commands/generation/shared.d.ts +1414 -0
- package/dist/cli/commands/generation/shared.js +291 -0
- package/dist/cli/commands/generation/step-commands.d.ts +8 -0
- package/dist/cli/commands/generation/step-commands.js +315 -0
- package/dist/cli/commands/generation.js +10 -507
- package/dist/cli/commands/impact.d.ts +3 -0
- package/dist/cli/commands/impact.js +87 -0
- package/dist/cli/commands/init.js +13 -6
- package/dist/cli/commands/journey.d.ts +3 -0
- package/dist/cli/commands/journey.js +382 -0
- package/dist/cli/commands/knowledge.d.ts +3 -0
- package/dist/cli/commands/knowledge.js +93 -0
- package/dist/cli/commands/observe.d.ts +3 -0
- package/dist/cli/commands/observe.js +127 -0
- package/dist/cli/commands/project.js +2 -1
- package/dist/cli/commands/record.js +18 -5
- package/dist/cli/commands/verify.js +326 -64
- package/dist/cli/dependencies.d.ts +136 -1
- package/dist/cli/dependencies.js +504 -52
- package/dist/cli/diagnostics-recorder.d.ts +31 -0
- package/dist/cli/diagnostics-recorder.js +82 -0
- package/dist/cli/diff-verification.d.ts +41 -0
- package/dist/cli/diff-verification.js +192 -0
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.js +107 -2
- package/dist/cli/output.d.ts +5 -3
- package/dist/cli/output.js +12 -0
- package/dist/cli/program.js +21 -1
- package/dist/cli/project-root.d.ts +1 -0
- package/dist/cli/project-root.js +6 -0
- package/dist/cli/runtime-selection.d.ts +22 -0
- package/dist/cli/runtime-selection.js +92 -0
- package/dist/cli/version.d.ts +1 -0
- package/dist/cli/version.js +14 -0
- package/dist/cli/workspace-guard.d.ts +2 -0
- package/dist/cli/workspace-guard.js +3 -0
- package/dist/domain/binding-reference.d.ts +4 -0
- package/dist/domain/binding-reference.js +23 -0
- package/dist/domain/checkpoint.d.ts +404 -0
- package/dist/domain/checkpoint.js +297 -0
- package/dist/domain/config.d.ts +107 -1
- package/dist/domain/config.js +52 -6
- package/dist/domain/contract.d.ts +413 -0
- package/dist/domain/contract.js +196 -0
- package/dist/domain/diagnostics.d.ts +1396 -0
- package/dist/domain/diagnostics.js +193 -0
- package/dist/domain/external-flow.d.ts +493 -0
- package/dist/domain/external-flow.js +15 -0
- package/dist/domain/failure-classification.d.ts +176 -0
- package/dist/domain/failure-classification.js +169 -0
- package/dist/domain/failure.d.ts +2 -1
- package/dist/domain/failure.js +123 -0
- package/dist/domain/generation.d.ts +1671 -132
- package/dist/domain/generation.js +202 -13
- package/dist/domain/geometry.d.ts +13 -0
- package/dist/domain/geometry.js +16 -0
- package/dist/domain/impact.d.ts +71 -0
- package/dist/domain/impact.js +76 -0
- package/dist/domain/init.d.ts +12 -4
- package/dist/domain/init.js +24 -18
- package/dist/domain/journey-composition.d.ts +2285 -0
- package/dist/domain/journey-composition.js +85 -0
- package/dist/domain/journey-lifecycle.d.ts +10 -0
- package/dist/domain/journey-lifecycle.js +9 -0
- package/dist/domain/journey.d.ts +2419 -212
- package/dist/domain/journey.js +384 -14
- package/dist/domain/knowledge.d.ts +165 -0
- package/dist/domain/knowledge.js +188 -0
- package/dist/domain/layout.d.ts +34 -5
- package/dist/domain/layout.js +64 -6
- package/dist/domain/locator-evidence.d.ts +3 -0
- package/dist/domain/locator-evidence.js +36 -0
- package/dist/domain/logcat-event.d.ts +54 -0
- package/dist/domain/logcat-event.js +40 -0
- package/dist/domain/observation.d.ts +33 -0
- package/dist/domain/observation.js +18 -0
- package/dist/domain/project-context.d.ts +219 -1
- package/dist/domain/project-context.js +209 -6
- package/dist/domain/proposed-step.d.ts +340 -60
- package/dist/domain/proposed-step.js +23 -3
- package/dist/domain/report.d.ts +1455 -28
- package/dist/domain/report.js +211 -14
- package/dist/domain/runtime-snapshot.d.ts +58 -1
- package/dist/domain/runtime-snapshot.js +14 -3
- package/dist/domain/runtime.d.ts +50 -0
- package/dist/domain/runtime.js +36 -0
- package/dist/domain/system-app-profiles.d.ts +6 -0
- package/dist/domain/system-app-profiles.js +43 -0
- package/dist/domain/ui-backend.d.ts +28 -0
- package/dist/domain/ui-backend.js +33 -0
- package/dist/domain/ui-cache.d.ts +11 -0
- package/dist/domain/ui-cache.js +10 -0
- package/dist/domain/verify-receipt.d.ts +17 -0
- package/dist/domain/verify-receipt.js +17 -0
- package/dist/domain/window-hierarchy.d.ts +84 -0
- package/dist/domain/window-hierarchy.js +172 -0
- package/dist/domain/workflow-manifest.d.ts +77 -0
- package/dist/domain/workflow-manifest.js +136 -0
- package/dist/domain/workspace.d.ts +30 -0
- package/dist/domain/workspace.js +74 -0
- package/dist/ports/adb.d.ts +34 -1
- package/dist/ports/align-prompt.d.ts +11 -0
- package/dist/ports/align-prompt.js +6 -0
- package/dist/ports/anchor-resolver.d.ts +30 -0
- package/dist/ports/anchor-resolver.js +1 -0
- package/dist/ports/annotated-screen-resolver.d.ts +4 -0
- package/dist/ports/annotated-screen-resolver.js +1 -0
- package/dist/ports/camera-probe.d.ts +23 -0
- package/dist/ports/camera-probe.js +8 -0
- package/dist/ports/context-document-writer.d.ts +24 -0
- package/dist/ports/context-document-writer.js +1 -0
- package/dist/ports/detached-process-launcher.d.ts +12 -0
- package/dist/ports/detached-process-launcher.js +1 -0
- package/dist/ports/diagnostics.d.ts +15 -0
- package/dist/ports/diagnostics.js +1 -0
- package/dist/ports/external-flow-registry.d.ts +37 -0
- package/dist/ports/external-flow-registry.js +1 -0
- package/dist/ports/generation-prompt.d.ts +2 -1
- package/dist/ports/generation-session-store.d.ts +12 -2
- package/dist/ports/git-diff.d.ts +9 -0
- package/dist/ports/git-diff.js +1 -0
- package/dist/ports/journey-composition-store.d.ts +17 -0
- package/dist/ports/journey-composition-store.js +1 -0
- package/dist/ports/knowledge-registry.d.ts +20 -0
- package/dist/ports/knowledge-registry.js +1 -0
- package/dist/ports/process-runner.d.ts +7 -0
- package/dist/ports/project-file-inspector.d.ts +1 -0
- package/dist/ports/project-identity-inspector.d.ts +24 -0
- package/dist/ports/project-identity-inspector.js +1 -0
- package/dist/ports/project-inventory-inspector.d.ts +21 -0
- package/dist/ports/project-inventory-inspector.js +1 -0
- package/dist/ports/project-module-discoverer.d.ts +26 -0
- package/dist/ports/project-module-discoverer.js +1 -0
- package/dist/ports/recorder-prompt.d.ts +10 -1
- package/dist/ports/runtime-backend.d.ts +89 -0
- package/dist/ports/runtime-backend.js +13 -0
- package/dist/ports/runtime-capability.d.ts +12 -0
- package/dist/ports/runtime-capability.js +20 -0
- package/dist/ports/runtime-session-ports.d.ts +25 -0
- package/dist/ports/runtime-session-ports.js +1 -0
- package/dist/ports/screenshot.d.ts +11 -0
- package/dist/ports/screenshot.js +1 -0
- package/dist/ports/skill-installer.d.ts +2 -2
- package/dist/ports/ui-snapshot.d.ts +35 -0
- package/dist/ports/ui-snapshot.js +1 -0
- package/dist/ports/ui-stability.d.ts +19 -0
- package/dist/ports/ui-stability.js +1 -0
- package/dist/ports/workspace-layout.d.ts +4 -0
- package/dist/ports/workspace-layout.js +1 -0
- package/dist/shared/errors.d.ts +2 -0
- package/dist/shared/errors.js +22 -0
- package/dist/shared/paths.d.ts +2 -0
- package/dist/shared/paths.js +24 -0
- package/dist/shared/strings.d.ts +2 -0
- package/dist/shared/strings.js +16 -0
- package/package.json +7 -2
- package/assets/skills/taphound-ai-journey/GUIDE.md +0 -862
- package/assets/skills/taphound-ai-journey/SKILL.md +0 -377
- package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +0 -526
- package/assets/skills/taphound-ai-journey/prompts/generate-step.md +0 -109
- package/assets/skills/taphound-ai-journey/schemas/project-context.json +0 -81
- package/assets/skills/taphound-ai-journey/templates/project-context.example.json +0 -49
- package/dist/ports/android-cli.d.ts +0 -21
- /package/dist/{ports/android-cli.js → adapters/runtime/mobile-mcp/mobile-mcp-tools.js} +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { ProjectContextModuleSchema, ProjectContextSchema } from "../../domain/project-context.js";
|
|
2
|
+
import { projectRelativePath } from "../../shared/paths.js";
|
|
3
|
+
import { MAX_CONTEXT_SHARD_BYTES } from "./context-loader.js";
|
|
4
|
+
import { assertShardIdentity } from "./shard-identity.js";
|
|
5
|
+
import { assertProjectPathUnder, CONTEXT_DIR } from "../../domain/workspace.js";
|
|
6
|
+
export class ContextRehashError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
name = "ContextRehashError";
|
|
9
|
+
constructor(code, message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.code = code;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class ContextRehasher {
|
|
15
|
+
dependencies;
|
|
16
|
+
constructor(dependencies) {
|
|
17
|
+
this.dependencies = dependencies;
|
|
18
|
+
}
|
|
19
|
+
rehash = async (input) => {
|
|
20
|
+
const contextRelativePath = projectRelativePath(input.projectRoot, input.contextPath, (message) => new ContextRehashError("CONTEXT_INVALID", message));
|
|
21
|
+
try {
|
|
22
|
+
assertProjectPathUnder(input.projectRoot, contextRelativePath, CONTEXT_DIR, "Project Context output");
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
throw new ContextRehashError("CONTEXT_INVALID", error instanceof Error ? error.message : String(error));
|
|
26
|
+
}
|
|
27
|
+
const { bundle, indexHash } = await this.dependencies.loader.readIndex({
|
|
28
|
+
projectRoot: input.projectRoot,
|
|
29
|
+
contextPath: input.contextPath
|
|
30
|
+
});
|
|
31
|
+
const requestedIds = input.moduleIds === undefined || input.moduleIds.length === 0
|
|
32
|
+
? undefined
|
|
33
|
+
: new Set(input.moduleIds);
|
|
34
|
+
const moduleResults = [];
|
|
35
|
+
let anyChanged = false;
|
|
36
|
+
for (const reference of bundle.modules) {
|
|
37
|
+
if (requestedIds !== undefined && !requestedIds.has(reference.id)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const inspection = await this.dependencies.files.inspectProjectFile({
|
|
41
|
+
projectRoot: input.projectRoot,
|
|
42
|
+
relativePath: reference.contextPath,
|
|
43
|
+
maximumBytes: MAX_CONTEXT_SHARD_BYTES
|
|
44
|
+
});
|
|
45
|
+
if (inspection.status !== "inspected") {
|
|
46
|
+
throw new ContextRehashError("CONTEXT_INVALID", `Context shard cannot be read: ${reference.contextPath}`);
|
|
47
|
+
}
|
|
48
|
+
let parsedJson;
|
|
49
|
+
try {
|
|
50
|
+
parsedJson = JSON.parse(inspection.bytes?.toString("utf8") ?? "");
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
throw new ContextRehashError("CONTEXT_INVALID", `Context shard is not valid JSON: ${reference.contextPath}`);
|
|
54
|
+
}
|
|
55
|
+
const document = ProjectContextModuleSchema.safeParse(parsedJson);
|
|
56
|
+
if (!document.success) {
|
|
57
|
+
throw new ContextRehashError("CONTEXT_INVALID", `Context shard does not match the module schema: ${reference.contextPath}`);
|
|
58
|
+
}
|
|
59
|
+
assertShardIdentity(reference, document.data, (message) => new ContextRehashError("CONTEXT_INVALID", message));
|
|
60
|
+
const changed = inspection.sha256 !== reference.sha256;
|
|
61
|
+
if (changed) {
|
|
62
|
+
anyChanged = true;
|
|
63
|
+
}
|
|
64
|
+
moduleResults.push({
|
|
65
|
+
id: reference.id,
|
|
66
|
+
previousSha256: reference.sha256,
|
|
67
|
+
currentSha256: inspection.sha256,
|
|
68
|
+
changed
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
if (!anyChanged) {
|
|
72
|
+
return {
|
|
73
|
+
status: "unchanged",
|
|
74
|
+
modules: moduleResults,
|
|
75
|
+
previousIndexHash: indexHash,
|
|
76
|
+
indexHash
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const nextModules = bundle.modules.map((reference) => {
|
|
80
|
+
const result = moduleResults.find((r) => r.id === reference.id);
|
|
81
|
+
return result !== undefined && result.changed
|
|
82
|
+
? { ...reference, sha256: result.currentSha256 }
|
|
83
|
+
: reference;
|
|
84
|
+
});
|
|
85
|
+
const nextBundle = {
|
|
86
|
+
...bundle,
|
|
87
|
+
modules: nextModules
|
|
88
|
+
};
|
|
89
|
+
const parsedBundle = ProjectContextSchema.safeParse(nextBundle);
|
|
90
|
+
if (!parsedBundle.success) {
|
|
91
|
+
throw new ContextRehashError("CONTEXT_INVALID", "Rehashed Project Context index does not match the version 2 schema");
|
|
92
|
+
}
|
|
93
|
+
const written = await this.dependencies.writer.writeContextDocument({
|
|
94
|
+
projectRoot: input.projectRoot,
|
|
95
|
+
relativePath: contextRelativePath,
|
|
96
|
+
document: parsedBundle.data
|
|
97
|
+
});
|
|
98
|
+
if (written.status !== "written") {
|
|
99
|
+
throw new ContextRehashError("CONTEXT_WRITE_FAILED", written.status === "escape"
|
|
100
|
+
? `Context document resolves outside the project: ${contextRelativePath}`
|
|
101
|
+
: `Context document cannot be written: ${contextRelativePath}${"message" in written ? `: ${written.message}` : ""}`);
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
status: "rehashed",
|
|
105
|
+
modules: moduleResults,
|
|
106
|
+
previousIndexHash: indexHash,
|
|
107
|
+
indexHash: written.sha256
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -1,27 +1,49 @@
|
|
|
1
1
|
import type { TapHoundConfig } from "../../domain/config.js";
|
|
2
|
+
import { type ProjectContextModule } from "../../domain/project-context.js";
|
|
2
3
|
import { type ProjectFileInspector } from "../../ports/project-file-inspector.js";
|
|
4
|
+
import type { ProjectInventoryInspector } from "../../ports/project-inventory-inspector.js";
|
|
3
5
|
export declare const MAX_CONTEXT_EVIDENCE_BYTES: number;
|
|
4
6
|
export type ContextValidationReasonCode = "CONTEXT_SCHEMA_INVALID" | "CONTEXT_IDENTITY_MISMATCH" | "PROJECT_ROOT_UNREADABLE" | "PROJECT_ROOT_NOT_DIRECTORY" | "EVIDENCE_SECRET_PATH" | "EVIDENCE_NOT_FOUND" | "EVIDENCE_UNREADABLE" | "EVIDENCE_NOT_FILE" | "EVIDENCE_PATH_ESCAPE" | "EVIDENCE_CHANGED_IDENTITY" | "EVIDENCE_TOO_LARGE" | "EVIDENCE_HASH_MISMATCH";
|
|
5
7
|
export interface ContextValidationReason {
|
|
6
8
|
code: ContextValidationReasonCode;
|
|
7
9
|
message: string;
|
|
8
10
|
}
|
|
11
|
+
export interface ContextValidationScope {
|
|
12
|
+
id: string;
|
|
13
|
+
inventoryChanged: boolean;
|
|
14
|
+
missingPaths: string[];
|
|
15
|
+
changedPaths: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface ContextIdentityDivergence {
|
|
18
|
+
evidencePackageName: string;
|
|
19
|
+
configuredPackageName: string;
|
|
20
|
+
launchActivity: string;
|
|
21
|
+
}
|
|
9
22
|
export type ContextValidationResult = {
|
|
10
23
|
status: "valid";
|
|
24
|
+
scopes?: ContextValidationScope[] | undefined;
|
|
25
|
+
divergence?: ContextIdentityDivergence | undefined;
|
|
11
26
|
} | {
|
|
12
27
|
status: "stale";
|
|
13
28
|
reason: ContextValidationReason;
|
|
29
|
+
scopes?: ContextValidationScope[];
|
|
14
30
|
} | {
|
|
15
31
|
status: "invalid";
|
|
16
32
|
reason: ContextValidationReason;
|
|
33
|
+
scopes?: ContextValidationScope[];
|
|
17
34
|
};
|
|
18
35
|
export interface ContextValidationInput {
|
|
19
36
|
context: unknown;
|
|
20
37
|
projectRoot: string;
|
|
21
38
|
config: TapHoundConfig;
|
|
39
|
+
modules?: ProjectContextModule[] | undefined;
|
|
40
|
+
reportScopes?: boolean | undefined;
|
|
41
|
+
identityPolicy?: "strict" | "configured" | undefined;
|
|
22
42
|
}
|
|
23
43
|
export declare class ContextValidator {
|
|
24
44
|
private readonly files;
|
|
25
|
-
|
|
45
|
+
private readonly inventory?;
|
|
46
|
+
constructor(files: ProjectFileInspector, inventory?: ProjectInventoryInspector | undefined);
|
|
26
47
|
readonly validate: (input: ContextValidationInput) => Promise<ContextValidationResult>;
|
|
48
|
+
private readonly inspectScopes;
|
|
27
49
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { normalizeActivity } from "../../domain/activity.js";
|
|
2
|
-
import {
|
|
2
|
+
import { evidenceMatches } from "./evidence-match.js";
|
|
3
|
+
import { ResolvedProjectContextSchema } from "../../domain/project-context.js";
|
|
3
4
|
export const MAX_CONTEXT_EVIDENCE_BYTES = 1024 * 1024;
|
|
4
5
|
const SECRET_FILE_NAMES = new Set([
|
|
5
6
|
".git-credentials",
|
|
@@ -70,13 +71,15 @@ function invalidInspection(path, inspection) {
|
|
|
70
71
|
}
|
|
71
72
|
export class ContextValidator {
|
|
72
73
|
files;
|
|
73
|
-
|
|
74
|
+
inventory;
|
|
75
|
+
constructor(files, inventory) {
|
|
74
76
|
this.files = files;
|
|
77
|
+
this.inventory = inventory;
|
|
75
78
|
}
|
|
76
79
|
validate = async (input) => {
|
|
77
|
-
const parsed =
|
|
80
|
+
const parsed = ResolvedProjectContextSchema.safeParse(input.context);
|
|
78
81
|
if (!parsed.success) {
|
|
79
|
-
return invalid("CONTEXT_SCHEMA_INVALID", "Project Context does not match the version
|
|
82
|
+
return invalid("CONTEXT_SCHEMA_INVALID", "Resolved Project Context does not match the version 2 schema");
|
|
80
83
|
}
|
|
81
84
|
let configuredActivity;
|
|
82
85
|
try {
|
|
@@ -85,11 +88,55 @@ export class ContextValidator {
|
|
|
85
88
|
catch {
|
|
86
89
|
return invalid("CONTEXT_IDENTITY_MISMATCH", "Project Context identity does not match the configured project");
|
|
87
90
|
}
|
|
88
|
-
|
|
91
|
+
let divergence;
|
|
92
|
+
if (input.identityPolicy === "configured") {
|
|
93
|
+
const evidenceActivity = parsed.data.launchActivity;
|
|
94
|
+
const activityIsRelative = input.config.run.activity.startsWith(".");
|
|
95
|
+
const suffixMatch = (activityIsRelative
|
|
96
|
+
&& evidenceActivity.endsWith(input.config.run.activity));
|
|
97
|
+
if (evidenceActivity === configuredActivity
|
|
98
|
+
|| suffixMatch) {
|
|
99
|
+
if (parsed.data.packageName !== input.config.run.packageName) {
|
|
100
|
+
const evidencePackageName = suffixMatch
|
|
101
|
+
? evidenceActivity.slice(0, evidenceActivity.length - input.config.run.activity.length)
|
|
102
|
+
: parsed.data.packageName;
|
|
103
|
+
divergence = {
|
|
104
|
+
evidencePackageName,
|
|
105
|
+
configuredPackageName: input.config.run.packageName,
|
|
106
|
+
launchActivity: evidenceActivity
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
return invalid("CONTEXT_IDENTITY_MISMATCH", `Project Context identity does not match the configured project (evidence launchActivity ${evidenceActivity}, configured ${configuredActivity}; declare the activity with: taphound local add <id> --path <path> --package <pkg> --activity <relative-or-fq>)`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (parsed.data.packageName !== input.config.run.packageName
|
|
89
115
|
|| parsed.data.launchActivity !== configuredActivity) {
|
|
90
116
|
return invalid("CONTEXT_IDENTITY_MISMATCH", "Project Context identity does not match the configured project");
|
|
91
117
|
}
|
|
92
118
|
let staleReason;
|
|
119
|
+
const inventoryCache = new Map();
|
|
120
|
+
if (this.inventory !== undefined) {
|
|
121
|
+
for (const module of parsed.data.selection.modules) {
|
|
122
|
+
const inspection = await this.inventory.inspectProjectInventory({
|
|
123
|
+
projectRoot: input.projectRoot,
|
|
124
|
+
projectDir: module.projectDir,
|
|
125
|
+
categories: module.inventory.categories
|
|
126
|
+
});
|
|
127
|
+
inventoryCache.set(module.projectDir, inspection);
|
|
128
|
+
if (inspection.status !== "inspected") {
|
|
129
|
+
return invalid("CONTEXT_SCHEMA_INVALID", `Unable to inspect module inventory: ${module.id}`);
|
|
130
|
+
}
|
|
131
|
+
if (inspection.pathSetSha256 !== module.inventory.pathSetSha256
|
|
132
|
+
&& staleReason === undefined) {
|
|
133
|
+
staleReason = {
|
|
134
|
+
code: "EVIDENCE_HASH_MISMATCH",
|
|
135
|
+
message: `Module file inventory changed: ${module.id}`
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
93
140
|
for (const evidence of parsed.data.manifest.files) {
|
|
94
141
|
if (isSecretEvidencePath(evidence.path)) {
|
|
95
142
|
return invalid("EVIDENCE_SECRET_PATH", `Secret files cannot be context evidence: ${evidence.path}`);
|
|
@@ -106,15 +153,75 @@ export class ContextValidator {
|
|
|
106
153
|
if (inspection.status !== "inspected") {
|
|
107
154
|
return invalidInspection(evidence.path, inspection);
|
|
108
155
|
}
|
|
109
|
-
|
|
156
|
+
const inspected = inspection;
|
|
157
|
+
if (!evidenceMatches(evidence, inspected)) {
|
|
110
158
|
staleReason ??= {
|
|
111
159
|
code: "EVIDENCE_HASH_MISMATCH",
|
|
112
|
-
message:
|
|
160
|
+
message: evidence.semanticSha256 !== undefined
|
|
161
|
+
? `Semantic evidence changed: ${evidence.path}`
|
|
162
|
+
: `Evidence file changed: ${evidence.path}`
|
|
113
163
|
};
|
|
114
164
|
}
|
|
115
165
|
}
|
|
166
|
+
const scopes = input.reportScopes === true && input.modules !== undefined
|
|
167
|
+
? await this.inspectScopes(input.projectRoot, input.modules, inventoryCache)
|
|
168
|
+
: undefined;
|
|
116
169
|
return staleReason === undefined
|
|
117
|
-
? {
|
|
118
|
-
|
|
170
|
+
? {
|
|
171
|
+
status: "valid",
|
|
172
|
+
...(scopes === undefined ? {} : { scopes }),
|
|
173
|
+
...(divergence === undefined ? {} : { divergence })
|
|
174
|
+
}
|
|
175
|
+
: {
|
|
176
|
+
status: "stale",
|
|
177
|
+
reason: staleReason,
|
|
178
|
+
...(scopes === undefined ? {} : { scopes })
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
inspectScopes = async (projectRoot, modules, inventoryCache) => {
|
|
182
|
+
const scopes = [];
|
|
183
|
+
for (const module of modules) {
|
|
184
|
+
const cached = inventoryCache?.get(module.projectDir);
|
|
185
|
+
const inventory = cached !== undefined
|
|
186
|
+
? cached
|
|
187
|
+
: this.inventory === undefined
|
|
188
|
+
? undefined
|
|
189
|
+
: await this.inventory.inspectProjectInventory({
|
|
190
|
+
projectRoot,
|
|
191
|
+
projectDir: module.projectDir,
|
|
192
|
+
categories: module.inventory.categories
|
|
193
|
+
});
|
|
194
|
+
const inventoryChanged = inventory !== undefined
|
|
195
|
+
&& inventory.status === "inspected"
|
|
196
|
+
&& inventory.pathSetSha256 !== module.inventory.pathSetSha256;
|
|
197
|
+
const missingPaths = [];
|
|
198
|
+
const changedPaths = [];
|
|
199
|
+
for (const evidence of module.manifest.files) {
|
|
200
|
+
const inspection = await this.files.inspectProjectFile({
|
|
201
|
+
projectRoot,
|
|
202
|
+
relativePath: evidence.path,
|
|
203
|
+
maximumBytes: MAX_CONTEXT_EVIDENCE_BYTES
|
|
204
|
+
});
|
|
205
|
+
if (inspection.status !== "inspected") {
|
|
206
|
+
if (inspection.status === "notFound") {
|
|
207
|
+
missingPaths.push(evidence.path);
|
|
208
|
+
}
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (inspection.bytes === undefined) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (!evidenceMatches(evidence, inspection)) {
|
|
215
|
+
changedPaths.push(evidence.path);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
scopes.push({
|
|
219
|
+
id: module.moduleId,
|
|
220
|
+
inventoryChanged,
|
|
221
|
+
missingPaths,
|
|
222
|
+
changedPaths
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return scopes;
|
|
119
226
|
};
|
|
120
227
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function semanticSha256(value: string | Uint8Array): string;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
// Produces a conservative semantic hash for source and resource evidence.
|
|
3
|
+
//
|
|
4
|
+
// Comments and formatting whitespace are ignored, while string contents and
|
|
5
|
+
// all other tokens remain significant. This intentionally prefers false
|
|
6
|
+
// positives over allowing a potentially meaningful UI change to pass
|
|
7
|
+
// unnoticed.
|
|
8
|
+
//
|
|
9
|
+
// Supported comment forms: double-slash and hash line comments, C-style and
|
|
10
|
+
// XML block comments. Hash is retained because Gradle .properties provenance
|
|
11
|
+
// files use it.
|
|
12
|
+
//
|
|
13
|
+
// String literals (single quote, double quote, backtick) preserve their
|
|
14
|
+
// contents verbatim, with backslash escapes honored so a quote inside a
|
|
15
|
+
// string does not close it.
|
|
16
|
+
//
|
|
17
|
+
// Kotlin raw strings (triple double-quote) and XML CDATA sections are
|
|
18
|
+
// treated as opaque literals: their full content is preserved (including
|
|
19
|
+
// internal whitespace, which is semantically significant in both) and no
|
|
20
|
+
// comment or quote sequence inside them is interpreted.
|
|
21
|
+
export function semanticSha256(value) {
|
|
22
|
+
const source = typeof value === "string"
|
|
23
|
+
? value
|
|
24
|
+
: Buffer.from(value).toString("utf8");
|
|
25
|
+
let normalized = "";
|
|
26
|
+
let quote;
|
|
27
|
+
let rawString = false;
|
|
28
|
+
let cdata = false;
|
|
29
|
+
let escaped = false;
|
|
30
|
+
let lineComment = false;
|
|
31
|
+
let blockComment = false;
|
|
32
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
33
|
+
const current = source.charAt(index);
|
|
34
|
+
const next = source.charAt(index + 1);
|
|
35
|
+
const after = source.charAt(index + 2);
|
|
36
|
+
if (lineComment) {
|
|
37
|
+
if (current === "\n") {
|
|
38
|
+
lineComment = false;
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (blockComment) {
|
|
43
|
+
if ((current === "*" && next === "/")
|
|
44
|
+
|| (current === "-"
|
|
45
|
+
&& next === "-"
|
|
46
|
+
&& after === ">")) {
|
|
47
|
+
blockComment = false;
|
|
48
|
+
index += current === "*" ? 1 : 2;
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (cdata) {
|
|
53
|
+
if (current === "]" && next === "]" && after === ">") {
|
|
54
|
+
cdata = false;
|
|
55
|
+
index += 2;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
normalized += current;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (rawString) {
|
|
62
|
+
if (current === "\"" && next === "\"" && after === "\"") {
|
|
63
|
+
rawString = false;
|
|
64
|
+
normalized += "\"\"\"";
|
|
65
|
+
index += 2;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
normalized += current;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (quote !== undefined) {
|
|
72
|
+
normalized += current;
|
|
73
|
+
if (escaped) {
|
|
74
|
+
escaped = false;
|
|
75
|
+
}
|
|
76
|
+
else if (current === "\\") {
|
|
77
|
+
escaped = true;
|
|
78
|
+
}
|
|
79
|
+
else if (current === quote) {
|
|
80
|
+
quote = undefined;
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (current === "\"" && next === "\"" && after === "\"") {
|
|
85
|
+
rawString = true;
|
|
86
|
+
normalized += "\"\"\"";
|
|
87
|
+
index += 2;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (current === "<"
|
|
91
|
+
&& next === "!"
|
|
92
|
+
&& after === "["
|
|
93
|
+
&& source.startsWith("[CDATA[", index + 2)) {
|
|
94
|
+
cdata = true;
|
|
95
|
+
normalized += source.slice(index, index + 9);
|
|
96
|
+
index += 8;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if ((current === "/" && next === "/") || current === "#") {
|
|
100
|
+
lineComment = true;
|
|
101
|
+
if (current === "/") {
|
|
102
|
+
index += 1;
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if ((current === "/" && next === "*")
|
|
107
|
+
|| (current === "<"
|
|
108
|
+
&& next === "!"
|
|
109
|
+
&& after === "-"
|
|
110
|
+
&& source.charAt(index + 3) === "-")) {
|
|
111
|
+
blockComment = true;
|
|
112
|
+
index += current === "/" ? 1 : 3;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (current === "'" || current === "\"" || current === "`") {
|
|
116
|
+
quote = current;
|
|
117
|
+
normalized += current;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (!/\s/.test(current)) {
|
|
121
|
+
normalized += current;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
125
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface EvidenceRecord {
|
|
2
|
+
readonly sha256: string;
|
|
3
|
+
readonly semanticSha256?: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
export interface InspectedFile {
|
|
6
|
+
readonly sha256: string;
|
|
7
|
+
readonly bytes?: Buffer | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare function evidenceMatches(evidence: EvidenceRecord, inspected: InspectedFile): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { semanticSha256 } from "./evidence-hash.js";
|
|
2
|
+
export function evidenceMatches(evidence, inspected) {
|
|
3
|
+
if (evidence.semanticSha256 !== undefined) {
|
|
4
|
+
return inspected.bytes !== undefined
|
|
5
|
+
&& semanticSha256(inspected.bytes) === evidence.semanticSha256;
|
|
6
|
+
}
|
|
7
|
+
return inspected.sha256 === evidence.sha256;
|
|
8
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function assertShardIdentity(reference, document, createError) {
|
|
2
|
+
if (document.moduleId !== reference.id
|
|
3
|
+
|| document.projectDir !== reference.projectDir
|
|
4
|
+
|| document.status !== reference.status) {
|
|
5
|
+
throw createError(`Context shard identity does not match its index: ${reference.id}`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type AcceptanceContract } from "../../domain/contract.js";
|
|
2
|
+
import type { FailureCode } from "../../domain/failure.js";
|
|
3
|
+
import { type Journey } from "../../domain/journey.js";
|
|
4
|
+
export declare class ContractError extends Error {
|
|
5
|
+
readonly code: FailureCode;
|
|
6
|
+
constructor(code: FailureCode, message: string);
|
|
7
|
+
}
|
|
8
|
+
export interface LoadedContract {
|
|
9
|
+
contract: AcceptanceContract;
|
|
10
|
+
contractSha256: string;
|
|
11
|
+
journey: Journey;
|
|
12
|
+
journeyPath: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ContractLoaderDependencies {
|
|
15
|
+
readText: (path: string) => Promise<string>;
|
|
16
|
+
}
|
|
17
|
+
export declare function hashContractText(text: string): string;
|
|
18
|
+
export declare class ContractLoader {
|
|
19
|
+
private readonly dependencies;
|
|
20
|
+
constructor(dependencies: ContractLoaderDependencies);
|
|
21
|
+
readonly load: (input: {
|
|
22
|
+
projectRoot: string;
|
|
23
|
+
contractPath: string;
|
|
24
|
+
}) => Promise<LoadedContract>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { AcceptanceContractSchema } from "../../domain/contract.js";
|
|
4
|
+
import { JourneySchema } from "../../domain/journey.js";
|
|
5
|
+
import { hashJourney } from "../../domain/report.js";
|
|
6
|
+
export class ContractError extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(code, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.name = "ContractError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function hashContractText(text) {
|
|
15
|
+
return createHash("sha256").update(text).digest("hex");
|
|
16
|
+
}
|
|
17
|
+
export class ContractLoader {
|
|
18
|
+
dependencies;
|
|
19
|
+
constructor(dependencies) {
|
|
20
|
+
this.dependencies = dependencies;
|
|
21
|
+
}
|
|
22
|
+
load = async (input) => {
|
|
23
|
+
let contractText;
|
|
24
|
+
try {
|
|
25
|
+
contractText = await this.dependencies.readText(input.contractPath);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
throw new ContractError("CONTRACT_INVALID", `Cannot read Acceptance Contract at ${input.contractPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
29
|
+
}
|
|
30
|
+
let contract;
|
|
31
|
+
try {
|
|
32
|
+
contract = AcceptanceContractSchema.parse(JSON.parse(contractText));
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw new ContractError("CONTRACT_INVALID", `Acceptance Contract at ${input.contractPath} is invalid: ${error instanceof Error ? error.message : String(error)}`);
|
|
36
|
+
}
|
|
37
|
+
const journeyPath = join(input.projectRoot, contract.journey.path);
|
|
38
|
+
let journeyText;
|
|
39
|
+
try {
|
|
40
|
+
journeyText = await this.dependencies.readText(journeyPath);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
throw new ContractError("CONTRACT_JOURNEY_MISSING", `Bound Journey ${contract.journey.path} is missing: ${error instanceof Error ? error.message : String(error)}`);
|
|
44
|
+
}
|
|
45
|
+
let journey;
|
|
46
|
+
try {
|
|
47
|
+
journey = JourneySchema.parse(JSON.parse(journeyText));
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
throw new ContractError("CONTRACT_JOURNEY_MISSING", `Bound Journey ${contract.journey.path} is invalid: ${error instanceof Error ? error.message : String(error)}`);
|
|
51
|
+
}
|
|
52
|
+
const journeySha256 = hashJourney(journey);
|
|
53
|
+
if (journeySha256 !== contract.journey.sha256) {
|
|
54
|
+
throw new ContractError("CONTRACT_JOURNEY_DRIFT", `Bound Journey ${contract.journey.path} drifted: binding ${contract.journey.sha256}, found ${journeySha256}. Re-bind the contract to the current Journey or restore the bound content.`);
|
|
55
|
+
}
|
|
56
|
+
for (const id of contract.requiredCheckpoints) {
|
|
57
|
+
if (!journey.checkpoints?.some((checkpoint) => checkpoint.id === id)) {
|
|
58
|
+
throw new ContractError("CONTRACT_INVALID", `Required Checkpoint ${id} is not defined by the bound Journey`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
contract,
|
|
63
|
+
contractSha256: hashContractText(contractText),
|
|
64
|
+
journey,
|
|
65
|
+
journeyPath
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ContractReviewInput, type ContractVerdictView } from "../../domain/contract.js";
|
|
2
|
+
export interface ContractReviewMergeDependencies {
|
|
3
|
+
now: () => Date;
|
|
4
|
+
}
|
|
5
|
+
export interface ContractReviewMergeResult {
|
|
6
|
+
view: ContractVerdictView;
|
|
7
|
+
applied: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Applies reviewer findings on top of a deterministic Verdict view.
|
|
11
|
+
*
|
|
12
|
+
* Source-of-Truth enforcement (docs/source-of-truth.md):
|
|
13
|
+
* - a lower-trust layer (semantic / multimodal reviewer) may escalate a
|
|
14
|
+
* successful or uncertain result into `needsReview`;
|
|
15
|
+
* - it must never rewrite a deterministic `fail` or `invalid` back to
|
|
16
|
+
* success; those stay immutable and the review is recorded as not applied.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ContractReviewMerger {
|
|
19
|
+
private readonly dependencies;
|
|
20
|
+
constructor(dependencies: ContractReviewMergeDependencies);
|
|
21
|
+
readonly merge: (input: {
|
|
22
|
+
view: ContractVerdictView;
|
|
23
|
+
review: ContractReviewInput;
|
|
24
|
+
}) => Promise<ContractReviewMergeResult>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ContractReviewSchema, ContractVerdictViewSchema } from "../../domain/contract.js";
|
|
2
|
+
const IMMUTABLE_VERDICTS = new Set([
|
|
3
|
+
"fail",
|
|
4
|
+
"invalid"
|
|
5
|
+
]);
|
|
6
|
+
/**
|
|
7
|
+
* Applies reviewer findings on top of a deterministic Verdict view.
|
|
8
|
+
*
|
|
9
|
+
* Source-of-Truth enforcement (docs/source-of-truth.md):
|
|
10
|
+
* - a lower-trust layer (semantic / multimodal reviewer) may escalate a
|
|
11
|
+
* successful or uncertain result into `needsReview`;
|
|
12
|
+
* - it must never rewrite a deterministic `fail` or `invalid` back to
|
|
13
|
+
* success; those stay immutable and the review is recorded as not applied.
|
|
14
|
+
*/
|
|
15
|
+
export class ContractReviewMerger {
|
|
16
|
+
dependencies;
|
|
17
|
+
constructor(dependencies) {
|
|
18
|
+
this.dependencies = dependencies;
|
|
19
|
+
}
|
|
20
|
+
merge = (input) => {
|
|
21
|
+
const { view, review } = input;
|
|
22
|
+
const immutable = IMMUTABLE_VERDICTS.has(view.verdict);
|
|
23
|
+
const applied = !immutable;
|
|
24
|
+
const previousFindings = view.review?.findings ?? [];
|
|
25
|
+
const record = ContractReviewSchema.parse({
|
|
26
|
+
version: 1,
|
|
27
|
+
source: review.source,
|
|
28
|
+
...(review.model === undefined ? {} : { model: review.model }),
|
|
29
|
+
...(review.promptVersion === undefined
|
|
30
|
+
? {}
|
|
31
|
+
: { promptVersion: review.promptVersion }),
|
|
32
|
+
findings: [...previousFindings, ...review.findings],
|
|
33
|
+
appliedAt: new Date(this.dependencies.now()).toISOString(),
|
|
34
|
+
applied,
|
|
35
|
+
baseVerdict: view.verdict,
|
|
36
|
+
baseReason: view.reason
|
|
37
|
+
});
|
|
38
|
+
const merged = ContractVerdictViewSchema.parse({
|
|
39
|
+
...view,
|
|
40
|
+
...(applied
|
|
41
|
+
? {
|
|
42
|
+
verdict: "needsReview",
|
|
43
|
+
reason: "REVIEW_FINDINGS",
|
|
44
|
+
message: `Reviewer ${review.source} found ${String(record.findings.length)} finding(s) requiring human review`
|
|
45
|
+
}
|
|
46
|
+
: {}),
|
|
47
|
+
review: record
|
|
48
|
+
});
|
|
49
|
+
return Promise.resolve({ view: merged, applied });
|
|
50
|
+
};
|
|
51
|
+
}
|