@intentcomputing/koko-agent-sdk 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/CODE_OF_CONDUCT.md +3 -0
- package/CONTRIBUTING.md +9 -0
- package/LICENSE +21 -0
- package/README.md +65 -0
- package/README.zh-CN.md +50 -0
- package/SECURITY.md +5 -0
- package/android/build.gradle +40 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/cn/intentcomputing/kokoagentsdk/KokoAgentSdkModule.java +1356 -0
- package/android/src/main/java/cn/intentcomputing/kokoagentsdk/KokoAgentSdkPackage.java +23 -0
- package/docs/INTEGRATION.md +168 -0
- package/docs/INTEGRATION.zh-CN.md +140 -0
- package/docs/PRIVACY.md +11 -0
- package/docs/PRIVACY.zh-CN.md +11 -0
- package/docs/PUBLISH.md +11 -0
- package/docs/PUBLISH.zh-CN.md +11 -0
- package/ios/KokoAgentSdk/KokoAgentSdk.h +5 -0
- package/ios/KokoAgentSdk/KokoAgentSdk.m +2464 -0
- package/ios/KokoAgentSdk/KokoOcrBounds.h +20 -0
- package/ios/KokoAgentSdk/KokoScrollBounds.h +21 -0
- package/koko-agent-sdk.podspec +23 -0
- package/lib/commonjs/KokoAgent.js +1427 -0
- package/lib/commonjs/KokoAgent.js.map +1 -0
- package/lib/commonjs/assist/OnDeviceAssist.js +94 -0
- package/lib/commonjs/assist/OnDeviceAssist.js.map +1 -0
- package/lib/commonjs/assist/intentClassify.js +100 -0
- package/lib/commonjs/assist/intentClassify.js.map +1 -0
- package/lib/commonjs/assist/nodeRank.js +120 -0
- package/lib/commonjs/assist/nodeRank.js.map +1 -0
- package/lib/commonjs/assist/ocrTarget.js +135 -0
- package/lib/commonjs/assist/ocrTarget.js.map +1 -0
- package/lib/commonjs/assist/webVisualChange.js +29 -0
- package/lib/commonjs/assist/webVisualChange.js.map +1 -0
- package/lib/commonjs/client/ActionOutcomeUnknownError.js +28 -0
- package/lib/commonjs/client/ActionOutcomeUnknownError.js.map +1 -0
- package/lib/commonjs/client/AgentSession.js +858 -0
- package/lib/commonjs/client/AgentSession.js.map +1 -0
- package/lib/commonjs/client/GatewayClient.js +302 -0
- package/lib/commonjs/client/GatewayClient.js.map +1 -0
- package/lib/commonjs/client/OperationReplayGuard.js +62 -0
- package/lib/commonjs/client/OperationReplayGuard.js.map +1 -0
- package/lib/commonjs/client/RunCheckpoint.js +139 -0
- package/lib/commonjs/client/RunCheckpoint.js.map +1 -0
- package/lib/commonjs/client/loopDetect.js +184 -0
- package/lib/commonjs/client/loopDetect.js.map +1 -0
- package/lib/commonjs/client/recentSearch.js +50 -0
- package/lib/commonjs/client/recentSearch.js.map +1 -0
- package/lib/commonjs/client/walletChoiceGuard.js +18 -0
- package/lib/commonjs/client/walletChoiceGuard.js.map +1 -0
- package/lib/commonjs/client/webResultCategory.js +38 -0
- package/lib/commonjs/client/webResultCategory.js.map +1 -0
- package/lib/commonjs/commercial/AccountStore.js +78 -0
- package/lib/commonjs/commercial/AccountStore.js.map +1 -0
- package/lib/commonjs/commercial/AgentDebug.js +104 -0
- package/lib/commonjs/commercial/AgentDebug.js.map +1 -0
- package/lib/commonjs/commercial/ExecutionGuard.js +53 -0
- package/lib/commonjs/commercial/ExecutionGuard.js.map +1 -0
- package/lib/commonjs/commercial/UsageBus.js +42 -0
- package/lib/commonjs/commercial/UsageBus.js.map +1 -0
- package/lib/commonjs/commercial/branding.js +69 -0
- package/lib/commonjs/commercial/branding.js.map +1 -0
- package/lib/commonjs/commercial/devMode.js +52 -0
- package/lib/commonjs/commercial/devMode.js.map +1 -0
- package/lib/commonjs/commercial/trust.js +69 -0
- package/lib/commonjs/commercial/trust.js.map +1 -0
- package/lib/commonjs/confirmation/gate.js +62 -0
- package/lib/commonjs/confirmation/gate.js.map +1 -0
- package/lib/commonjs/cursor/CursorOverlay.js +141 -0
- package/lib/commonjs/cursor/CursorOverlay.js.map +1 -0
- package/lib/commonjs/cursor/PointerHand.js +51 -0
- package/lib/commonjs/cursor/PointerHand.js.map +1 -0
- package/lib/commonjs/cursor/controller.js +91 -0
- package/lib/commonjs/cursor/controller.js.map +1 -0
- package/lib/commonjs/cursor/pointer.js +49 -0
- package/lib/commonjs/cursor/pointer.js.map +1 -0
- package/lib/commonjs/debug/KokoRemoteSmoke.js +611 -0
- package/lib/commonjs/debug/KokoRemoteSmoke.js.map +1 -0
- package/lib/commonjs/explore/ExplorationGraph.js +418 -0
- package/lib/commonjs/explore/ExplorationGraph.js.map +1 -0
- package/lib/commonjs/explore/bootstrapExplore.js +59 -0
- package/lib/commonjs/explore/bootstrapExplore.js.map +1 -0
- package/lib/commonjs/host/HostActions.js +266 -0
- package/lib/commonjs/host/HostActions.js.map +1 -0
- package/lib/commonjs/i18n/index.js +169 -0
- package/lib/commonjs/i18n/index.js.map +1 -0
- package/lib/commonjs/i18n/runtimeMessages.js +184 -0
- package/lib/commonjs/i18n/runtimeMessages.js.map +1 -0
- package/lib/commonjs/index.js +640 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/native/NativeBridge.js +132 -0
- package/lib/commonjs/native/NativeBridge.js.map +1 -0
- package/lib/commonjs/native/navigationLabel.js +16 -0
- package/lib/commonjs/native/navigationLabel.js.map +1 -0
- package/lib/commonjs/native/normalizeViewTree.js +28 -0
- package/lib/commonjs/native/normalizeViewTree.js.map +1 -0
- package/lib/commonjs/native/pruneOffscreen.js +76 -0
- package/lib/commonjs/native/pruneOffscreen.js.map +1 -0
- package/lib/commonjs/native/scrollViewport.js +69 -0
- package/lib/commonjs/native/scrollViewport.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/privacy/redact.js +108 -0
- package/lib/commonjs/privacy/redact.js.map +1 -0
- package/lib/commonjs/privacy/screenEvidence.js +59 -0
- package/lib/commonjs/privacy/screenEvidence.js.map +1 -0
- package/lib/commonjs/privacy/screenModel.js +404 -0
- package/lib/commonjs/privacy/screenModel.js.map +1 -0
- package/lib/commonjs/privacy/sensitiveScreen.js +58 -0
- package/lib/commonjs/privacy/sensitiveScreen.js.map +1 -0
- package/lib/commonjs/privacy/userGate.js +213 -0
- package/lib/commonjs/privacy/userGate.js.map +1 -0
- package/lib/commonjs/protocol/actions.js +112 -0
- package/lib/commonjs/protocol/actions.js.map +1 -0
- package/lib/commonjs/provider/HostAppearanceStore.js +111 -0
- package/lib/commonjs/provider/HostAppearanceStore.js.map +1 -0
- package/lib/commonjs/provider/KokoProvider.js +81 -0
- package/lib/commonjs/provider/KokoProvider.js.map +1 -0
- package/lib/commonjs/provider/KokoUiContext.js +102 -0
- package/lib/commonjs/provider/KokoUiContext.js.map +1 -0
- package/lib/commonjs/selector/match.js +378 -0
- package/lib/commonjs/selector/match.js.map +1 -0
- package/lib/commonjs/task/TaskStore.js +361 -0
- package/lib/commonjs/task/TaskStore.js.map +1 -0
- package/lib/commonjs/task/types.js +2 -0
- package/lib/commonjs/task/types.js.map +1 -0
- package/lib/commonjs/task/useTaskStore.js +14 -0
- package/lib/commonjs/task/useTaskStore.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/ui/KokoChatSheet.js +885 -0
- package/lib/commonjs/ui/KokoChatSheet.js.map +1 -0
- package/lib/commonjs/ui/KokoComposer.js +161 -0
- package/lib/commonjs/ui/KokoComposer.js.map +1 -0
- package/lib/commonjs/ui/KokoDialogHost.js +254 -0
- package/lib/commonjs/ui/KokoDialogHost.js.map +1 -0
- package/lib/commonjs/ui/KokoEntryButton.js +81 -0
- package/lib/commonjs/ui/KokoEntryButton.js.map +1 -0
- package/lib/commonjs/ui/KokoObserver.js +522 -0
- package/lib/commonjs/ui/KokoObserver.js.map +1 -0
- package/lib/commonjs/ui/KokoOverlayLayer.js +45 -0
- package/lib/commonjs/ui/KokoOverlayLayer.js.map +1 -0
- package/lib/commonjs/ui/KokoSubtitle.js +95 -0
- package/lib/commonjs/ui/KokoSubtitle.js.map +1 -0
- package/lib/commonjs/ui/KokoTaskPanel.js +322 -0
- package/lib/commonjs/ui/KokoTaskPanel.js.map +1 -0
- package/lib/commonjs/ui/hostOverlay.js +126 -0
- package/lib/commonjs/ui/hostOverlay.js.map +1 -0
- package/lib/commonjs/ui/icons.js +132 -0
- package/lib/commonjs/ui/icons.js.map +1 -0
- package/lib/commonjs/ui/progressChrome.js +66 -0
- package/lib/commonjs/ui/progressChrome.js.map +1 -0
- package/lib/commonjs/ui/safeArea.js +96 -0
- package/lib/commonjs/ui/safeArea.js.map +1 -0
- package/lib/commonjs/ui/useOverlayOrigin.js +40 -0
- package/lib/commonjs/ui/useOverlayOrigin.js.map +1 -0
- package/lib/module/KokoAgent.js +1418 -0
- package/lib/module/KokoAgent.js.map +1 -0
- package/lib/module/assist/OnDeviceAssist.js +89 -0
- package/lib/module/assist/OnDeviceAssist.js.map +1 -0
- package/lib/module/assist/intentClassify.js +95 -0
- package/lib/module/assist/intentClassify.js.map +1 -0
- package/lib/module/assist/nodeRank.js +115 -0
- package/lib/module/assist/nodeRank.js.map +1 -0
- package/lib/module/assist/ocrTarget.js +123 -0
- package/lib/module/assist/ocrTarget.js.map +1 -0
- package/lib/module/assist/webVisualChange.js +24 -0
- package/lib/module/assist/webVisualChange.js.map +1 -0
- package/lib/module/client/ActionOutcomeUnknownError.js +23 -0
- package/lib/module/client/ActionOutcomeUnknownError.js.map +1 -0
- package/lib/module/client/AgentSession.js +854 -0
- package/lib/module/client/AgentSession.js.map +1 -0
- package/lib/module/client/GatewayClient.js +293 -0
- package/lib/module/client/GatewayClient.js.map +1 -0
- package/lib/module/client/OperationReplayGuard.js +58 -0
- package/lib/module/client/OperationReplayGuard.js.map +1 -0
- package/lib/module/client/RunCheckpoint.js +135 -0
- package/lib/module/client/RunCheckpoint.js.map +1 -0
- package/lib/module/client/loopDetect.js +177 -0
- package/lib/module/client/loopDetect.js.map +1 -0
- package/lib/module/client/recentSearch.js +46 -0
- package/lib/module/client/recentSearch.js.map +1 -0
- package/lib/module/client/walletChoiceGuard.js +14 -0
- package/lib/module/client/walletChoiceGuard.js.map +1 -0
- package/lib/module/client/webResultCategory.js +34 -0
- package/lib/module/client/webResultCategory.js.map +1 -0
- package/lib/module/commercial/AccountStore.js +75 -0
- package/lib/module/commercial/AccountStore.js.map +1 -0
- package/lib/module/commercial/AgentDebug.js +99 -0
- package/lib/module/commercial/AgentDebug.js.map +1 -0
- package/lib/module/commercial/ExecutionGuard.js +49 -0
- package/lib/module/commercial/ExecutionGuard.js.map +1 -0
- package/lib/module/commercial/UsageBus.js +38 -0
- package/lib/module/commercial/UsageBus.js.map +1 -0
- package/lib/module/commercial/branding.js +63 -0
- package/lib/module/commercial/branding.js.map +1 -0
- package/lib/module/commercial/devMode.js +45 -0
- package/lib/module/commercial/devMode.js.map +1 -0
- package/lib/module/commercial/trust.js +62 -0
- package/lib/module/commercial/trust.js.map +1 -0
- package/lib/module/confirmation/gate.js +54 -0
- package/lib/module/confirmation/gate.js.map +1 -0
- package/lib/module/cursor/CursorOverlay.js +136 -0
- package/lib/module/cursor/CursorOverlay.js.map +1 -0
- package/lib/module/cursor/PointerHand.js +47 -0
- package/lib/module/cursor/PointerHand.js.map +1 -0
- package/lib/module/cursor/controller.js +87 -0
- package/lib/module/cursor/controller.js.map +1 -0
- package/lib/module/cursor/pointer.js +45 -0
- package/lib/module/cursor/pointer.js.map +1 -0
- package/lib/module/debug/KokoRemoteSmoke.js +608 -0
- package/lib/module/debug/KokoRemoteSmoke.js.map +1 -0
- package/lib/module/explore/ExplorationGraph.js +406 -0
- package/lib/module/explore/ExplorationGraph.js.map +1 -0
- package/lib/module/explore/bootstrapExplore.js +55 -0
- package/lib/module/explore/bootstrapExplore.js.map +1 -0
- package/lib/module/host/HostActions.js +255 -0
- package/lib/module/host/HostActions.js.map +1 -0
- package/lib/module/i18n/index.js +159 -0
- package/lib/module/i18n/index.js.map +1 -0
- package/lib/module/i18n/runtimeMessages.js +180 -0
- package/lib/module/i18n/runtimeMessages.js.map +1 -0
- package/lib/module/index.js +44 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/NativeBridge.js +128 -0
- package/lib/module/native/NativeBridge.js.map +1 -0
- package/lib/module/native/navigationLabel.js +12 -0
- package/lib/module/native/navigationLabel.js.map +1 -0
- package/lib/module/native/normalizeViewTree.js +25 -0
- package/lib/module/native/normalizeViewTree.js.map +1 -0
- package/lib/module/native/pruneOffscreen.js +72 -0
- package/lib/module/native/pruneOffscreen.js.map +1 -0
- package/lib/module/native/scrollViewport.js +63 -0
- package/lib/module/native/scrollViewport.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/privacy/redact.js +103 -0
- package/lib/module/privacy/redact.js.map +1 -0
- package/lib/module/privacy/screenEvidence.js +50 -0
- package/lib/module/privacy/screenEvidence.js.map +1 -0
- package/lib/module/privacy/screenModel.js +397 -0
- package/lib/module/privacy/screenModel.js.map +1 -0
- package/lib/module/privacy/sensitiveScreen.js +52 -0
- package/lib/module/privacy/sensitiveScreen.js.map +1 -0
- package/lib/module/privacy/userGate.js +202 -0
- package/lib/module/privacy/userGate.js.map +1 -0
- package/lib/module/protocol/actions.js +108 -0
- package/lib/module/protocol/actions.js.map +1 -0
- package/lib/module/provider/HostAppearanceStore.js +101 -0
- package/lib/module/provider/HostAppearanceStore.js.map +1 -0
- package/lib/module/provider/KokoProvider.js +74 -0
- package/lib/module/provider/KokoProvider.js.map +1 -0
- package/lib/module/provider/KokoUiContext.js +96 -0
- package/lib/module/provider/KokoUiContext.js.map +1 -0
- package/lib/module/selector/match.js +366 -0
- package/lib/module/selector/match.js.map +1 -0
- package/lib/module/task/TaskStore.js +356 -0
- package/lib/module/task/TaskStore.js.map +1 -0
- package/lib/module/task/types.js +2 -0
- package/lib/module/task/types.js.map +1 -0
- package/lib/module/task/useTaskStore.js +10 -0
- package/lib/module/task/useTaskStore.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/ui/KokoChatSheet.js +879 -0
- package/lib/module/ui/KokoChatSheet.js.map +1 -0
- package/lib/module/ui/KokoComposer.js +155 -0
- package/lib/module/ui/KokoComposer.js.map +1 -0
- package/lib/module/ui/KokoDialogHost.js +247 -0
- package/lib/module/ui/KokoDialogHost.js.map +1 -0
- package/lib/module/ui/KokoEntryButton.js +74 -0
- package/lib/module/ui/KokoEntryButton.js.map +1 -0
- package/lib/module/ui/KokoObserver.js +516 -0
- package/lib/module/ui/KokoObserver.js.map +1 -0
- package/lib/module/ui/KokoOverlayLayer.js +39 -0
- package/lib/module/ui/KokoOverlayLayer.js.map +1 -0
- package/lib/module/ui/KokoSubtitle.js +90 -0
- package/lib/module/ui/KokoSubtitle.js.map +1 -0
- package/lib/module/ui/KokoTaskPanel.js +316 -0
- package/lib/module/ui/KokoTaskPanel.js.map +1 -0
- package/lib/module/ui/hostOverlay.js +120 -0
- package/lib/module/ui/hostOverlay.js.map +1 -0
- package/lib/module/ui/icons.js +124 -0
- package/lib/module/ui/icons.js.map +1 -0
- package/lib/module/ui/progressChrome.js +58 -0
- package/lib/module/ui/progressChrome.js.map +1 -0
- package/lib/module/ui/safeArea.js +92 -0
- package/lib/module/ui/safeArea.js.map +1 -0
- package/lib/module/ui/useOverlayOrigin.js +36 -0
- package/lib/module/ui/useOverlayOrigin.js.map +1 -0
- package/lib/typescript/commonjs/KokoAgent.d.ts +167 -0
- package/lib/typescript/commonjs/KokoAgent.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/OnDeviceAssist.d.ts +31 -0
- package/lib/typescript/commonjs/assist/OnDeviceAssist.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/intentClassify.d.ts +18 -0
- package/lib/typescript/commonjs/assist/intentClassify.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/nodeRank.d.ts +32 -0
- package/lib/typescript/commonjs/assist/nodeRank.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/ocrTarget.d.ts +25 -0
- package/lib/typescript/commonjs/assist/ocrTarget.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/webVisualChange.d.ts +6 -0
- package/lib/typescript/commonjs/assist/webVisualChange.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/ActionOutcomeUnknownError.d.ts +13 -0
- package/lib/typescript/commonjs/client/ActionOutcomeUnknownError.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/AgentSession.d.ts +56 -0
- package/lib/typescript/commonjs/client/AgentSession.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/GatewayClient.d.ts +149 -0
- package/lib/typescript/commonjs/client/GatewayClient.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/OperationReplayGuard.d.ts +13 -0
- package/lib/typescript/commonjs/client/OperationReplayGuard.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/RunCheckpoint.d.ts +57 -0
- package/lib/typescript/commonjs/client/RunCheckpoint.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/loopDetect.d.ts +15 -0
- package/lib/typescript/commonjs/client/loopDetect.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/recentSearch.d.ts +5 -0
- package/lib/typescript/commonjs/client/recentSearch.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/walletChoiceGuard.d.ts +4 -0
- package/lib/typescript/commonjs/client/walletChoiceGuard.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/webResultCategory.d.ts +5 -0
- package/lib/typescript/commonjs/client/webResultCategory.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/AccountStore.d.ts +17 -0
- package/lib/typescript/commonjs/commercial/AccountStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/AgentDebug.d.ts +25 -0
- package/lib/typescript/commonjs/commercial/AgentDebug.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/ExecutionGuard.d.ts +18 -0
- package/lib/typescript/commonjs/commercial/ExecutionGuard.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/UsageBus.d.ts +18 -0
- package/lib/typescript/commonjs/commercial/UsageBus.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/branding.d.ts +25 -0
- package/lib/typescript/commonjs/commercial/branding.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/devMode.d.ts +26 -0
- package/lib/typescript/commonjs/commercial/devMode.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/trust.d.ts +21 -0
- package/lib/typescript/commonjs/commercial/trust.d.ts.map +1 -0
- package/lib/typescript/commonjs/confirmation/gate.d.ts +18 -0
- package/lib/typescript/commonjs/confirmation/gate.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/CursorOverlay.d.ts +13 -0
- package/lib/typescript/commonjs/cursor/CursorOverlay.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/PointerHand.d.ts +16 -0
- package/lib/typescript/commonjs/cursor/PointerHand.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/controller.d.ts +30 -0
- package/lib/typescript/commonjs/cursor/controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/pointer.d.ts +23 -0
- package/lib/typescript/commonjs/cursor/pointer.d.ts.map +1 -0
- package/lib/typescript/commonjs/debug/KokoRemoteSmoke.d.ts +96 -0
- package/lib/typescript/commonjs/debug/KokoRemoteSmoke.d.ts.map +1 -0
- package/lib/typescript/commonjs/explore/ExplorationGraph.d.ts +96 -0
- package/lib/typescript/commonjs/explore/ExplorationGraph.d.ts.map +1 -0
- package/lib/typescript/commonjs/explore/bootstrapExplore.d.ts +40 -0
- package/lib/typescript/commonjs/explore/bootstrapExplore.d.ts.map +1 -0
- package/lib/typescript/commonjs/host/HostActions.d.ts +101 -0
- package/lib/typescript/commonjs/host/HostActions.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/index.d.ts +20 -0
- package/lib/typescript/commonjs/i18n/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/runtimeMessages.d.ts +178 -0
- package/lib/typescript/commonjs/i18n/runtimeMessages.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +66 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/NativeBridge.d.ts +70 -0
- package/lib/typescript/commonjs/native/NativeBridge.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/navigationLabel.d.ts +4 -0
- package/lib/typescript/commonjs/native/navigationLabel.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/normalizeViewTree.d.ts +4 -0
- package/lib/typescript/commonjs/native/normalizeViewTree.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/pruneOffscreen.d.ts +3 -0
- package/lib/typescript/commonjs/native/pruneOffscreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/scrollViewport.d.ts +13 -0
- package/lib/typescript/commonjs/native/scrollViewport.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/privacy/redact.d.ts +9 -0
- package/lib/typescript/commonjs/privacy/redact.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/screenEvidence.d.ts +14 -0
- package/lib/typescript/commonjs/privacy/screenEvidence.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/screenModel.d.ts +26 -0
- package/lib/typescript/commonjs/privacy/screenModel.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/sensitiveScreen.d.ts +8 -0
- package/lib/typescript/commonjs/privacy/sensitiveScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/userGate.d.ts +58 -0
- package/lib/typescript/commonjs/privacy/userGate.d.ts.map +1 -0
- package/lib/typescript/commonjs/protocol/actions.d.ts +7 -0
- package/lib/typescript/commonjs/protocol/actions.d.ts.map +1 -0
- package/lib/typescript/commonjs/provider/HostAppearanceStore.d.ts +64 -0
- package/lib/typescript/commonjs/provider/HostAppearanceStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/provider/KokoProvider.d.ts +39 -0
- package/lib/typescript/commonjs/provider/KokoProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/provider/KokoUiContext.d.ts +22 -0
- package/lib/typescript/commonjs/provider/KokoUiContext.d.ts.map +1 -0
- package/lib/typescript/commonjs/selector/match.d.ts +27 -0
- package/lib/typescript/commonjs/selector/match.d.ts.map +1 -0
- package/lib/typescript/commonjs/task/TaskStore.d.ts +65 -0
- package/lib/typescript/commonjs/task/TaskStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/task/types.d.ts +66 -0
- package/lib/typescript/commonjs/task/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/task/useTaskStore.d.ts +3 -0
- package/lib/typescript/commonjs/task/useTaskStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/types.d.ts +372 -0
- package/lib/typescript/commonjs/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoChatSheet.d.ts +8 -0
- package/lib/typescript/commonjs/ui/KokoChatSheet.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoComposer.d.ts +13 -0
- package/lib/typescript/commonjs/ui/KokoComposer.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoDialogHost.d.ts +32 -0
- package/lib/typescript/commonjs/ui/KokoDialogHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoEntryButton.d.ts +18 -0
- package/lib/typescript/commonjs/ui/KokoEntryButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoObserver.d.ts +13 -0
- package/lib/typescript/commonjs/ui/KokoObserver.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoOverlayLayer.d.ts +35 -0
- package/lib/typescript/commonjs/ui/KokoOverlayLayer.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoSubtitle.d.ts +7 -0
- package/lib/typescript/commonjs/ui/KokoSubtitle.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoTaskPanel.d.ts +7 -0
- package/lib/typescript/commonjs/ui/KokoTaskPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hostOverlay.d.ts +28 -0
- package/lib/typescript/commonjs/ui/hostOverlay.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/icons.d.ts +26 -0
- package/lib/typescript/commonjs/ui/icons.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/progressChrome.d.ts +21 -0
- package/lib/typescript/commonjs/ui/progressChrome.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/safeArea.d.ts +12 -0
- package/lib/typescript/commonjs/ui/safeArea.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/useOverlayOrigin.d.ts +22 -0
- package/lib/typescript/commonjs/ui/useOverlayOrigin.d.ts.map +1 -0
- package/lib/typescript/module/KokoAgent.d.ts +167 -0
- package/lib/typescript/module/KokoAgent.d.ts.map +1 -0
- package/lib/typescript/module/assist/OnDeviceAssist.d.ts +31 -0
- package/lib/typescript/module/assist/OnDeviceAssist.d.ts.map +1 -0
- package/lib/typescript/module/assist/intentClassify.d.ts +18 -0
- package/lib/typescript/module/assist/intentClassify.d.ts.map +1 -0
- package/lib/typescript/module/assist/nodeRank.d.ts +32 -0
- package/lib/typescript/module/assist/nodeRank.d.ts.map +1 -0
- package/lib/typescript/module/assist/ocrTarget.d.ts +25 -0
- package/lib/typescript/module/assist/ocrTarget.d.ts.map +1 -0
- package/lib/typescript/module/assist/webVisualChange.d.ts +6 -0
- package/lib/typescript/module/assist/webVisualChange.d.ts.map +1 -0
- package/lib/typescript/module/client/ActionOutcomeUnknownError.d.ts +13 -0
- package/lib/typescript/module/client/ActionOutcomeUnknownError.d.ts.map +1 -0
- package/lib/typescript/module/client/AgentSession.d.ts +56 -0
- package/lib/typescript/module/client/AgentSession.d.ts.map +1 -0
- package/lib/typescript/module/client/GatewayClient.d.ts +149 -0
- package/lib/typescript/module/client/GatewayClient.d.ts.map +1 -0
- package/lib/typescript/module/client/OperationReplayGuard.d.ts +13 -0
- package/lib/typescript/module/client/OperationReplayGuard.d.ts.map +1 -0
- package/lib/typescript/module/client/RunCheckpoint.d.ts +57 -0
- package/lib/typescript/module/client/RunCheckpoint.d.ts.map +1 -0
- package/lib/typescript/module/client/loopDetect.d.ts +15 -0
- package/lib/typescript/module/client/loopDetect.d.ts.map +1 -0
- package/lib/typescript/module/client/recentSearch.d.ts +5 -0
- package/lib/typescript/module/client/recentSearch.d.ts.map +1 -0
- package/lib/typescript/module/client/walletChoiceGuard.d.ts +4 -0
- package/lib/typescript/module/client/walletChoiceGuard.d.ts.map +1 -0
- package/lib/typescript/module/client/webResultCategory.d.ts +5 -0
- package/lib/typescript/module/client/webResultCategory.d.ts.map +1 -0
- package/lib/typescript/module/commercial/AccountStore.d.ts +17 -0
- package/lib/typescript/module/commercial/AccountStore.d.ts.map +1 -0
- package/lib/typescript/module/commercial/AgentDebug.d.ts +25 -0
- package/lib/typescript/module/commercial/AgentDebug.d.ts.map +1 -0
- package/lib/typescript/module/commercial/ExecutionGuard.d.ts +18 -0
- package/lib/typescript/module/commercial/ExecutionGuard.d.ts.map +1 -0
- package/lib/typescript/module/commercial/UsageBus.d.ts +18 -0
- package/lib/typescript/module/commercial/UsageBus.d.ts.map +1 -0
- package/lib/typescript/module/commercial/branding.d.ts +25 -0
- package/lib/typescript/module/commercial/branding.d.ts.map +1 -0
- package/lib/typescript/module/commercial/devMode.d.ts +26 -0
- package/lib/typescript/module/commercial/devMode.d.ts.map +1 -0
- package/lib/typescript/module/commercial/trust.d.ts +21 -0
- package/lib/typescript/module/commercial/trust.d.ts.map +1 -0
- package/lib/typescript/module/confirmation/gate.d.ts +18 -0
- package/lib/typescript/module/confirmation/gate.d.ts.map +1 -0
- package/lib/typescript/module/cursor/CursorOverlay.d.ts +13 -0
- package/lib/typescript/module/cursor/CursorOverlay.d.ts.map +1 -0
- package/lib/typescript/module/cursor/PointerHand.d.ts +16 -0
- package/lib/typescript/module/cursor/PointerHand.d.ts.map +1 -0
- package/lib/typescript/module/cursor/controller.d.ts +30 -0
- package/lib/typescript/module/cursor/controller.d.ts.map +1 -0
- package/lib/typescript/module/cursor/pointer.d.ts +23 -0
- package/lib/typescript/module/cursor/pointer.d.ts.map +1 -0
- package/lib/typescript/module/debug/KokoRemoteSmoke.d.ts +96 -0
- package/lib/typescript/module/debug/KokoRemoteSmoke.d.ts.map +1 -0
- package/lib/typescript/module/explore/ExplorationGraph.d.ts +96 -0
- package/lib/typescript/module/explore/ExplorationGraph.d.ts.map +1 -0
- package/lib/typescript/module/explore/bootstrapExplore.d.ts +40 -0
- package/lib/typescript/module/explore/bootstrapExplore.d.ts.map +1 -0
- package/lib/typescript/module/host/HostActions.d.ts +101 -0
- package/lib/typescript/module/host/HostActions.d.ts.map +1 -0
- package/lib/typescript/module/i18n/index.d.ts +20 -0
- package/lib/typescript/module/i18n/index.d.ts.map +1 -0
- package/lib/typescript/module/i18n/runtimeMessages.d.ts +178 -0
- package/lib/typescript/module/i18n/runtimeMessages.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +66 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/native/NativeBridge.d.ts +70 -0
- package/lib/typescript/module/native/NativeBridge.d.ts.map +1 -0
- package/lib/typescript/module/native/navigationLabel.d.ts +4 -0
- package/lib/typescript/module/native/navigationLabel.d.ts.map +1 -0
- package/lib/typescript/module/native/normalizeViewTree.d.ts +4 -0
- package/lib/typescript/module/native/normalizeViewTree.d.ts.map +1 -0
- package/lib/typescript/module/native/pruneOffscreen.d.ts +3 -0
- package/lib/typescript/module/native/pruneOffscreen.d.ts.map +1 -0
- package/lib/typescript/module/native/scrollViewport.d.ts +13 -0
- package/lib/typescript/module/native/scrollViewport.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/privacy/redact.d.ts +9 -0
- package/lib/typescript/module/privacy/redact.d.ts.map +1 -0
- package/lib/typescript/module/privacy/screenEvidence.d.ts +14 -0
- package/lib/typescript/module/privacy/screenEvidence.d.ts.map +1 -0
- package/lib/typescript/module/privacy/screenModel.d.ts +26 -0
- package/lib/typescript/module/privacy/screenModel.d.ts.map +1 -0
- package/lib/typescript/module/privacy/sensitiveScreen.d.ts +8 -0
- package/lib/typescript/module/privacy/sensitiveScreen.d.ts.map +1 -0
- package/lib/typescript/module/privacy/userGate.d.ts +58 -0
- package/lib/typescript/module/privacy/userGate.d.ts.map +1 -0
- package/lib/typescript/module/protocol/actions.d.ts +7 -0
- package/lib/typescript/module/protocol/actions.d.ts.map +1 -0
- package/lib/typescript/module/provider/HostAppearanceStore.d.ts +64 -0
- package/lib/typescript/module/provider/HostAppearanceStore.d.ts.map +1 -0
- package/lib/typescript/module/provider/KokoProvider.d.ts +39 -0
- package/lib/typescript/module/provider/KokoProvider.d.ts.map +1 -0
- package/lib/typescript/module/provider/KokoUiContext.d.ts +22 -0
- package/lib/typescript/module/provider/KokoUiContext.d.ts.map +1 -0
- package/lib/typescript/module/selector/match.d.ts +27 -0
- package/lib/typescript/module/selector/match.d.ts.map +1 -0
- package/lib/typescript/module/task/TaskStore.d.ts +65 -0
- package/lib/typescript/module/task/TaskStore.d.ts.map +1 -0
- package/lib/typescript/module/task/types.d.ts +66 -0
- package/lib/typescript/module/task/types.d.ts.map +1 -0
- package/lib/typescript/module/task/useTaskStore.d.ts +3 -0
- package/lib/typescript/module/task/useTaskStore.d.ts.map +1 -0
- package/lib/typescript/module/types.d.ts +372 -0
- package/lib/typescript/module/types.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoChatSheet.d.ts +8 -0
- package/lib/typescript/module/ui/KokoChatSheet.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoComposer.d.ts +13 -0
- package/lib/typescript/module/ui/KokoComposer.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoDialogHost.d.ts +32 -0
- package/lib/typescript/module/ui/KokoDialogHost.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoEntryButton.d.ts +18 -0
- package/lib/typescript/module/ui/KokoEntryButton.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoObserver.d.ts +13 -0
- package/lib/typescript/module/ui/KokoObserver.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoOverlayLayer.d.ts +35 -0
- package/lib/typescript/module/ui/KokoOverlayLayer.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoSubtitle.d.ts +7 -0
- package/lib/typescript/module/ui/KokoSubtitle.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoTaskPanel.d.ts +7 -0
- package/lib/typescript/module/ui/KokoTaskPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/hostOverlay.d.ts +28 -0
- package/lib/typescript/module/ui/hostOverlay.d.ts.map +1 -0
- package/lib/typescript/module/ui/icons.d.ts +26 -0
- package/lib/typescript/module/ui/icons.d.ts.map +1 -0
- package/lib/typescript/module/ui/progressChrome.d.ts +21 -0
- package/lib/typescript/module/ui/progressChrome.d.ts.map +1 -0
- package/lib/typescript/module/ui/safeArea.d.ts +12 -0
- package/lib/typescript/module/ui/safeArea.d.ts.map +1 -0
- package/lib/typescript/module/ui/useOverlayOrigin.d.ts +22 -0
- package/lib/typescript/module/ui/useOverlayOrigin.d.ts.map +1 -0
- package/package.json +153 -0
- package/react-native.config.js +12 -0
- package/src/KokoAgent.ts +1415 -0
- package/src/assist/OnDeviceAssist.ts +133 -0
- package/src/assist/intentClassify.ts +122 -0
- package/src/assist/nodeRank.ts +167 -0
- package/src/assist/ocrTarget.ts +146 -0
- package/src/assist/webVisualChange.ts +24 -0
- package/src/client/ActionOutcomeUnknownError.ts +18 -0
- package/src/client/AgentSession.ts +952 -0
- package/src/client/GatewayClient.ts +439 -0
- package/src/client/OperationReplayGuard.ts +61 -0
- package/src/client/RunCheckpoint.ts +154 -0
- package/src/client/loopDetect.ts +213 -0
- package/src/client/recentSearch.ts +47 -0
- package/src/client/walletChoiceGuard.ts +15 -0
- package/src/client/webResultCategory.ts +28 -0
- package/src/commercial/AccountStore.ts +85 -0
- package/src/commercial/AgentDebug.ts +142 -0
- package/src/commercial/ExecutionGuard.ts +67 -0
- package/src/commercial/UsageBus.ts +44 -0
- package/src/commercial/branding.ts +97 -0
- package/src/commercial/devMode.ts +48 -0
- package/src/commercial/trust.ts +67 -0
- package/src/confirmation/gate.ts +82 -0
- package/src/cursor/CursorOverlay.tsx +138 -0
- package/src/cursor/PointerHand.tsx +49 -0
- package/src/cursor/controller.ts +98 -0
- package/src/cursor/pointer.ts +40 -0
- package/src/debug/KokoRemoteSmoke.tsx +561 -0
- package/src/explore/ExplorationGraph.ts +518 -0
- package/src/explore/bootstrapExplore.ts +89 -0
- package/src/host/HostActions.ts +349 -0
- package/src/i18n/index.ts +229 -0
- package/src/i18n/runtimeMessages.ts +180 -0
- package/src/index.ts +203 -0
- package/src/native/NativeBridge.ts +207 -0
- package/src/native/navigationLabel.ts +11 -0
- package/src/native/normalizeViewTree.ts +16 -0
- package/src/native/pruneOffscreen.ts +72 -0
- package/src/native/scrollViewport.ts +51 -0
- package/src/privacy/redact.ts +115 -0
- package/src/privacy/screenEvidence.ts +55 -0
- package/src/privacy/screenModel.ts +504 -0
- package/src/privacy/sensitiveScreen.ts +55 -0
- package/src/privacy/userGate.ts +233 -0
- package/src/protocol/actions.ts +66 -0
- package/src/provider/HostAppearanceStore.ts +148 -0
- package/src/provider/KokoProvider.tsx +118 -0
- package/src/provider/KokoUiContext.tsx +162 -0
- package/src/selector/match.ts +417 -0
- package/src/task/TaskStore.ts +387 -0
- package/src/task/types.ts +82 -0
- package/src/task/useTaskStore.ts +9 -0
- package/src/types.ts +318 -0
- package/src/ui/KokoChatSheet.tsx +930 -0
- package/src/ui/KokoComposer.tsx +174 -0
- package/src/ui/KokoDialogHost.tsx +249 -0
- package/src/ui/KokoEntryButton.tsx +74 -0
- package/src/ui/KokoObserver.tsx +587 -0
- package/src/ui/KokoOverlayLayer.tsx +53 -0
- package/src/ui/KokoSubtitle.tsx +80 -0
- package/src/ui/KokoTaskPanel.tsx +299 -0
- package/src/ui/hostOverlay.tsx +148 -0
- package/src/ui/icons.tsx +145 -0
- package/src/ui/progressChrome.ts +73 -0
- package/src/ui/safeArea.ts +95 -0
- package/src/ui/useOverlayOrigin.ts +29 -0
|
@@ -0,0 +1,1427 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.KokoAgent = void 0;
|
|
7
|
+
exports.getKokoAgent = getKokoAgent;
|
|
8
|
+
exports.initKokoAgent = initKokoAgent;
|
|
9
|
+
var _reactNative = require("react-native");
|
|
10
|
+
var _controller = require("./cursor/controller.js");
|
|
11
|
+
var _gate = require("./confirmation/gate.js");
|
|
12
|
+
var _NativeBridge = require("./native/NativeBridge.js");
|
|
13
|
+
var _actions = require("./protocol/actions.js");
|
|
14
|
+
var _match = require("./selector/match.js");
|
|
15
|
+
var _sensitiveScreen = require("./privacy/sensitiveScreen.js");
|
|
16
|
+
var _scrollViewport = require("./native/scrollViewport.js");
|
|
17
|
+
var _HostActions = require("./host/HostActions.js");
|
|
18
|
+
var _screenModel = require("./privacy/screenModel.js");
|
|
19
|
+
var _TaskStore = require("./task/TaskStore.js");
|
|
20
|
+
var _AgentSession = require("./client/AgentSession.js");
|
|
21
|
+
var _RunCheckpoint = require("./client/RunCheckpoint.js");
|
|
22
|
+
var _ActionOutcomeUnknownError = require("./client/ActionOutcomeUnknownError.js");
|
|
23
|
+
var _ExplorationGraph = require("./explore/ExplorationGraph.js");
|
|
24
|
+
var _KokoDialogHost = require("./ui/KokoDialogHost.js");
|
|
25
|
+
var _progressChrome = require("./ui/progressChrome.js");
|
|
26
|
+
var _UsageBus = require("./commercial/UsageBus.js");
|
|
27
|
+
var _AccountStore = require("./commercial/AccountStore.js");
|
|
28
|
+
var _ExecutionGuard = require("./commercial/ExecutionGuard.js");
|
|
29
|
+
var _AgentDebug = require("./commercial/AgentDebug.js");
|
|
30
|
+
var _index = require("./i18n/index.js");
|
|
31
|
+
var _ocrTarget = require("./assist/ocrTarget.js");
|
|
32
|
+
var cache;
|
|
33
|
+
function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
|
|
34
|
+
/**
|
|
35
|
+
* Koko Agent SDK runtime — dump / find / tap / swipe / pinch / type + cursor + confirm gate + task log.
|
|
36
|
+
*/
|
|
37
|
+
class KokoAgent {
|
|
38
|
+
lastTree = null;
|
|
39
|
+
planningTree = null;
|
|
40
|
+
// OCR ids are local references to observed text, never caller-supplied points.
|
|
41
|
+
ocrTargets = new Map();
|
|
42
|
+
nextOcrTargetId = 0;
|
|
43
|
+
/** Labels already confirmed in the current runGoal — avoid repeat dialogs on retry. */
|
|
44
|
+
confirmedSensitive = new Set();
|
|
45
|
+
/** Last tap used a host `run` callback (tab/CTA) — skip false tap_noop. */
|
|
46
|
+
lastTapViaHost = null;
|
|
47
|
+
/** Current NL goal; direct SDK callers may opt into visible scroll search. */
|
|
48
|
+
|
|
49
|
+
constructor(config = {}) {
|
|
50
|
+
this.config = {
|
|
51
|
+
dumpMaxDepth: 80,
|
|
52
|
+
dumpSkipInvisible: true,
|
|
53
|
+
cursorDurationMs: 480,
|
|
54
|
+
observer: true,
|
|
55
|
+
...config,
|
|
56
|
+
confirmation: {
|
|
57
|
+
requireUserConfirm: true,
|
|
58
|
+
mode: 'preflight',
|
|
59
|
+
...config.confirmation
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (!this.config.onConfirmSensitive) {
|
|
63
|
+
this.config.onConfirmSensitive = async ctx => {
|
|
64
|
+
const locale = (0, _index.currentLocale)(this.config.locale);
|
|
65
|
+
const label = ctx.label ?? ctx.action;
|
|
66
|
+
return _KokoDialogHost.DialogBus.requestConfirm(ctx.action === 'preflight' ? (0, _index.t)(locale, 'confirm.preflightTitle') : (0, _index.t)(locale, 'confirm.inlineTitle'), ctx.action === 'preflight' ? (0, _index.t)(locale, 'confirm.preflightBody', {
|
|
67
|
+
label
|
|
68
|
+
}) : (0, _index.t)(locale, 'confirm.inlineBody', {
|
|
69
|
+
label
|
|
70
|
+
}));
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
configure(patch) {
|
|
75
|
+
this.config = {
|
|
76
|
+
...this.config,
|
|
77
|
+
...patch
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
getConfig() {
|
|
81
|
+
return this.config;
|
|
82
|
+
}
|
|
83
|
+
message(key, vars) {
|
|
84
|
+
return (0, _index.message)(key, vars, this.config.locale);
|
|
85
|
+
}
|
|
86
|
+
text(key, vars) {
|
|
87
|
+
return (0, _index.runtimeText)(key, vars, this.config.locale);
|
|
88
|
+
}
|
|
89
|
+
isNativeReady() {
|
|
90
|
+
return _NativeBridge.NativeBridge.isAvailable();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Start a user-facing task (shows subtitle + appears in panel). */
|
|
94
|
+
startTask(title) {
|
|
95
|
+
this.confirmedSensitive.clear();
|
|
96
|
+
this.ocrTargets.clear();
|
|
97
|
+
this.planningTree = null;
|
|
98
|
+
const task = _TaskStore.TaskStore.startTask(title);
|
|
99
|
+
_UsageBus.UsageBus.emit({
|
|
100
|
+
type: 'task_started',
|
|
101
|
+
taskId: task.id,
|
|
102
|
+
goal: title,
|
|
103
|
+
at: Date.now()
|
|
104
|
+
});
|
|
105
|
+
return task;
|
|
106
|
+
}
|
|
107
|
+
finishTask(status = 'success', summary) {
|
|
108
|
+
this.confirmedSensitive.clear();
|
|
109
|
+
_controller.CursorController.hide();
|
|
110
|
+
const snap = _TaskStore.TaskStore.snapshot();
|
|
111
|
+
const active = snap.tasks.find(t => t.id === snap.activeTaskId);
|
|
112
|
+
_TaskStore.TaskStore.finishTask(status, undefined, summary);
|
|
113
|
+
_UsageBus.UsageBus.emit({
|
|
114
|
+
type: 'task_finished',
|
|
115
|
+
taskId: active?.id,
|
|
116
|
+
status,
|
|
117
|
+
steps: active?.nodes?.length,
|
|
118
|
+
at: Date.now()
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Manually append an observer log node (for cloud agent narration). */
|
|
123
|
+
log(kind, title, detail) {
|
|
124
|
+
if (this.config.observer === false) return null;
|
|
125
|
+
return _TaskStore.TaskStore.appendNode({
|
|
126
|
+
kind,
|
|
127
|
+
title,
|
|
128
|
+
detail,
|
|
129
|
+
status: 'done'
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Open a cloud-backed agent session (official gateway; LLM vendor is server-side). */
|
|
134
|
+
createSession(opts) {
|
|
135
|
+
return new _AgentSession.AgentSession(this, {
|
|
136
|
+
...opts,
|
|
137
|
+
onAskUser: opts.onAskUser ?? (q => _KokoDialogHost.DialogBus.requestAsk(q))
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* One-shot: talk to official gateway → local dump/find/tap until done.
|
|
143
|
+
* Users never supply model API keys. Token comes from opts or KokoProvider config.gateway.
|
|
144
|
+
*/
|
|
145
|
+
activeSession = null;
|
|
146
|
+
executionEpoch = 0;
|
|
147
|
+
claimingCheckpoint = false;
|
|
148
|
+
|
|
149
|
+
/** @internal Sessions created through createSession share runGoal's owner. */
|
|
150
|
+
acquireSession(session) {
|
|
151
|
+
if (this.activeSession && this.activeSession !== session || this.claimingCheckpoint) {
|
|
152
|
+
throw new Error((0, _index.runtimeText)('runtime.alreadyRunning', undefined, this.config?.locale));
|
|
153
|
+
}
|
|
154
|
+
const acquired = !this.activeSession;
|
|
155
|
+
this.activeSession = session;
|
|
156
|
+
return acquired;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** @internal Release only an owner acquired by a direct session.run(). */
|
|
160
|
+
releaseSession(session) {
|
|
161
|
+
if (this.activeSession === session) this.activeSession = null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** @internal Invalidates gestures already waiting on confirmation/animation. */
|
|
165
|
+
cancelPendingActions() {
|
|
166
|
+
this.executionEpoch++;
|
|
167
|
+
_controller.CursorController.hide();
|
|
168
|
+
}
|
|
169
|
+
assertExecutionCurrent(epoch) {
|
|
170
|
+
if (epoch !== this.executionEpoch) throw new Error('KokoAgent: task cancelled');
|
|
171
|
+
}
|
|
172
|
+
async runGoal(goal, opts) {
|
|
173
|
+
if (this.activeSession || this.claimingCheckpoint) {
|
|
174
|
+
throw new Error((0, _index.runtimeText)('runtime.alreadyRunning', undefined, this.config?.locale));
|
|
175
|
+
}
|
|
176
|
+
const token = opts?.token ?? this.config.gateway?.token;
|
|
177
|
+
if (!token) {
|
|
178
|
+
throw new Error(this.text('runtime.missingToken'));
|
|
179
|
+
}
|
|
180
|
+
const baseUrl = opts?.baseUrl ?? this.config.gateway?.baseUrl;
|
|
181
|
+
const locale = (0, _index.gatewayLocale)((0, _index.currentLocale)(opts?.locale ?? this.config.locale));
|
|
182
|
+
void _AccountStore.AccountStore.refresh({
|
|
183
|
+
token,
|
|
184
|
+
baseUrl
|
|
185
|
+
});
|
|
186
|
+
const session = this.createSession({
|
|
187
|
+
locale,
|
|
188
|
+
resumedFromReload: (opts?.resumes ?? 0) > 0,
|
|
189
|
+
localRetries: opts?.localRetries,
|
|
190
|
+
userGateTimeoutMs: opts?.userGateTimeoutMs,
|
|
191
|
+
onAskUser: opts?.onAskUser,
|
|
192
|
+
onNarration: opts?.onNarration,
|
|
193
|
+
baseUrl,
|
|
194
|
+
token
|
|
195
|
+
});
|
|
196
|
+
this.activeSession = session;
|
|
197
|
+
// An action can take down the context running it (locale/theme/RTL change,
|
|
198
|
+
// feature-flag remount). Persist the goal so the next init can resume it;
|
|
199
|
+
// see RunCheckpoint. Never let storage trouble block a run.
|
|
200
|
+
try {
|
|
201
|
+
await _RunCheckpoint.RunCheckpoint.begin(goal, opts?.resumes ?? 0).catch(() => {});
|
|
202
|
+
return await session.run(goal);
|
|
203
|
+
} finally {
|
|
204
|
+
// Keep ownership until cleanup settles; stop() must not let a second run
|
|
205
|
+
// overlap an outstanding gateway response or pending native gesture.
|
|
206
|
+
await _RunCheckpoint.RunCheckpoint.clear().catch(() => {});
|
|
207
|
+
if (this.activeSession === session) this.activeSession = null;
|
|
208
|
+
void _AccountStore.AccountStore.refresh({
|
|
209
|
+
token,
|
|
210
|
+
baseUrl
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Pick up a run that a JS-context restart interrupted, if any.
|
|
217
|
+
*
|
|
218
|
+
* Called once per init by KokoProvider. Resolves to the resumed goal, or null
|
|
219
|
+
* when there was nothing fresh to resume. The planner decides what is left to
|
|
220
|
+
* do from the screen the App came back on — if the goal already happened, it
|
|
221
|
+
* answers `done` without touching anything.
|
|
222
|
+
*/
|
|
223
|
+
async resumeInterruptedRun() {
|
|
224
|
+
if (this.activeSession || this.claimingCheckpoint) return null;
|
|
225
|
+
this.claimingCheckpoint = true;
|
|
226
|
+
const epoch = this.executionEpoch;
|
|
227
|
+
let pending;
|
|
228
|
+
try {
|
|
229
|
+
pending = await _RunCheckpoint.RunCheckpoint.claimResumable().catch(() => null);
|
|
230
|
+
} finally {
|
|
231
|
+
this.claimingCheckpoint = false;
|
|
232
|
+
}
|
|
233
|
+
if (!pending || epoch !== this.executionEpoch) return null;
|
|
234
|
+
try {
|
|
235
|
+
await this.runGoal(pending.goal, {
|
|
236
|
+
resumes: pending.resumes + 1
|
|
237
|
+
});
|
|
238
|
+
} catch {
|
|
239
|
+
// A resume is best-effort; a failure here must not break host startup.
|
|
240
|
+
}
|
|
241
|
+
return pending.goal;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* On-device exploration crawl — builds a local screen/transition graph
|
|
246
|
+
* without a host feature tree. Safe-ish (skips sensitive labels). Call
|
|
247
|
+
* after SDK init / on a debug build; then runGoal can reuse the graph.
|
|
248
|
+
*/
|
|
249
|
+
async bootstrapExplore(opts) {
|
|
250
|
+
const {
|
|
251
|
+
bootstrapExplore
|
|
252
|
+
} = await Promise.resolve().then(() => _interopRequireWildcard(require('./explore/bootstrapExplore')));
|
|
253
|
+
return bootstrapExplore(this, opts);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Snapshot of the on-device exploration graph (nodes/edges). */
|
|
257
|
+
getExplorationGraph() {
|
|
258
|
+
return _ExplorationGraph.ExplorationGraph.snapshot();
|
|
259
|
+
}
|
|
260
|
+
clearExplorationGraph() {
|
|
261
|
+
_ExplorationGraph.ExplorationGraph.clear();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Refresh plan / quota / entitlements from gateway. */
|
|
265
|
+
async refreshAccount() {
|
|
266
|
+
const token = this.config.gateway?.token;
|
|
267
|
+
if (!token) return null;
|
|
268
|
+
return _AccountStore.AccountStore.refresh({
|
|
269
|
+
token,
|
|
270
|
+
baseUrl: this.config.gateway?.baseUrl
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
getAccount() {
|
|
274
|
+
return _AccountStore.AccountStore.get();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Stop the in-flight runGoal / session, if any. */
|
|
278
|
+
stop() {
|
|
279
|
+
if (this.activeSession) this.activeSession.stop();else this.cancelPendingActions();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Open chat sheet (history + NL input) from host UI. */
|
|
283
|
+
openChat(taskId) {
|
|
284
|
+
_TaskStore.TaskStore.openSheet(taskId);
|
|
285
|
+
}
|
|
286
|
+
closeChat() {
|
|
287
|
+
_TaskStore.TaskStore.closeSheet();
|
|
288
|
+
}
|
|
289
|
+
getTaskStore() {
|
|
290
|
+
return _TaskStore.TaskStore;
|
|
291
|
+
}
|
|
292
|
+
async dump(options) {
|
|
293
|
+
_ExecutionGuard.ExecutionGuard.assert('dump');
|
|
294
|
+
// Sheet Modal lives in another window and blocks host; close before scan.
|
|
295
|
+
if (_TaskStore.TaskStore.snapshot().ui.sheetOpen) {
|
|
296
|
+
_TaskStore.TaskStore.closeSheet();
|
|
297
|
+
// Host apps (OneKey) freezeOnBlur — need a beat to remount Empty states.
|
|
298
|
+
await sleep(480);
|
|
299
|
+
}
|
|
300
|
+
const silent = options?.silent === true;
|
|
301
|
+
const node = silent ? {
|
|
302
|
+
id: ''
|
|
303
|
+
} : this.track('dump', this.message('runtime.scan'));
|
|
304
|
+
try {
|
|
305
|
+
const tree = await _NativeBridge.NativeBridge.dump({
|
|
306
|
+
maxDepth: options?.maxDepth ?? this.config.dumpMaxDepth,
|
|
307
|
+
skipInvisible: options?.skipInvisible ?? this.config.dumpSkipInvisible
|
|
308
|
+
});
|
|
309
|
+
this.lastTree = tree;
|
|
310
|
+
this.warnIfDepthCapped(tree, options?.maxDepth ?? this.config.dumpMaxDepth ?? 0);
|
|
311
|
+
if (!silent) this.done(node, this.message('runtime.scanned'));
|
|
312
|
+
return tree;
|
|
313
|
+
} catch (e) {
|
|
314
|
+
if (!silent) this.fail(node, e);
|
|
315
|
+
throw e;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Screenshot the host app. By default hides Koko overlay layers
|
|
321
|
+
* (progress / cursor / sheet) so the image matches what dump sees.
|
|
322
|
+
*/
|
|
323
|
+
async screenshot(options) {
|
|
324
|
+
_ExecutionGuard.ExecutionGuard.assert('screenshot');
|
|
325
|
+
return _NativeBridge.NativeBridge.screenshot({
|
|
326
|
+
hideOverlays: options?.hideOverlays ?? true
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
getLastTree() {
|
|
330
|
+
return this.lastTree;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** @internal Return a locally observed OCR label for validating a planned action. */
|
|
334
|
+
observedOcrLabel(nodeId) {
|
|
335
|
+
return nodeId ? this.ocrTargets.get(nodeId)?.text : undefined;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/** @internal Pin the screen whose node ids the planner is about to see. */
|
|
339
|
+
setPlanningTree(tree) {
|
|
340
|
+
this.planningTree = tree;
|
|
341
|
+
}
|
|
342
|
+
async find(selector, tree) {
|
|
343
|
+
const wantedLabel = selectorLabel(selector);
|
|
344
|
+
const label = wantedLabel ?? this.text('runtime.element');
|
|
345
|
+
const node = this.track('find', this.message('runtime.find', {
|
|
346
|
+
label
|
|
347
|
+
}));
|
|
348
|
+
try {
|
|
349
|
+
const root = tree ?? (await this.dump({
|
|
350
|
+
silent: true
|
|
351
|
+
}));
|
|
352
|
+
if ((0, _sensitiveScreen.sensitiveScreenKind)(root)) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.privateStep'));
|
|
353
|
+
let hit = (0, _match.find)(root, selector);
|
|
354
|
+
// OCR can confirm only a unique visible text label. It cannot prove an
|
|
355
|
+
// index, nearby context, element type, or actual clickability.
|
|
356
|
+
const ocrEligible = selector.match.length === 1 && ('text' in selector.match[0] || 'accessibilityLabel' in selector.match[0]) && (selector.index === undefined || selector.index === 0);
|
|
357
|
+
if (!hit && !!wantedLabel && ocrEligible && _NativeBridge.NativeBridge.isAvailable()) {
|
|
358
|
+
try {
|
|
359
|
+
const ocr = await _NativeBridge.NativeBridge.recognizeScreenText({
|
|
360
|
+
maxTokens: 32,
|
|
361
|
+
hideOverlays: true
|
|
362
|
+
});
|
|
363
|
+
const directHit = (0, _ocrTarget.findOcrTextHit)(ocr.texts || [], label);
|
|
364
|
+
const textHit = directHit || (0, _ocrTarget.findOcrTextHit)(ocr.texts || [], label, {
|
|
365
|
+
translatedWebRegions: (0, _ocrTarget.visibleWebViewFrames)(root)
|
|
366
|
+
});
|
|
367
|
+
if (textHit?.frame) {
|
|
368
|
+
const f = textHit.frame;
|
|
369
|
+
// The id carries no coordinates. A later tap must recognize this
|
|
370
|
+
// text again and use its current frame rather than this snapshot.
|
|
371
|
+
const id = `ocr:local-${++this.nextOcrTargetId}`;
|
|
372
|
+
this.ocrTargets.set(id, {
|
|
373
|
+
text: textHit.text,
|
|
374
|
+
webview: !directHit
|
|
375
|
+
});
|
|
376
|
+
if (this.ocrTargets.size > 32) this.ocrTargets.delete(this.ocrTargets.keys().next().value);
|
|
377
|
+
hit = {
|
|
378
|
+
id,
|
|
379
|
+
type: 'KokoOcrText',
|
|
380
|
+
frame: f,
|
|
381
|
+
// Only return the requested label, not arbitrary OCR screen text.
|
|
382
|
+
// Raw OCR remains on-device even if a webpage contains secrets.
|
|
383
|
+
text: label,
|
|
384
|
+
clickable: true,
|
|
385
|
+
enabled: true,
|
|
386
|
+
visible: true,
|
|
387
|
+
children: []
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
} catch {
|
|
391
|
+
// OCR is optional; a normal miss remains a normal miss.
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
if (!hit && !tree && this.activeGoal) {
|
|
395
|
+
hit = await this.revealVisibleTarget(selector, wantedLabel || undefined);
|
|
396
|
+
}
|
|
397
|
+
this.done(node, this.message(hit ? 'runtime.found' : 'runtime.notFound', {
|
|
398
|
+
label
|
|
399
|
+
}), hit ? hit.id : undefined);
|
|
400
|
+
return hit;
|
|
401
|
+
} catch (e) {
|
|
402
|
+
this.fail(node, e);
|
|
403
|
+
throw e;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
async findAll(selector, tree) {
|
|
407
|
+
const root = tree ?? this.lastTree ?? (await this.dump({
|
|
408
|
+
silent: true
|
|
409
|
+
}));
|
|
410
|
+
return (0, _match.findAll)(root, selector);
|
|
411
|
+
}
|
|
412
|
+
async tap(target) {
|
|
413
|
+
const epoch = this.executionEpoch;
|
|
414
|
+
const assertCurrent = () => this.assertExecutionCurrent(epoch);
|
|
415
|
+
_ExecutionGuard.ExecutionGuard.assert('tap');
|
|
416
|
+
if ((0, _sensitiveScreen.sensitiveScreenKind)(await _NativeBridge.NativeBridge.dump())) {
|
|
417
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.privateStep'));
|
|
418
|
+
}
|
|
419
|
+
assertCurrent();
|
|
420
|
+
this.lastTapViaHost = null;
|
|
421
|
+
let label = target.label ?? selectorLabel(target.selector) ?? this.text('runtime.target');
|
|
422
|
+
let hostHit = target.nodeId || target.point ? undefined : _HostActions.HostActionsStore.findForTap({
|
|
423
|
+
label,
|
|
424
|
+
text: selectorLabel(target.selector),
|
|
425
|
+
testID: selectorTestID(target.selector)
|
|
426
|
+
});
|
|
427
|
+
// Planner often taps dump nodeId of a native tab label; resolve copy then
|
|
428
|
+
// match host run (geometric hit-test on UITabBar is unreliable).
|
|
429
|
+
let preresolved = null;
|
|
430
|
+
if (!hostHit?.run) {
|
|
431
|
+
try {
|
|
432
|
+
preresolved = await this.resolveNode(target);
|
|
433
|
+
const nodeLabel = (preresolved?.text || preresolved?.accessibilityLabel || '').trim();
|
|
434
|
+
if (nodeLabel) {
|
|
435
|
+
const byNode = _HostActions.HostActionsStore.findForTap({
|
|
436
|
+
label: nodeLabel,
|
|
437
|
+
text: nodeLabel,
|
|
438
|
+
testID: preresolved?.testID
|
|
439
|
+
});
|
|
440
|
+
if (byNode?.run) {
|
|
441
|
+
hostHit = byNode;
|
|
442
|
+
label = nodeLabel;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} catch {
|
|
446
|
+
// Geometric path will surface the same resolve error.
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
assertCurrent();
|
|
450
|
+
// Host callbacks use the same visibility and confirmation guards as taps.
|
|
451
|
+
if (hostHit?.run) {
|
|
452
|
+
assertCurrent();
|
|
453
|
+
// A host callback is not permission to activate a mounted but hidden row.
|
|
454
|
+
const visible = preresolved ?? (target.options?.revealIfNeeded === false ? (0, _match.find)(await this.dump({
|
|
455
|
+
silent: true
|
|
456
|
+
}), target.selector || {
|
|
457
|
+
match: [{
|
|
458
|
+
text: hostHit.text || hostHit.label
|
|
459
|
+
}]
|
|
460
|
+
}, tapFindOptions(target)) : await this.revealVisibleTarget(target.selector || {
|
|
461
|
+
match: [{
|
|
462
|
+
text: hostHit.text || hostHit.label
|
|
463
|
+
}]
|
|
464
|
+
}, hostHit.text || hostHit.label, tapFindOptions(target).preferNonInput));
|
|
465
|
+
if (visible) preresolved = visible;
|
|
466
|
+
if (!visible || !(0, _HostActions.canRunHostActionForNode)(hostHit, visible, this.lastTree)) hostHit = undefined;
|
|
467
|
+
}
|
|
468
|
+
if (hostHit?.run) {
|
|
469
|
+
const node = this.track('tap', this.message('runtime.tap', {
|
|
470
|
+
label
|
|
471
|
+
}));
|
|
472
|
+
try {
|
|
473
|
+
const confirmKey = `tap:${label}`;
|
|
474
|
+
if (!this.confirmedSensitive.has(confirmKey)) {
|
|
475
|
+
const allowed = await (0, _gate.runConfirmationGate)({
|
|
476
|
+
action: 'tap',
|
|
477
|
+
label,
|
|
478
|
+
selector: target.selector
|
|
479
|
+
}, this.config.confirmation, this.config.onConfirmSensitive);
|
|
480
|
+
assertCurrent();
|
|
481
|
+
if (!allowed) {
|
|
482
|
+
_TaskStore.TaskStore.updateNode(node.id, {
|
|
483
|
+
status: 'failed',
|
|
484
|
+
title: this.message('runtime.confirmBlocked', {
|
|
485
|
+
label
|
|
486
|
+
})
|
|
487
|
+
});
|
|
488
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.confirmationRequired'));
|
|
489
|
+
}
|
|
490
|
+
if ((0, _gate.isSensitiveLabel)(label, this.config.confirmation)) {
|
|
491
|
+
this.confirmedSensitive.add(confirmKey);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const silent = target.options?.silent;
|
|
495
|
+
const beforeSnap = await this.snapshotLine(true);
|
|
496
|
+
const duration = target.options?.cursorDurationMs ?? this.config.cursorDurationMs ?? 320;
|
|
497
|
+
const spot = await this.hostActionPoint(target, preresolved);
|
|
498
|
+
if (!silent) {
|
|
499
|
+
if (spot) {
|
|
500
|
+
assertCurrent();
|
|
501
|
+
await _controller.CursorController.moveTo(spot.x, spot.y, duration);
|
|
502
|
+
assertCurrent();
|
|
503
|
+
_controller.CursorController.setPressing(true);
|
|
504
|
+
await sleep(40);
|
|
505
|
+
} else {
|
|
506
|
+
_controller.CursorController.hide();
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
try {
|
|
510
|
+
if (!spot) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.hostTargetMissing'));
|
|
511
|
+
await this.assertTapTargetCurrent(target, spot, preresolved);
|
|
512
|
+
assertCurrent();
|
|
513
|
+
if (!(await (0, _HostActions.runHostAction)(hostHit.run))) {
|
|
514
|
+
throw new _ActionOutcomeUnknownError.ActionOutcomeUnknownError(`host action for ${label} did not settle`);
|
|
515
|
+
}
|
|
516
|
+
} finally {
|
|
517
|
+
if (!silent) {
|
|
518
|
+
await sleep(120);
|
|
519
|
+
_controller.CursorController.setPressing(false);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// One-shot CTAs: drop so the next screen is not poisoned.
|
|
523
|
+
// Tabs / persistent chrome keep `oneshot: false`.
|
|
524
|
+
if (hostHit.oneshot !== false) {
|
|
525
|
+
_HostActions.HostActionsStore.unregisterAction(hostHit.id);
|
|
526
|
+
}
|
|
527
|
+
// Navigation / root reset needs a beat before dump.
|
|
528
|
+
await sleep(hostHit.kind === 'tab' ? 700 : 900);
|
|
529
|
+
assertCurrent();
|
|
530
|
+
// Observe the result, but never turn an uncertain callback into a
|
|
531
|
+
// second coordinate tap: async work may already have committed.
|
|
532
|
+
if (beforeSnap && (await this.snapshotLine()) === beforeSnap) {
|
|
533
|
+
this.lastTapViaHost = null;
|
|
534
|
+
// A resolved callback may already have submitted async work. An
|
|
535
|
+
// unchanged screen does not prove it is safe to perform it again.
|
|
536
|
+
throw new _ActionOutcomeUnknownError.ActionOutcomeUnknownError(`host action for ${label} is unverified; not replayed`);
|
|
537
|
+
} else {
|
|
538
|
+
this.lastTapViaHost = {
|
|
539
|
+
kind: hostHit.kind,
|
|
540
|
+
label
|
|
541
|
+
};
|
|
542
|
+
// Settings / modal hosts stack above progress — remount chrome on top.
|
|
543
|
+
_TaskStore.TaskStore.liftChrome();
|
|
544
|
+
this.done(node, this.message('runtime.tapped', {
|
|
545
|
+
label
|
|
546
|
+
}));
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
} catch (e) {
|
|
550
|
+
this.fail(node, e);
|
|
551
|
+
throw e;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
assertCurrent();
|
|
555
|
+
let controlNode = preresolved ?? (await this.resolveNode(target));
|
|
556
|
+
let point;
|
|
557
|
+
try {
|
|
558
|
+
point = await this.resolvePoint(target);
|
|
559
|
+
} catch (e) {
|
|
560
|
+
// No target evidence means no decorative tap at a guessed position.
|
|
561
|
+
throw e;
|
|
562
|
+
}
|
|
563
|
+
// Refresh control metadata from the same visible tree used for the point.
|
|
564
|
+
({
|
|
565
|
+
point,
|
|
566
|
+
node: controlNode
|
|
567
|
+
} = await this.ensureSafeTapPoint(target, point, controlNode));
|
|
568
|
+
assertCurrent();
|
|
569
|
+
const isToggle = Boolean(controlNode?.toggle);
|
|
570
|
+
const adjustableKind = controlNode ? classifyAdjustable(controlNode) : null;
|
|
571
|
+
const node = this.track('tap', isToggle ? this.message('runtime.toggle', {
|
|
572
|
+
label
|
|
573
|
+
}) : adjustableKind ? this.message('runtime.adjust', {
|
|
574
|
+
label
|
|
575
|
+
}) : this.message('runtime.tap', {
|
|
576
|
+
label
|
|
577
|
+
}));
|
|
578
|
+
try {
|
|
579
|
+
const confirmKey = `tap:${label}`;
|
|
580
|
+
if (!this.confirmedSensitive.has(confirmKey)) {
|
|
581
|
+
const allowed = await (0, _gate.runConfirmationGate)({
|
|
582
|
+
action: 'tap',
|
|
583
|
+
label,
|
|
584
|
+
selector: target.selector
|
|
585
|
+
}, this.config.confirmation, this.config.onConfirmSensitive);
|
|
586
|
+
assertCurrent();
|
|
587
|
+
if (!allowed) {
|
|
588
|
+
_TaskStore.TaskStore.updateNode(node.id, {
|
|
589
|
+
status: 'failed',
|
|
590
|
+
title: this.message('runtime.confirmBlocked', {
|
|
591
|
+
label
|
|
592
|
+
})
|
|
593
|
+
});
|
|
594
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.confirmationRequired'));
|
|
595
|
+
}
|
|
596
|
+
if ((0, _gate.isSensitiveLabel)(label, this.config.confirmation)) {
|
|
597
|
+
this.confirmedSensitive.add(confirmKey);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const silent = target.options?.silent;
|
|
601
|
+
const duration = target.options?.cursorDurationMs ?? this.config.cursorDurationMs ?? 320;
|
|
602
|
+
|
|
603
|
+
// Switches / toggles: prefer a real tap — native UISwitch handling is reliable.
|
|
604
|
+
// (A JS→swipe path used to miss UISwitch in dispatchSwipe.)
|
|
605
|
+
if (controlNode?.toggle && controlNode.frame) {
|
|
606
|
+
const targetPoint = (0, _match.centerOf)(controlNode);
|
|
607
|
+
if (!silent) {
|
|
608
|
+
assertCurrent();
|
|
609
|
+
await _controller.CursorController.moveTo(targetPoint.x, targetPoint.y, duration);
|
|
610
|
+
assertCurrent();
|
|
611
|
+
_controller.CursorController.setPressing(true);
|
|
612
|
+
await sleep(40);
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
await withChromeClearance([targetPoint], async () => {
|
|
616
|
+
await this.assertTapTargetCurrent(target, point, controlNode);
|
|
617
|
+
assertCurrent();
|
|
618
|
+
return _NativeBridge.NativeBridge.tap(targetPoint);
|
|
619
|
+
});
|
|
620
|
+
} finally {
|
|
621
|
+
if (!silent && epoch === this.executionEpoch) {
|
|
622
|
+
_controller.CursorController.showAt(targetPoint.x, targetPoint.y, 0);
|
|
623
|
+
await sleep(120);
|
|
624
|
+
_controller.CursorController.setPressing(false);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
this.done(node, this.message('runtime.toggled', {
|
|
628
|
+
label
|
|
629
|
+
}));
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Slider / picker: route to swipe. Stepper / segment: plain tap (native handles ± / index).
|
|
634
|
+
if (controlNode?.frame && adjustableKind && (adjustableKind === 'slider' || adjustableKind === 'picker' || adjustableKind === 'other')) {
|
|
635
|
+
const gesture = adjustableGesture(controlNode, adjustableKind, point);
|
|
636
|
+
if (gesture) {
|
|
637
|
+
if (!silent) {
|
|
638
|
+
assertCurrent();
|
|
639
|
+
await _controller.CursorController.moveTo(gesture.from.x, gesture.from.y, duration);
|
|
640
|
+
assertCurrent();
|
|
641
|
+
_controller.CursorController.setPressing(true);
|
|
642
|
+
await sleep(40);
|
|
643
|
+
}
|
|
644
|
+
try {
|
|
645
|
+
await withChromeClearance([gesture.from, gesture.to], async () => {
|
|
646
|
+
await this.assertTapTargetCurrent(target, point, controlNode);
|
|
647
|
+
assertCurrent();
|
|
648
|
+
return _NativeBridge.NativeBridge.swipe(gesture.from, gesture.to, gesture.durationMs);
|
|
649
|
+
});
|
|
650
|
+
} finally {
|
|
651
|
+
if (!silent && epoch === this.executionEpoch) {
|
|
652
|
+
_controller.CursorController.showAt(gesture.to.x, gesture.to.y, 0);
|
|
653
|
+
await sleep(120);
|
|
654
|
+
_controller.CursorController.setPressing(false);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
this.done(node, this.message('runtime.adjusted', {
|
|
658
|
+
label
|
|
659
|
+
}));
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// System Alert / ActionSheet buttons: invoke handler by title (hit-testing is unreliable).
|
|
665
|
+
if (controlNode && isAlertActionNode(controlNode)) {
|
|
666
|
+
const title = (controlNode.text || controlNode.accessibilityLabel || label || '').trim();
|
|
667
|
+
if (!silent) {
|
|
668
|
+
assertCurrent();
|
|
669
|
+
await _controller.CursorController.moveTo(point.x, point.y, duration);
|
|
670
|
+
assertCurrent();
|
|
671
|
+
_controller.CursorController.setPressing(true);
|
|
672
|
+
await sleep(40);
|
|
673
|
+
}
|
|
674
|
+
try {
|
|
675
|
+
await this.assertTapTargetCurrent(target, point, controlNode);
|
|
676
|
+
assertCurrent();
|
|
677
|
+
const invoked = title ? await _NativeBridge.NativeBridge.invokeAlertAction(title) : false;
|
|
678
|
+
if (!invoked) {
|
|
679
|
+
await withChromeClearance([point], async () => {
|
|
680
|
+
await this.assertTapTargetCurrent(target, point, controlNode);
|
|
681
|
+
assertCurrent();
|
|
682
|
+
return _NativeBridge.NativeBridge.tap(point);
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
} finally {
|
|
686
|
+
if (!silent) {
|
|
687
|
+
await sleep(120);
|
|
688
|
+
_controller.CursorController.setPressing(false);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
this.done(node, this.message('runtime.confirmed', {
|
|
692
|
+
label: title || label
|
|
693
|
+
}));
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (!silent) {
|
|
697
|
+
assertCurrent();
|
|
698
|
+
await _controller.CursorController.moveTo(point.x, point.y, duration);
|
|
699
|
+
assertCurrent();
|
|
700
|
+
_controller.CursorController.setPressing(true);
|
|
701
|
+
await sleep(40);
|
|
702
|
+
}
|
|
703
|
+
try {
|
|
704
|
+
await this.assertTapTargetCurrent(target, point, controlNode);
|
|
705
|
+
assertCurrent();
|
|
706
|
+
if (!silent && epoch === this.executionEpoch) {
|
|
707
|
+
_controller.CursorController.showAt(point.x, point.y, 0);
|
|
708
|
+
}
|
|
709
|
+
// If an alert is up, prefer title invoke even for generic sheet taps.
|
|
710
|
+
let didAlert = false;
|
|
711
|
+
if (controlNode?.sheet && controlNode.clickable) {
|
|
712
|
+
const title = (controlNode.text || controlNode.accessibilityLabel || label || '').trim();
|
|
713
|
+
if (title) {
|
|
714
|
+
assertCurrent();
|
|
715
|
+
didAlert = await _NativeBridge.NativeBridge.invokeAlertAction(title);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (!didAlert) {
|
|
719
|
+
await withChromeClearance([point], async () => {
|
|
720
|
+
await this.assertTapTargetCurrent(target, point, controlNode);
|
|
721
|
+
assertCurrent();
|
|
722
|
+
return _NativeBridge.NativeBridge.tap(point);
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
} finally {
|
|
726
|
+
if (!silent) {
|
|
727
|
+
await sleep(160);
|
|
728
|
+
_controller.CursorController.setPressing(false);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
this.done(node, this.message('runtime.tapped', {
|
|
732
|
+
label
|
|
733
|
+
}));
|
|
734
|
+
} catch (e) {
|
|
735
|
+
this.fail(node, e);
|
|
736
|
+
throw e;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/** Animation and confirmations may outlive the layout that was planned. */
|
|
741
|
+
async assertTapTargetCurrent(target, point, expected) {
|
|
742
|
+
const currentPoint = await this.resolvePoint({
|
|
743
|
+
...target,
|
|
744
|
+
options: {
|
|
745
|
+
...target.options,
|
|
746
|
+
revealIfNeeded: false
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
if (Math.hypot(currentPoint.x - point.x, currentPoint.y - point.y) > 16) {
|
|
750
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.positionChanged'));
|
|
751
|
+
}
|
|
752
|
+
if (expected && !expected.id.startsWith('ocr:')) {
|
|
753
|
+
const current = this.lastTree ? (0, _match.findNodeById)(this.lastTree, expected.id) : null;
|
|
754
|
+
if (!current || current.enabled === false || current.visible === false || current.type !== expected.type || current.text !== expected.text || current.accessibilityLabel !== expected.accessibilityLabel || current.testID !== expected.testID) {
|
|
755
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.contentChanged'));
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/** Refresh node metadata after scroll-based target resolution. */
|
|
761
|
+
async ensureSafeTapPoint(target, point, controlNode) {
|
|
762
|
+
const tree = this.lastTree;
|
|
763
|
+
const current = tree ? target.selector ? (0, _match.find)(tree, target.selector, tapFindOptions(target)) : target.nodeId ? (0, _match.findNodeById)(tree, target.nodeId) : controlNode : controlNode;
|
|
764
|
+
return {
|
|
765
|
+
point,
|
|
766
|
+
node: current?.visible === false ? null : current
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/** Reveal by visible swipes, only inside a natively confirmed scrollable list. */
|
|
771
|
+
async revealVisibleTarget(selector, label, preferNonInput = false) {
|
|
772
|
+
const epoch = this.executionEpoch;
|
|
773
|
+
const seen = new Set();
|
|
774
|
+
for (const direction of [1, -1]) {
|
|
775
|
+
for (let page = 0; page < 8; page++) {
|
|
776
|
+
const tree = await this.dump({
|
|
777
|
+
silent: true
|
|
778
|
+
});
|
|
779
|
+
if ((0, _sensitiveScreen.sensitiveScreenKind)(tree)) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.privateStep'));
|
|
780
|
+
const hit = (0, _match.find)(tree, selector, {
|
|
781
|
+
preferNonInput
|
|
782
|
+
}) || (label && allowsSoftLabelFallback(selector) ? (0, _match.findBySoftLabel)(tree, label, {
|
|
783
|
+
preferNonInput
|
|
784
|
+
}) : null);
|
|
785
|
+
if (hit) return hit;
|
|
786
|
+
const viewport = (0, _scrollViewport.scrollViewports)(tree).filter(({
|
|
787
|
+
frame
|
|
788
|
+
}) => frame.height >= 140 && frame.width >= tree.frame.width * 0.45).sort((a, b) => b.frame.width * b.frame.height - a.frame.width * a.frame.height)[0];
|
|
789
|
+
if (!viewport) return null;
|
|
790
|
+
// Use the list itself, not the first few screen affordances: sticky
|
|
791
|
+
// headers can stay unchanged while later rows are still moving.
|
|
792
|
+
const fingerprint = `${direction}:${JSON.stringify((0, _match.flattenTree)(viewport.node).map(n => [n.id, n.text || n.accessibilityLabel || '', Math.round(n.frame.y)]))}`;
|
|
793
|
+
if (seen.has(fingerprint)) break;
|
|
794
|
+
seen.add(fingerprint);
|
|
795
|
+
this.log('info', this.message('runtime.reveal'));
|
|
796
|
+
const f = viewport.frame;
|
|
797
|
+
const x = f.x + f.width / 2;
|
|
798
|
+
const upper = f.y + f.height * 0.25;
|
|
799
|
+
const lower = f.y + f.height * 0.75;
|
|
800
|
+
this.assertExecutionCurrent(epoch);
|
|
801
|
+
await this.swipe({
|
|
802
|
+
x,
|
|
803
|
+
y: direction > 0 ? lower : upper
|
|
804
|
+
}, {
|
|
805
|
+
x,
|
|
806
|
+
y: direction > 0 ? upper : lower
|
|
807
|
+
}, {
|
|
808
|
+
durationMs: 420
|
|
809
|
+
});
|
|
810
|
+
await sleep(250);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
return null;
|
|
814
|
+
}
|
|
815
|
+
async swipe(from, to, options) {
|
|
816
|
+
const epoch = this.executionEpoch;
|
|
817
|
+
const assertCurrent = () => this.assertExecutionCurrent(epoch);
|
|
818
|
+
_ExecutionGuard.ExecutionGuard.assert('swipe');
|
|
819
|
+
const tree = await this.dump({
|
|
820
|
+
silent: true
|
|
821
|
+
});
|
|
822
|
+
if ((0, _sensitiveScreen.sensitiveScreenKind)(tree)) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.privateStep'));
|
|
823
|
+
const viewport = (0, _scrollViewport.scrollViewports)(tree).filter(({
|
|
824
|
+
frame: f
|
|
825
|
+
}) => from.x >= f.x && from.x <= f.x + f.width && from.y >= f.y && from.y <= f.y + f.height).sort((a, b) => a.frame.width * a.frame.height - b.frame.width * b.frame.height)[0];
|
|
826
|
+
if (viewport) ({
|
|
827
|
+
from,
|
|
828
|
+
to
|
|
829
|
+
} = (0, _scrollViewport.boundedScrollGesture)(viewport.frame, from, to));
|
|
830
|
+
const silent = options?.silent;
|
|
831
|
+
const node = silent ? {
|
|
832
|
+
id: ''
|
|
833
|
+
} : this.track('swipe', this.message('runtime.swipe'));
|
|
834
|
+
const durationMs = options?.durationMs ?? 280;
|
|
835
|
+
try {
|
|
836
|
+
if (!silent) {
|
|
837
|
+
assertCurrent();
|
|
838
|
+
await _controller.CursorController.moveTo(from.x, from.y, this.config.cursorDurationMs ?? 320);
|
|
839
|
+
assertCurrent();
|
|
840
|
+
_controller.CursorController.setPressing(true);
|
|
841
|
+
}
|
|
842
|
+
try {
|
|
843
|
+
await withChromeClearance([from, to], () => {
|
|
844
|
+
assertCurrent();
|
|
845
|
+
return _NativeBridge.NativeBridge.swipe(from, to, durationMs);
|
|
846
|
+
});
|
|
847
|
+
} finally {
|
|
848
|
+
if (!silent && epoch === this.executionEpoch) {
|
|
849
|
+
_controller.CursorController.showAt(to.x, to.y);
|
|
850
|
+
_controller.CursorController.setPressing(false);
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
this.done(node, this.message('runtime.swiped'));
|
|
854
|
+
} catch (e) {
|
|
855
|
+
this.fail(node, e);
|
|
856
|
+
throw e;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Two-finger pinch at center. scale>1 zoom in, scale<1 zoom out.
|
|
862
|
+
*/
|
|
863
|
+
async pinch(center, scale, options) {
|
|
864
|
+
const epoch = this.executionEpoch;
|
|
865
|
+
const assertCurrent = () => this.assertExecutionCurrent(epoch);
|
|
866
|
+
_ExecutionGuard.ExecutionGuard.assert('pinch');
|
|
867
|
+
const silent = options?.silent;
|
|
868
|
+
const zoomIn = scale >= 1;
|
|
869
|
+
const node = silent ? {
|
|
870
|
+
id: ''
|
|
871
|
+
} : this.track('swipe', zoomIn ? this.message('runtime.zoomIn') : this.message('runtime.zoomOut'));
|
|
872
|
+
const durationMs = options?.durationMs ?? 280;
|
|
873
|
+
try {
|
|
874
|
+
if (!silent) {
|
|
875
|
+
assertCurrent();
|
|
876
|
+
await _controller.CursorController.moveTo(center.x, center.y, this.config.cursorDurationMs ?? 320);
|
|
877
|
+
assertCurrent();
|
|
878
|
+
_controller.CursorController.setPressing(true);
|
|
879
|
+
}
|
|
880
|
+
try {
|
|
881
|
+
await withChromeClearance([center], () => {
|
|
882
|
+
assertCurrent();
|
|
883
|
+
return _NativeBridge.NativeBridge.pinch(center, scale, durationMs);
|
|
884
|
+
});
|
|
885
|
+
} finally {
|
|
886
|
+
if (!silent && epoch === this.executionEpoch) {
|
|
887
|
+
_controller.CursorController.showAt(center.x, center.y);
|
|
888
|
+
_controller.CursorController.setPressing(false);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
this.done(node, zoomIn ? this.message('runtime.zoomedIn') : this.message('runtime.zoomedOut'));
|
|
892
|
+
} catch (e) {
|
|
893
|
+
this.fail(node, e);
|
|
894
|
+
throw e;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
async type(text, target = {}) {
|
|
898
|
+
const epoch = this.executionEpoch;
|
|
899
|
+
const assertCurrent = () => this.assertExecutionCurrent(epoch);
|
|
900
|
+
_ExecutionGuard.ExecutionGuard.assert('type');
|
|
901
|
+
if ((0, _sensitiveScreen.sensitiveScreenKind)(await _NativeBridge.NativeBridge.dump())) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.privateStep'));
|
|
902
|
+
assertCurrent();
|
|
903
|
+
const preview = text.length > 18 ? `${text.slice(0, 18)}…` : text;
|
|
904
|
+
const node = this.track('type', this.message('runtime.input', {
|
|
905
|
+
text: preview
|
|
906
|
+
}));
|
|
907
|
+
try {
|
|
908
|
+
// Ensure a field is focused: tap selector / node, or first text field on screen.
|
|
909
|
+
// Native tap must becomeFirstResponder (keyboard); synthetic UIControl events alone do not.
|
|
910
|
+
let focusPoint = null;
|
|
911
|
+
if (target.selector || target.nodeId) {
|
|
912
|
+
focusPoint = await this.resolvePoint({
|
|
913
|
+
selector: target.selector,
|
|
914
|
+
nodeId: target.nodeId,
|
|
915
|
+
inputTarget: true
|
|
916
|
+
});
|
|
917
|
+
assertCurrent();
|
|
918
|
+
await this.tap({
|
|
919
|
+
selector: target.selector,
|
|
920
|
+
nodeId: target.nodeId,
|
|
921
|
+
options: {
|
|
922
|
+
silent: target.options?.silent
|
|
923
|
+
},
|
|
924
|
+
label: target.label ?? this.text('runtime.field'),
|
|
925
|
+
inputTarget: true
|
|
926
|
+
});
|
|
927
|
+
} else {
|
|
928
|
+
const root = this.lastTree ?? (await this.dump({
|
|
929
|
+
silent: true
|
|
930
|
+
}));
|
|
931
|
+
const field = findFirstTextField(root);
|
|
932
|
+
if (field) {
|
|
933
|
+
focusPoint = await this.resolvePoint({
|
|
934
|
+
nodeId: field.id
|
|
935
|
+
});
|
|
936
|
+
assertCurrent();
|
|
937
|
+
await this.tap({
|
|
938
|
+
nodeId: field.id,
|
|
939
|
+
options: {
|
|
940
|
+
silent: target.options?.silent
|
|
941
|
+
},
|
|
942
|
+
label: target.label ?? field.accessibilityLabel ?? field.text ?? this.text('runtime.field')
|
|
943
|
+
});
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
await sleep(160);
|
|
947
|
+
if (focusPoint) {
|
|
948
|
+
try {
|
|
949
|
+
assertCurrent();
|
|
950
|
+
await _NativeBridge.NativeBridge.focusAt(focusPoint);
|
|
951
|
+
} catch {
|
|
952
|
+
try {
|
|
953
|
+
assertCurrent();
|
|
954
|
+
await _NativeBridge.NativeBridge.focusNode(target.nodeId ?? '');
|
|
955
|
+
} catch {
|
|
956
|
+
// typeText will try becomeFirstResponder again
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
} else {
|
|
960
|
+
try {
|
|
961
|
+
assertCurrent();
|
|
962
|
+
await _NativeBridge.NativeBridge.focusNode(target.nodeId ?? '');
|
|
963
|
+
} catch {
|
|
964
|
+
// optional
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
await sleep(80);
|
|
968
|
+
assertCurrent();
|
|
969
|
+
await _NativeBridge.NativeBridge.typeText(text, target.options?.clear ?? false);
|
|
970
|
+
this.done(node, this.message('runtime.typed', {
|
|
971
|
+
text: preview
|
|
972
|
+
}));
|
|
973
|
+
} catch (e) {
|
|
974
|
+
this.fail(node, e);
|
|
975
|
+
throw e;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
async requestConfirm(ctx) {
|
|
979
|
+
const label = ctx.label ?? ctx.action;
|
|
980
|
+
const node = this.track('confirm', this.message('runtime.confirm', {
|
|
981
|
+
label
|
|
982
|
+
}));
|
|
983
|
+
const ok = await (0, _gate.runConfirmationGate)(ctx, this.config.confirmation, this.config.onConfirmSensitive);
|
|
984
|
+
_TaskStore.TaskStore.updateNode(node.id, {
|
|
985
|
+
status: ok ? 'done' : 'failed',
|
|
986
|
+
title: this.message(ok ? 'runtime.userConfirmed' : 'runtime.userDeclined', {
|
|
987
|
+
label
|
|
988
|
+
})
|
|
989
|
+
});
|
|
990
|
+
return ok;
|
|
991
|
+
}
|
|
992
|
+
hideCursor() {
|
|
993
|
+
_controller.CursorController.hide();
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/** Run one agent protocol tool call. */
|
|
997
|
+
async runAction(action) {
|
|
998
|
+
return (0, _actions.executeAgentAction)(this, action);
|
|
999
|
+
}
|
|
1000
|
+
track(kind, title) {
|
|
1001
|
+
if (this.config.observer === false) {
|
|
1002
|
+
return {
|
|
1003
|
+
id: ''
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
return _TaskStore.TaskStore.appendNode({
|
|
1007
|
+
kind,
|
|
1008
|
+
title,
|
|
1009
|
+
status: 'running'
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
done(node, title, detail) {
|
|
1013
|
+
if (!node.id || this.config.observer === false) return;
|
|
1014
|
+
_TaskStore.TaskStore.updateNode(node.id, {
|
|
1015
|
+
status: 'done',
|
|
1016
|
+
title,
|
|
1017
|
+
detail
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
fail(node, e) {
|
|
1021
|
+
if (!node.id || this.config.observer === false) return;
|
|
1022
|
+
const copy = e instanceof _ActionOutcomeUnknownError.ActionValidationError ? e.localizedMessage : this.message('runtime.operationFailed');
|
|
1023
|
+
_TaskStore.TaskStore.updateNode(node.id, {
|
|
1024
|
+
status: 'failed',
|
|
1025
|
+
title: copy
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
async resolvePoint(target) {
|
|
1029
|
+
// A labelled cloud coordinate is a hint, not evidence that a row is visible.
|
|
1030
|
+
// Prefer a fresh selector/label and scroll lookup before dispatching a touch.
|
|
1031
|
+
if (target.point && !target.selector && !target.nodeId) {
|
|
1032
|
+
if (!this.activeGoal) return this.pointWithinWindow(target.point);
|
|
1033
|
+
const label = target.label?.match(/[「“"]([^」”"]+)[」”"]/)?.[1] || target.label?.replace(/^(点击|轻点|打开)\s*/, '').replace(/按钮$/, '');
|
|
1034
|
+
if (!label) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.missingTarget'));
|
|
1035
|
+
return this.resolvePoint({
|
|
1036
|
+
selector: {
|
|
1037
|
+
match: [{
|
|
1038
|
+
text: label
|
|
1039
|
+
}]
|
|
1040
|
+
},
|
|
1041
|
+
label,
|
|
1042
|
+
options: target.options
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
const root = await this.dump({
|
|
1046
|
+
silent: true
|
|
1047
|
+
});
|
|
1048
|
+
if ((0, _sensitiveScreen.sensitiveScreenKind)(root)) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.privateStep'));
|
|
1049
|
+
|
|
1050
|
+
// An explicit selector is target evidence; a node path is only a hint.
|
|
1051
|
+
// In particular do not replace a selector with a stale recycled row id.
|
|
1052
|
+
if (target.selector) {
|
|
1053
|
+
let node = (0, _match.find)(root, target.selector, tapFindOptions(target));
|
|
1054
|
+
const soft = selectorLabel(target.selector);
|
|
1055
|
+
const allowSoft = allowsSoftLabelFallback(target.selector);
|
|
1056
|
+
if (!node && soft && allowSoft) node = (0, _match.findBySoftLabel)(root, soft, tapFindOptions(target));
|
|
1057
|
+
if (!node && soft && allowSoft && _NativeBridge.NativeBridge.isAvailable()) {
|
|
1058
|
+
const point = await this.currentOcrPoint(soft);
|
|
1059
|
+
if (point) return point;
|
|
1060
|
+
}
|
|
1061
|
+
if (!node && target.options?.revealIfNeeded !== false) {
|
|
1062
|
+
node = await this.revealVisibleTarget(target.selector, soft || undefined, tapFindOptions(target).preferNonInput);
|
|
1063
|
+
}
|
|
1064
|
+
if (!node || node.visible === false || node.enabled === false) {
|
|
1065
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.missingTarget'));
|
|
1066
|
+
}
|
|
1067
|
+
return this.pointWithinWindow((0, _match.centerOfLabel)(node, soft));
|
|
1068
|
+
}
|
|
1069
|
+
if (target.nodeId) {
|
|
1070
|
+
if (target.nodeId.startsWith('ocr:')) {
|
|
1071
|
+
const observed = this.ocrTargets.get(target.nodeId);
|
|
1072
|
+
if (!observed) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.ocrUnobserved'));
|
|
1073
|
+
const point = await this.currentOcrPoint(observed.text, observed.webview ? root : undefined);
|
|
1074
|
+
if (point) return point;
|
|
1075
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.ocrMissing'));
|
|
1076
|
+
}
|
|
1077
|
+
// host:… is a catalog id, not a dump node — remap to visible text.
|
|
1078
|
+
if (target.nodeId.startsWith('host:')) {
|
|
1079
|
+
const host = _HostActions.HostActionsStore.getById(target.nodeId);
|
|
1080
|
+
const soft = host?.text || host?.label;
|
|
1081
|
+
if (soft) {
|
|
1082
|
+
const hit = target.options?.revealIfNeeded === false ? (0, _match.findBySoftLabel)(root, soft) : await this.revealVisibleTarget({
|
|
1083
|
+
match: [{
|
|
1084
|
+
text: soft
|
|
1085
|
+
}]
|
|
1086
|
+
}, soft);
|
|
1087
|
+
if (hit && hit.visible !== false && hit.enabled !== false) return this.pointWithinWindow((0, _match.centerOfLabel)(hit, soft));
|
|
1088
|
+
}
|
|
1089
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.hostNotVisible', {
|
|
1090
|
+
id: target.nodeId
|
|
1091
|
+
}));
|
|
1092
|
+
}
|
|
1093
|
+
const node = this.validatedNativeNode(root, target.nodeId);
|
|
1094
|
+
// label is narration, in any language. It must not override a real
|
|
1095
|
+
// current node or become an invented selector such as “Click Back”.
|
|
1096
|
+
return this.pointWithinWindow((0, _match.centerOfLabel)(node));
|
|
1097
|
+
}
|
|
1098
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.invalidTarget'));
|
|
1099
|
+
}
|
|
1100
|
+
validatedNativeNode(root, nodeId) {
|
|
1101
|
+
const node = (0, _match.findNodeById)(root, nodeId);
|
|
1102
|
+
if (!node || node.visible === false || node.enabled === false) {
|
|
1103
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.nodeUnavailable'));
|
|
1104
|
+
}
|
|
1105
|
+
if (this.activeGoal) {
|
|
1106
|
+
const observed = this.planningTree ? (0, _match.findNodeById)(this.planningTree, nodeId) : null;
|
|
1107
|
+
const identity = item => JSON.stringify([item.type, item.text || '', item.accessibilityLabel || '', item.testID || '']);
|
|
1108
|
+
if (!observed || identity(observed) !== identity(node)) {
|
|
1109
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.nodeChanged'));
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return node;
|
|
1113
|
+
}
|
|
1114
|
+
async currentOcrPoint(text, webviewRoot) {
|
|
1115
|
+
if (!_NativeBridge.NativeBridge.isAvailable()) return null;
|
|
1116
|
+
try {
|
|
1117
|
+
const ocr = await _NativeBridge.NativeBridge.recognizeScreenText({
|
|
1118
|
+
maxTokens: 32,
|
|
1119
|
+
hideOverlays: true
|
|
1120
|
+
});
|
|
1121
|
+
const hit = (0, _ocrTarget.findOcrTextHit)(ocr.texts || [], text);
|
|
1122
|
+
const frame = hit?.frame;
|
|
1123
|
+
if (!frame || ![frame.x, frame.y, frame.width, frame.height].every(Number.isFinite)) return null;
|
|
1124
|
+
if (webviewRoot && (!hit || !(0, _ocrTarget.ocrHitInFrames)(hit, (0, _ocrTarget.visibleWebViewFrames)(webviewRoot)))) return null;
|
|
1125
|
+
return await this.pointWithinWindow({
|
|
1126
|
+
x: frame.x + frame.width / 2,
|
|
1127
|
+
y: frame.y + frame.height / 2
|
|
1128
|
+
});
|
|
1129
|
+
} catch {
|
|
1130
|
+
// No current positioned evidence means no touch, even if an older OCR
|
|
1131
|
+
// read found the same text at a plausible location.
|
|
1132
|
+
return null;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* A coordinate tap has no node to sanity-check it against, so an invented
|
|
1138
|
+
* point would dispatch into nowhere and only surface later as tap_noop.
|
|
1139
|
+
* Fail loudly instead.
|
|
1140
|
+
*/
|
|
1141
|
+
/**
|
|
1142
|
+
* A tree that bottoms out exactly at the cap was almost certainly cut short,
|
|
1143
|
+
* and the part that gets cut is the page body — the agent is then left with
|
|
1144
|
+
* the shallow chrome and reports the control as missing. Surface it rather
|
|
1145
|
+
* than letting it read as an empty screen.
|
|
1146
|
+
*/
|
|
1147
|
+
warnIfDepthCapped(tree, cap) {
|
|
1148
|
+
if (!cap) return;
|
|
1149
|
+
let deepest = 0;
|
|
1150
|
+
const walk = (n, d) => {
|
|
1151
|
+
if (d > deepest) deepest = d;
|
|
1152
|
+
for (const c of n.children ?? []) walk(c, d + 1);
|
|
1153
|
+
};
|
|
1154
|
+
walk(tree, 0);
|
|
1155
|
+
if (deepest >= cap) {
|
|
1156
|
+
_AgentDebug.AgentDebug.dumpTruncated(this.config, cap);
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
/**
|
|
1161
|
+
* Cheap screen fingerprint used to tell real navigation from a dead action.
|
|
1162
|
+
* The "before" side can reuse the tree the session just dumped for this step:
|
|
1163
|
+
* an extra full walk per tap is work the JS thread does not have to spare
|
|
1164
|
+
* while a task is running.
|
|
1165
|
+
*/
|
|
1166
|
+
async snapshotLine(reuseLastTree = false) {
|
|
1167
|
+
try {
|
|
1168
|
+
const tree = reuseLastTree ? this.lastTree ?? (await this.dump({
|
|
1169
|
+
silent: true
|
|
1170
|
+
})) : await this.dump({
|
|
1171
|
+
silent: true
|
|
1172
|
+
});
|
|
1173
|
+
return tree ? (0, _screenModel.screenSnapshotLine)(tree) : '';
|
|
1174
|
+
} catch {
|
|
1175
|
+
return '';
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
async pointWithinWindow(point) {
|
|
1179
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y) || point.x < 0 || point.y < 0) {
|
|
1180
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.invalidPoint', {
|
|
1181
|
+
x: point.x,
|
|
1182
|
+
y: point.y
|
|
1183
|
+
}));
|
|
1184
|
+
}
|
|
1185
|
+
const root = this.lastTree ?? (await this.dump({
|
|
1186
|
+
silent: true
|
|
1187
|
+
}));
|
|
1188
|
+
const w = root?.frame?.width ?? 0;
|
|
1189
|
+
const h = root?.frame?.height ?? 0;
|
|
1190
|
+
if (w > 0 && h > 0 && (point.x > w || point.y > h)) {
|
|
1191
|
+
throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.outsideWindow'));
|
|
1192
|
+
}
|
|
1193
|
+
return point;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
/** Resolve the view node for a tap target (for toggle/adjustable routing). */
|
|
1197
|
+
/**
|
|
1198
|
+
* Where to point while a host action runs.
|
|
1199
|
+
*
|
|
1200
|
+
* Best effort by design: the whole reason this path exists is that the dump
|
|
1201
|
+
* sometimes cannot see the control, so a miss here is normal and must not
|
|
1202
|
+
* turn a working host action into a failed step.
|
|
1203
|
+
*/
|
|
1204
|
+
async hostActionPoint(target, preresolved) {
|
|
1205
|
+
if (preresolved?.frame) return (0, _match.centerOfLabel)(preresolved, target.label ?? selectorLabel(target.selector));
|
|
1206
|
+
try {
|
|
1207
|
+
return await this.resolvePoint(target);
|
|
1208
|
+
} catch {
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
async resolveNode(target) {
|
|
1213
|
+
if (target.point && !target.selector && !target.nodeId) return null;
|
|
1214
|
+
const root = await this.dump({
|
|
1215
|
+
silent: true
|
|
1216
|
+
});
|
|
1217
|
+
if ((0, _sensitiveScreen.sensitiveScreenKind)(root)) throw new _ActionOutcomeUnknownError.ActionValidationError(this.message('runtime.privateStep'));
|
|
1218
|
+
let node = null;
|
|
1219
|
+
if (target.selector) {
|
|
1220
|
+
node = (0, _match.find)(root, target.selector, tapFindOptions(target));
|
|
1221
|
+
if (!node) {
|
|
1222
|
+
const soft = selectorLabel(target.selector);
|
|
1223
|
+
if (soft && allowsSoftLabelFallback(target.selector)) node = (0, _match.findBySoftLabel)(root, soft, tapFindOptions(target));
|
|
1224
|
+
}
|
|
1225
|
+
} else if (target.nodeId) {
|
|
1226
|
+
if (target.nodeId.startsWith('ocr:')) return null;
|
|
1227
|
+
if (target.nodeId.startsWith('host:')) {
|
|
1228
|
+
const host = _HostActions.HostActionsStore.getById(target.nodeId);
|
|
1229
|
+
const soft = host?.text || host?.label;
|
|
1230
|
+
if (soft) node = (0, _match.findBySoftLabel)(root, soft);
|
|
1231
|
+
} else {
|
|
1232
|
+
node = this.validatedNativeNode(root, target.nodeId);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
if (!node || node.visible === false || node.enabled === false) return null;
|
|
1236
|
+
if (node.toggle || node.adjustable) return node;
|
|
1237
|
+
// Label may resolve to a wrapper; prefer a toggle / adjustable descendant.
|
|
1238
|
+
const nested = findControlDescendant(node);
|
|
1239
|
+
return nested ?? node;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
exports.KokoAgent = KokoAgent;
|
|
1243
|
+
function tapFindOptions(target) {
|
|
1244
|
+
const inputIntent = /(?:search|input|text)\s*(?:box|field|input)|输入框|搜索框/i.test(target.label || '');
|
|
1245
|
+
return {
|
|
1246
|
+
preferNonInput: !target.inputTarget && !inputIntent
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
/** A fallback must never discard context, identity, location, or an index. */
|
|
1251
|
+
function allowsSoftLabelFallback(selector) {
|
|
1252
|
+
return selector.index === undefined && selector.match.every(rule => 'text' in rule || 'accessibilityLabel' in rule || 'clickable' in rule && rule.clickable === true);
|
|
1253
|
+
}
|
|
1254
|
+
function findControlDescendant(node) {
|
|
1255
|
+
if (node.toggle || node.adjustable) return node;
|
|
1256
|
+
for (const c of node.children) {
|
|
1257
|
+
const hit = findControlDescendant(c);
|
|
1258
|
+
if (hit) return hit;
|
|
1259
|
+
}
|
|
1260
|
+
return null;
|
|
1261
|
+
}
|
|
1262
|
+
function isAlertActionNode(node) {
|
|
1263
|
+
if (node.type === 'UIAlertAction' || node.id.startsWith('alert/action/')) return true;
|
|
1264
|
+
if (!node.sheet || !node.clickable) return false;
|
|
1265
|
+
const t = (node.text || node.accessibilityLabel || '').trim();
|
|
1266
|
+
return /^(取消|清空|删除|好|确定|确认|允许|不允许|OK|Cancel|Delete|Yes|No|Discard)$/i.test(t);
|
|
1267
|
+
}
|
|
1268
|
+
function selectorLabel(selector) {
|
|
1269
|
+
if (!selector) return undefined;
|
|
1270
|
+
for (const rule of selector.match) {
|
|
1271
|
+
if ('text' in rule) return rule.text;
|
|
1272
|
+
if ('nearText' in rule) return rule.nearText;
|
|
1273
|
+
if ('accessibilityLabel' in rule) return rule.accessibilityLabel;
|
|
1274
|
+
}
|
|
1275
|
+
return undefined;
|
|
1276
|
+
}
|
|
1277
|
+
function selectorTestID(selector) {
|
|
1278
|
+
if (!selector) return undefined;
|
|
1279
|
+
for (const rule of selector.match) {
|
|
1280
|
+
if ('testID' in rule) return rule.testID;
|
|
1281
|
+
}
|
|
1282
|
+
return undefined;
|
|
1283
|
+
}
|
|
1284
|
+
function classifyAdjustable(node) {
|
|
1285
|
+
const t = node.type.toLowerCase();
|
|
1286
|
+
if (/slider|seekbar|rating/i.test(t)) return 'slider';
|
|
1287
|
+
if (/stepper/i.test(t)) return 'stepper';
|
|
1288
|
+
if (/segment/i.test(t)) return 'segment';
|
|
1289
|
+
if (/picker|datepicker|spinner|numberpicker/i.test(t)) return 'picker';
|
|
1290
|
+
if (node.adjustable) {
|
|
1291
|
+
// Trait-only adjustable: prefer horizontal if wide, else vertical.
|
|
1292
|
+
if (node.frame.width >= node.frame.height * 1.4) return 'slider';
|
|
1293
|
+
return 'picker';
|
|
1294
|
+
}
|
|
1295
|
+
return null;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* Map tap intent on an adjustable into a swipe that nudges value.
|
|
1300
|
+
* Uses tap X/Y relative to the control when available.
|
|
1301
|
+
*/
|
|
1302
|
+
function adjustableGesture(node, kind, tap) {
|
|
1303
|
+
const f = node.frame;
|
|
1304
|
+
const midX = f.x + f.width / 2;
|
|
1305
|
+
const midY = f.y + f.height / 2;
|
|
1306
|
+
const insetX = Math.max(8, f.width * 0.12);
|
|
1307
|
+
const insetY = Math.max(8, f.height * 0.18);
|
|
1308
|
+
if (kind === 'slider') {
|
|
1309
|
+
// Drag from current thumb (if value known) toward the tap X.
|
|
1310
|
+
// Near-center taps used to nudge +28% of track → often slammed to max (e.g. 1.6×).
|
|
1311
|
+
const min = typeof node.min === 'number' ? node.min : 0;
|
|
1312
|
+
const max = typeof node.max === 'number' ? node.max : 1;
|
|
1313
|
+
const span = Math.max(1e-6, max - min);
|
|
1314
|
+
const cur = typeof node.value === 'number' && Number.isFinite(node.value) ? node.value : min + span * 0.5;
|
|
1315
|
+
const thumbRatio = Math.max(0, Math.min(1, (cur - min) / span));
|
|
1316
|
+
const trackLeft = f.x + insetX;
|
|
1317
|
+
const trackRight = f.x + f.width - insetX;
|
|
1318
|
+
const trackW = Math.max(1, trackRight - trackLeft);
|
|
1319
|
+
const fromX = trackLeft + thumbRatio * trackW;
|
|
1320
|
+
let toX = tap.x;
|
|
1321
|
+
if (Math.abs(toX - midX) < f.width * 0.1) {
|
|
1322
|
+
// Ambiguous center tap: one small step toward + (~12% of range).
|
|
1323
|
+
toX = fromX + trackW * 0.12;
|
|
1324
|
+
}
|
|
1325
|
+
toX = Math.max(trackLeft, Math.min(trackRight, toX));
|
|
1326
|
+
return {
|
|
1327
|
+
from: {
|
|
1328
|
+
x: fromX,
|
|
1329
|
+
y: midY
|
|
1330
|
+
},
|
|
1331
|
+
to: {
|
|
1332
|
+
x: toX,
|
|
1333
|
+
y: midY
|
|
1334
|
+
},
|
|
1335
|
+
durationMs: 200
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
if (kind === 'stepper') {
|
|
1339
|
+
// Right half → +, left half → − (short horizontal nudge).
|
|
1340
|
+
const goPlus = tap.x >= midX;
|
|
1341
|
+
const from = {
|
|
1342
|
+
x: midX,
|
|
1343
|
+
y: midY
|
|
1344
|
+
};
|
|
1345
|
+
const to = {
|
|
1346
|
+
x: goPlus ? f.x + f.width - insetX : f.x + insetX,
|
|
1347
|
+
y: midY
|
|
1348
|
+
};
|
|
1349
|
+
return {
|
|
1350
|
+
from,
|
|
1351
|
+
to,
|
|
1352
|
+
durationMs: 160
|
|
1353
|
+
};
|
|
1354
|
+
}
|
|
1355
|
+
if (kind === 'picker') {
|
|
1356
|
+
// Vertical wheel: tap above mid → scroll up (earlier values), below → down.
|
|
1357
|
+
const goUp = tap.y < midY;
|
|
1358
|
+
const from = {
|
|
1359
|
+
x: midX,
|
|
1360
|
+
y: midY
|
|
1361
|
+
};
|
|
1362
|
+
const to = {
|
|
1363
|
+
x: midX,
|
|
1364
|
+
y: goUp ? f.y + insetY : f.y + f.height - insetY
|
|
1365
|
+
};
|
|
1366
|
+
return {
|
|
1367
|
+
from,
|
|
1368
|
+
to,
|
|
1369
|
+
durationMs: 260
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
return null;
|
|
1373
|
+
}
|
|
1374
|
+
function findFirstTextField(root) {
|
|
1375
|
+
let best = null;
|
|
1376
|
+
const walk = n => {
|
|
1377
|
+
const t = n.type.toLowerCase();
|
|
1378
|
+
if (n.visible && (/textfield|textinput|edittext|uitextfield/i.test(t) || n.secure === true)) {
|
|
1379
|
+
best = n;
|
|
1380
|
+
}
|
|
1381
|
+
for (const c of n.children) walk(c);
|
|
1382
|
+
};
|
|
1383
|
+
walk(root);
|
|
1384
|
+
return best;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Before an agent gesture: dismiss chat sheet, and if the tap/swipe lands in
|
|
1389
|
+
* the bottom-right progress/tab dock, hide chrome → wait for RN unmount →
|
|
1390
|
+
* gesture → show chrome again.
|
|
1391
|
+
*/
|
|
1392
|
+
async function withChromeClearance(points, action) {
|
|
1393
|
+
if (_TaskStore.TaskStore.snapshot().ui.sheetOpen) {
|
|
1394
|
+
_TaskStore.TaskStore.closeSheet();
|
|
1395
|
+
await sleep(480);
|
|
1396
|
+
}
|
|
1397
|
+
try {
|
|
1398
|
+
// iOS dispatch temporarily disables overlay hit-testing natively. Keep
|
|
1399
|
+
// the progress host mounted, including when touching beneath the pill.
|
|
1400
|
+
if (_reactNative.Platform.OS === 'ios' || !(0, _progressChrome.pointsOverlapProgressChrome)(points)) {
|
|
1401
|
+
await action();
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
_TaskStore.TaskStore.suppressChrome();
|
|
1405
|
+
// React must commit unmount before native hit-testing; 50ms was too short.
|
|
1406
|
+
await sleep(160);
|
|
1407
|
+
await action();
|
|
1408
|
+
} finally {
|
|
1409
|
+
_TaskStore.TaskStore.restoreChrome();
|
|
1410
|
+
// Host Settings/sheet Modals stack above our progress Modal — remount
|
|
1411
|
+
// so stop / pill stay tappable.
|
|
1412
|
+
_TaskStore.TaskStore.liftChrome();
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
function sleep(ms) {
|
|
1416
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1417
|
+
}
|
|
1418
|
+
let shared = null;
|
|
1419
|
+
function getKokoAgent() {
|
|
1420
|
+
if (!shared) shared = new KokoAgent();
|
|
1421
|
+
return shared;
|
|
1422
|
+
}
|
|
1423
|
+
function initKokoAgent(config) {
|
|
1424
|
+
shared = new KokoAgent(config);
|
|
1425
|
+
return shared;
|
|
1426
|
+
}
|
|
1427
|
+
//# sourceMappingURL=KokoAgent.js.map
|