From 718707fd19ab7c27e38c8807055c80809d25e6dc Mon Sep 17 00:00:00 2001 From: kong <135376906+3316891527@users.noreply.github.com> Date: Thu, 29 Oct 2026 11:27:20 +0000 Subject: [PATCH 1/4] =?UTF-8?q?refactor(tools):=20=E6=94=B6=E5=8F=A3?= =?UTF-8?q?=E4=B8=89=E6=A1=A3=E6=9D=83=E9=99=90=E5=AE=9E=E7=8E=B0=E4=B8=8E?= =?UTF-8?q?=20Shizuku=20=E5=90=8E=E7=AB=AF=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/tools/defaultTool/ToolGetter.kt | 14 +- .../AccessibilityDeviceInfoToolExecutor.kt | 9 - .../AccessibilityFileSystemTools.kt | 9 - .../AccessibilitySystemOperationTools.kt | 10 - .../accessbility/AccessibilityUITools.kt | 790 ----- .../admin/AdminDeviceInfoToolExecutor.kt | 9 - .../defaultTool/admin/AdminFileSystemTools.kt | 2962 ++++++++++++++++- .../admin/AdminSystemOperationTools.kt | 525 ++- .../tools/defaultTool/admin/AdminUITools.kt | 2122 +++++++++++- .../DebuggerDeviceInfoToolExecutor.kt | 10 - .../debugger/DebuggerFileSystemTools.kt | 2930 ---------------- .../debugger/DebuggerSystemOperationTools.kt | 527 --- .../defaultTool/debugger/DebuggerUITools.kt | 1359 -------- .../root/RootDeviceInfoToolExecutor.kt | 9 - .../defaultTool/root/RootFileSystemTools.kt | 9 - .../root/RootSystemOperationTools.kt | 9 - .../tools/defaultTool/root/RootUITools.kt | 5 +- .../defaultTool/standard/StandardUITools.kt | 2 +- .../tools/system/AndroidPermissionLevel.kt | 1 - .../system/action/ActionListenerFactory.kt | 2 +- ...onListener.kt => ShizukuActionListener.kt} | 6 +- .../system/shell/ShellExecutorFactory.kt | 2 +- ...ellExecutor.kt => ShizukuShellExecutor.kt} | 26 +- app/src/main/res/values-en/strings.xml | 4 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-id/strings.xml | 2 +- app/src/main/res/values-ja/strings.xml | 2 +- app/src/main/res/values-ko/strings.xml | 2 +- app/src/main/res/values-ms/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-ro/strings.xml | 4 +- app/src/main/res/values/strings.xml | 4 +- .../permissions/PermissionCapabilitiesTest.kt | 10 +- .../01-permissions.md | 25 + .../chore/tools-permissions-layout/index.md | 29 + 35 files changed, 5676 insertions(+), 5759 deletions(-) delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityDeviceInfoToolExecutor.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityFileSystemTools.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilitySystemOperationTools.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityUITools.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminDeviceInfoToolExecutor.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerDeviceInfoToolExecutor.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerFileSystemTools.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerSystemOperationTools.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerUITools.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootDeviceInfoToolExecutor.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootFileSystemTools.kt delete mode 100644 app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootSystemOperationTools.kt rename app/src/main/java/com/ai/assistance/operit/core/tools/system/action/{DebuggerActionListener.kt => ShizukuActionListener.kt} (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/{DebuggerShellExecutor.kt => ShizukuShellExecutor.kt} (96%) create mode 100644 docs/TODO/chore/tools-permissions-layout/01-permissions.md create mode 100644 docs/TODO/chore/tools-permissions-layout/index.md diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt index d02c589a91..91ea22b74b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt @@ -17,8 +17,7 @@ object ToolGetter { */ fun getFileSystemTools(context: Context): StandardFileSystemTools { return when (androidPermissionPreferences.getPreferredPermissionLevel()) { - AndroidPermissionLevel.ROOT -> RootFileSystemTools(context) - AndroidPermissionLevel.ADMIN -> AdminFileSystemTools(context) + AndroidPermissionLevel.ADMIN, AndroidPermissionLevel.ROOT -> AdminFileSystemTools(context) AndroidPermissionLevel.STANDARD -> StandardFileSystemTools(context) null -> StandardFileSystemTools(context) // 默认使用标准权限级别 } @@ -54,8 +53,7 @@ object ToolGetter { */ fun getSystemOperationTools(context: Context): StandardSystemOperationTools { return when (androidPermissionPreferences.getPreferredPermissionLevel()) { - AndroidPermissionLevel.ROOT -> RootSystemOperationTools(context) - AndroidPermissionLevel.ADMIN -> AdminSystemOperationTools(context) + AndroidPermissionLevel.ADMIN, AndroidPermissionLevel.ROOT -> AdminSystemOperationTools(context) AndroidPermissionLevel.STANDARD -> StandardSystemOperationTools(context) null -> StandardSystemOperationTools(context) // 默认使用标准权限级别 } @@ -67,12 +65,8 @@ object ToolGetter { * @return 根据首选权限级别的设备信息工具执行器实现 */ fun getDeviceInfoToolExecutor(context: Context): StandardDeviceInfoToolExecutor { - return when (androidPermissionPreferences.getPreferredPermissionLevel()) { - AndroidPermissionLevel.ROOT -> RootDeviceInfoToolExecutor(context) - AndroidPermissionLevel.ADMIN -> AdminDeviceInfoToolExecutor(context) - AndroidPermissionLevel.STANDARD -> StandardDeviceInfoToolExecutor(context) - null -> StandardDeviceInfoToolExecutor(context) // 默认使用标准权限级别 - } + // 原有各权限版本均没有设备信息特有行为,共享实现按实际能力执行操作。 + return StandardDeviceInfoToolExecutor(context) } /** diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityDeviceInfoToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityDeviceInfoToolExecutor.kt deleted file mode 100644 index 79ff4fbfbc..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityDeviceInfoToolExecutor.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.accessbility - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardDeviceInfoToolExecutor - -/** 无障碍级别的设备信息工具,继承标准版本 */ -open class AccessibilityDeviceInfoToolExecutor(context: Context) : StandardDeviceInfoToolExecutor(context) { - // 当前阶段不添加新功能,仅继承标准实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityFileSystemTools.kt deleted file mode 100644 index e578f318ef..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityFileSystemTools.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.accessbility - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardFileSystemTools - -/** 无障碍级别的文件系统工具,继承标准版本 */ -open class AccessibilityFileSystemTools(context: Context) : StandardFileSystemTools(context) { - // 当前阶段不添加新功能,仅继承标准实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilitySystemOperationTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilitySystemOperationTools.kt deleted file mode 100644 index 872085cc32..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilitySystemOperationTools.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.accessbility - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardSystemOperationTools - -/** 无障碍级别的系统操作工具,继承标准版本 */ -open class AccessibilitySystemOperationTools(context: Context) : - StandardSystemOperationTools(context) { - // 当前阶段不添加新功能,仅继承标准实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityUITools.kt deleted file mode 100644 index b21d94d4dd..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityUITools.kt +++ /dev/null @@ -1,790 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.accessbility - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.SimplifiedUINode -import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.UIActionResultData -import com.ai.assistance.operit.core.tools.UIPageResultData -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardUITools -import com.ai.assistance.operit.data.model.AITool -import com.ai.assistance.operit.data.model.ToolResult -import com.ai.assistance.operit.data.repository.UIHierarchyManager -import com.ai.assistance.operit.util.files.OperitPaths -import java.io.File -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import com.ai.assistance.operit.util.media.ImagePoolManager -import java.io.StringReader -import org.json.JSONObject -import org.xmlpull.v1.XmlPullParser -import org.xmlpull.v1.XmlPullParserFactory -import kotlinx.coroutines.delay - -/** 无障碍级别的UI工具,使用Android无障碍服务API实现UI操作 */ -open class AccessibilityUITools(context: Context) : StandardUITools(context) { - - companion object { - private const val TAG = "AccessibilityUITools" - private const val MAX_RETRY_COUNT = 3 - private const val RETRY_DELAY_MS = 300L - } - - /** - * 检查无障碍服务是否正在运行 - */ - private suspend fun isAccessibilityServiceEnabled(): Boolean { - return UIHierarchyManager.isAccessibilityServiceEnabled(context) - } - - /** - * 为需要无障碍服务的工具创建一个前置检查的包装器 - */ - private suspend fun withAccessibilityCheck(tool: AITool, block: suspend () -> T): T { - if (!isAccessibilityServiceEnabled()) { - throw IllegalStateException("Accessibility Service is not enabled. Please enable it in system settings to use this feature.") - } - return block() - } - - /** - * 获取UI层次结构,失败时重试 - * @return UI层次结构XML字符串,获取失败返回空字符串 - */ - private suspend fun getUIHierarchyWithRetry(): String { - var retryCount = 0 - var uiXml = "" - - while (retryCount < MAX_RETRY_COUNT) { - uiXml = UIHierarchyManager.getUIHierarchy(context) - if (uiXml.isNotEmpty()) { - return uiXml - } - - retryCount++ - if (retryCount < MAX_RETRY_COUNT) { - AppLogger.d(TAG, "获取UI层次结构失败,正在重试 #$retryCount") - delay(RETRY_DELAY_MS) - } - } - - AppLogger.w(TAG, "获取UI层次结构失败,已重试${MAX_RETRY_COUNT}次") - return uiXml - } - - /** Gets the current UI page/window information */ - override suspend fun getPageInfo(tool: AITool): ToolResult { - return try { - withAccessibilityCheck(tool) { - val format = tool.parameters.find { it.name == "format" }?.value ?: "xml" - val detail = tool.parameters.find { it.name == "detail" }?.value ?: "summary" - - if (format !in listOf("xml", "json")) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Invalid format specified. Must be 'xml' or 'json'." - ) - } - - // 使用无障碍服务获取UI数据(带重试) - val uiXml = getUIHierarchyWithRetry() - if (uiXml.isEmpty()) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to retrieve UI data via accessibility service." - ) - } - - // 解析当前窗口信息 - val focusInfo = extractFocusInfoFromAccessibility() - - // 简化布局信息 - val simplifiedLayout = simplifyLayout(uiXml) - - // 创建结构化数据 - val resultData = - UIPageResultData( - packageName = focusInfo.packageName ?: "Unknown", - activityName = focusInfo.activityName ?: "Unknown", - uiElements = simplifiedLayout - ) - - ToolResult(toolName = tool.name, success = true, result = resultData, error = "") - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error getting page info", e) - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error getting page info: ${e.message}" - ) - } - } - - /** 从无障碍服务获取焦点信息 */ - private suspend fun extractFocusInfoFromAccessibility(): FocusInfo { - val focusInfo = FocusInfo() - try { - // 1. 获取UI层次结构的XML快照(带重试) - val hierarchyXml = getUIHierarchyWithRetry() - if (hierarchyXml.isEmpty()) { - AppLogger.w(TAG, "无法获取UI层次结构XML,使用默认值。") - focusInfo.packageName = "android" - // 即使XML获取失败,仍然尝试获取Activity名称 - focusInfo.activityName = UIHierarchyManager.getCurrentActivityName(context) ?: "ForegroundActivity" - return focusInfo - } - - // 2. 从XML中解析包名 - val (packageName, _) = UIHierarchyManager.extractWindowInfo(hierarchyXml) - // 3. 从服务中直接获取当前Activity名称 - val activityName = UIHierarchyManager.getCurrentActivityName(context) - - focusInfo.packageName = packageName - focusInfo.activityName = activityName // 使用从服务获取的Activity名称 - - // 如果没有获取到,使用默认值 - if (focusInfo.packageName == null) focusInfo.packageName = "android" - if (focusInfo.activityName == null) focusInfo.activityName = "ForegroundActivity" - } catch (e: Exception) { - AppLogger.e(TAG, "从XML解析焦点信息时出错", e) - // 设置默认值 - focusInfo.packageName = "android" - focusInfo.activityName = "ForegroundActivity" - } - return focusInfo - } - - /** 简化XML布局为节点树 */ - fun simplifyLayout(xml: String): SimplifiedUINode { - val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } - val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } - - val nodeStack = mutableListOf() - var rootNode: UINode? = null - - while (parser.eventType != XmlPullParser.END_DOCUMENT) { - when (parser.eventType) { - XmlPullParser.START_TAG -> { - if (parser.name == "node") { - val newNode = createNode(parser) - if (rootNode == null) { - rootNode = newNode - nodeStack.add(newNode) - } else { - nodeStack.lastOrNull()?.children?.add(newNode) - nodeStack.add(newNode) - } - } - } - XmlPullParser.END_TAG -> { - if (parser.name == "node") { - nodeStack.removeLastOrNull() - } - } - } - parser.next() - } - - return rootNode?.toUINode() - ?: SimplifiedUINode( - className = null, - text = null, - contentDesc = null, - resourceId = null, - bounds = null, - isClickable = false, - children = emptyList() - ) - } - - private fun createNode(parser: XmlPullParser): UINode { - // 解析关键属性 - val className = parser.getAttributeValue(null, "class")?.substringAfterLast('.') - val text = parser.getAttributeValue(null, "text")?.replace(" ", "\n") - val contentDesc = parser.getAttributeValue(null, "content-desc") - val resourceId = parser.getAttributeValue(null, "resource-id") - val bounds = parser.getAttributeValue(null, "bounds") - val isClickable = parser.getAttributeValue(null, "clickable") == "true" - - return UINode( - className = className, - text = text, - contentDesc = contentDesc, - resourceId = resourceId, - bounds = bounds, - isClickable = isClickable - ) - } - - /** 点击元素 */ - override suspend fun clickElement(tool: AITool): ToolResult { - return try { - withAccessibilityCheck(tool) { - val resourceId = tool.parameters.find { it.name == "resourceId" }?.value - val className = tool.parameters.find { it.name == "className" }?.value - val contentDesc = tool.parameters.find { it.name == "contentDesc" }?.value - val index = tool.parameters.find { it.name == "index" }?.value?.toIntOrNull() ?: 0 - val bounds = tool.parameters.find { it.name == "bounds" }?.value - - if (resourceId == null && className == null && bounds == null && contentDesc == null) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Missing element identifier. Provide at least one of 'resourceId', 'className', 'contentDesc', or 'bounds'." - ) - } - - // 如果提供了边界坐标,直接解析并点击中心点 - if (bounds != null) { - return@withAccessibilityCheck handleClickByBounds(tool, bounds) - } - - // 获取UI层次结构XML(带重试) - val uiXml = getUIHierarchyWithRetry() - if (uiXml.isEmpty()) { - return@withAccessibilityCheck ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Unable to get UI hierarchy.") - } - - // 在XML中查找匹配的节点 - val matchedNodes = findNodesInXml(uiXml) { parser -> - val hasSelectors = resourceId != null || className != null || contentDesc != null - if (!hasSelectors) { - return@findNodesInXml false - } - - val actualId = parser.getAttributeValue(null, "resource-id") - val actualClass = parser.getAttributeValue(null, "class") - val actualDesc = parser.getAttributeValue(null, "content-desc") - - if(resourceId != null && (actualId == null || !actualId.endsWith(resourceId))){ - return@findNodesInXml false - } - - if(className != null && (actualClass == null || actualClass != className)){ - return@findNodesInXml false - } - - if(contentDesc != null && (actualDesc == null || !actualDesc.equals(contentDesc, ignoreCase = true))){ - return@findNodesInXml false - } - - true - } - - if (matchedNodes.isEmpty()) { - return@withAccessibilityCheck ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "No matching element found.") - } - - // 检查索引是否有效 - if (index < 0 || index >= matchedNodes.size) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Index out of range. Found ${matchedNodes.size} elements, but requested index $index." - ) - } - - // 获取目标节点的bounds - val targetNodeBounds = matchedNodes[index].bounds - if (targetNodeBounds == null) { - return@withAccessibilityCheck ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Target element has no bounds.") - } - - // 解析bounds并点击 - handleClickByBounds(tool, targetNodeBounds) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error clicking element", e) - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error clicking element: ${e.message}" - ) - } - } - - private suspend fun handleClickByBounds(tool: AITool, bounds: String): ToolResult { - try { - val rect = parseBounds(bounds) - if (rect.isEmpty) { - return ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Invalid bounds format: $bounds") - } - - val centerX = rect.centerX() - val centerY = rect.centerY() - - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - val clickSuccess = performAccessibilityClick(centerX, centerY) - - return if (clickSuccess) { - withContext(Dispatchers.Main) { - operationOverlay.showTap(centerX, centerY) - operationOverlay.hide() - } - ToolResult( - toolName = tool.name, - success = true, - result = UIActionResultData( - actionType = "click", - actionDescription = "Successfully clicked at bounds $bounds", - coordinates = Pair(centerX, centerY) - ) - ) - } else { - operationOverlay.hide() - ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Failed to click at bounds $bounds via accessibility service.") - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error clicking by bounds", e) - operationOverlay.hide() - return ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Error clicking at bounds: ${e.message}") - } - } - - private fun findNodesInXml(xml: String, predicate: (parser: XmlPullParser) -> Boolean): List { - val matchedNodes = mutableListOf() - val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } - val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } - - while (parser.eventType != XmlPullParser.END_DOCUMENT) { - if (parser.eventType == XmlPullParser.START_TAG && parser.name == "node") { - if (predicate(parser)) { - matchedNodes.add( - NodeInfo( - bounds = parser.getAttributeValue(null, "bounds"), - text = parser.getAttributeValue(null, "text") - ) - ) - } - } - parser.next() - } - return matchedNodes - } - - private data class NodeInfo(val bounds: String?, val text: String?) - - /** 设置输入文本 */ - override suspend fun setInputText(tool: AITool): ToolResult { - return try { - withAccessibilityCheck(tool) { - val text = tool.parameters.find { it.name == "text" }?.value ?: "" - - // 通过UIHierarchyManager请求远程服务找到焦点节点的ID - val focusedNodeId = UIHierarchyManager.findFocusedNodeId(context) - if (focusedNodeId.isNullOrEmpty()) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "No focused editable field found." - ) - } - - // 显示反馈 - val rect = parseBounds(focusedNodeId) - if (!rect.isEmpty) { - operationOverlay.showTextInput(rect.centerX(), rect.centerY(), text) - } - - // 通过UIHierarchyManager请求远程服务设置文本 - val result = UIHierarchyManager.setTextOnNode(context, focusedNodeId, text) - - if (result) { - // 成功后主动隐藏overlay - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "textInput", - actionDescription = - "Successfully set input text via accessibility service" - ), - error = "" - ) - } else { - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to set text via accessibility service." - ) - } - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error setting input text", e) - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error setting input text: ${e.message}" - ) - } - } - - /** 执行轻触操作 */ - override suspend fun tap(tool: AITool): ToolResult { - return try { - withAccessibilityCheck(tool) { - val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() - val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() - - if (x == null || y == null) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." - ) - } - - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - - // 使用无障碍服务执行点击 - val result = performAccessibilityClick(x, y) - - if (result) { - withContext(Dispatchers.Main) { - operationOverlay.showTap(x, y) - operationOverlay.hide() - } - ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "tap", - actionDescription = - "Successfully tapped at coordinates ($x, $y) via accessibility service", - coordinates = Pair(x, y) - ), - error = "" - ) - } else { - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to tap at coordinates via accessibility service." - ) - } - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error tapping at coordinates", e) - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error tapping at coordinates: ${e.message}" - ) - } - } - - /** 执行长按操作 */ - override suspend fun longPress(tool: AITool): ToolResult { - return try { - withAccessibilityCheck(tool) { - val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() - val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() - - if (x == null || y == null) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." - ) - } - - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - - // 使用无障碍服务执行长按 - val result = performAccessibilityLongPress(x, y) - - if (result) { - withContext(Dispatchers.Main) { - operationOverlay.showTap(x, y) - operationOverlay.hide() - } - ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "long_press", - actionDescription = - "Successfully long pressed at coordinates ($x, $y) via accessibility service", - coordinates = Pair(x, y) - ), - error = "" - ) - } else { - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to long press at coordinates via accessibility service." - ) - } - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error long pressing at coordinates", e) - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error long pressing at coordinates: ${e.message}" - ) - } - } - - /** 执行滑动操作 */ - override suspend fun swipe(tool: AITool): ToolResult { - return try { - withAccessibilityCheck(tool) { - val startX = tool.parameters.find { it.name == "start_x" }?.value?.toIntOrNull() - val startY = tool.parameters.find { it.name == "start_y" }?.value?.toIntOrNull() - val endX = tool.parameters.find { it.name == "end_x" }?.value?.toIntOrNull() - val endY = tool.parameters.find { it.name == "end_y" }?.value?.toIntOrNull() - val duration = tool.parameters.find { it.name == "duration" }?.value?.toIntOrNull() ?: 300 - - if (startX == null || startY == null || endX == null || endY == null) { - return@withAccessibilityCheck ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Missing or invalid coordinates. 'start_x', 'start_y', 'end_x', and 'end_y' must be valid integers." - ) - } - - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - - // 使用无障碍服务执行滑动 - val result = performAccessibilitySwipe(startX, startY, endX, endY, duration) - - if (result) { - withContext(Dispatchers.Main) { - operationOverlay.showSwipe(startX, startY, endX, endY) - operationOverlay.hide() - } - ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "swipe", - actionDescription = - "Successfully performed swipe from ($startX, $startY) to ($endX, $endY) via accessibility service" - ), - error = "" - ) - } else { - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to perform swipe via accessibility service." - ) - } - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error performing swipe", e) - operationOverlay.hide() - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error performing swipe: ${e.message}" - ) - } - } - - // 使用无障碍服务执行点击的辅助方法 - private suspend fun performAccessibilityClick(x: Int, y: Int): Boolean { - return try { - UIHierarchyManager.performClick(context, x, y) - } catch (e: Exception) { - AppLogger.e(TAG, "Error performing accessibility click", e) - return false - } - } - - // 使用无障碍服务执行长按的辅助方法 - private suspend fun performAccessibilityLongPress(x: Int, y: Int): Boolean { - return try { - UIHierarchyManager.performLongPress(context, x, y) - } catch (e: Exception) { - AppLogger.e(TAG, "Error performing accessibility long press", e) - return false - } - } - - // 使用无障碍服务执行滑动的辅助方法 - private suspend fun performAccessibilitySwipe( - startX: Int, - startY: Int, - endX: Int, - endY: Int, - duration: Int - ): Boolean { - return try { - UIHierarchyManager.performSwipe(context, startX, startY, endX, endY, duration.toLong()) - } catch (e: Exception) { - AppLogger.e(TAG, "Error performing accessibility swipe", e) - return false - } - } - - protected fun accessibilityKeyAction(keyCode: String): Int? = when (keyCode) { - "KEYCODE_BACK" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_BACK - "KEYCODE_HOME" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_HOME - "KEYCODE_RECENTS" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_RECENTS - "KEYCODE_NOTIFICATIONS" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS - "KEYCODE_QUICK_SETTINGS" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS - "KEYCODE_POWER_DIALOG" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_POWER_DIALOG - else -> null - } - - /** 模拟按键操作 */ - override suspend fun pressKey(tool: AITool): ToolResult { - val keyCode = tool.parameters.find { it.name == "key_code" }?.value - - if (keyCode == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Missing 'key_code' parameter." - ) - } - - try { - // 将字符串keyCode转换为AccessibilityService中的常量 - val keyAction = accessibilityKeyAction(keyCode) - - if (keyAction != null) { - // 通过UIHierarchyManager请求远程服务执行操作 - val success = UIHierarchyManager.performGlobalAction(context, keyAction) - return if (success) { - ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "keyPress", - actionDescription = - "Successfully pressed key: $keyCode via accessibility service" - ), - error = "" - ) - } else { - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = - "Failed to press key: $keyCode via accessibility service. Not all keys are supported." - ) - } - } else { - // 如果不是标准全局操作,返回不支持的错误 - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = - "Key: $keyCode is not supported via accessibility service. Only system keys like BACK, HOME, etc. are supported." - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error pressing key", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error pressing key: ${e.message ?: "Unknown exception"}" - ) - } - } - - override suspend fun captureScreenshotToFile(tool: AITool): Pair?> { - return try { - val screenshotDir = OperitPaths.cleanOnExitDir() - - val shortName = System.currentTimeMillis().toString().takeLast(4) - val file = File(screenshotDir, "$shortName.png") - - val success = UIHierarchyManager.takeScreenshot(context, file.absolutePath, "png") - if (!success) { - AppLogger.w(TAG, "captureScreenshotForAgent: AIDL takeScreenshot failed") - return Pair(null, null) - } - - val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } - BitmapFactory.decodeFile(file.absolutePath, options) - val dimensions = if (options.outWidth > 0 && options.outHeight > 0) { - Pair(options.outWidth, options.outHeight) - } else { - null - } - - Pair(file.absolutePath, dimensions) - } catch (e: Exception) { - AppLogger.e(TAG, "captureScreenshot via accessibility failed", e) - Pair(null, null) - } - } - - override suspend fun captureScreenshot(tool: AITool): Pair?> { - return captureScreenshotToFile(tool) - } - - override suspend fun captureScreenshotBitmap(tool: AITool): Pair?> { - val (filePath, dimensions) = captureScreenshot(tool) - if (filePath == null) { - return Pair(null, dimensions) - } - - val bitmap = BitmapFactory.decodeFile(filePath) ?: return Pair(null, dimensions) - val resolvedDimensions = dimensions ?: Pair(bitmap.width, bitmap.height) - return Pair(bitmap, resolvedDimensions) - } - - private fun parseBounds(boundsString: String): android.graphics.Rect { - // 解析 "[left,top][right,bottom]" 格式的边界字符串 - val rect = android.graphics.Rect() - try { - val parts = boundsString.replace("[", "").replace("]", ",").split(",") - if (parts.size >= 4) { - rect.left = parts[0].toInt() - rect.top = parts[1].toInt() - rect.right = parts[2].toInt() - rect.bottom = parts[3].toInt() - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error parsing bounds: $boundsString", e) - } - return rect - } -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminDeviceInfoToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminDeviceInfoToolExecutor.kt deleted file mode 100644 index 8d23ab6a9d..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminDeviceInfoToolExecutor.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.admin - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.debugger.DebuggerDeviceInfoToolExecutor - -/** 管理员级别的设备信息工具,继承调试版本 */ -open class AdminDeviceInfoToolExecutor(context: Context) : DebuggerDeviceInfoToolExecutor(context) { - // 当前阶段不添加新功能,仅继承调试实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt index 7dd851e1bd..2d043eb36a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt @@ -1,15 +1,2937 @@ package com.ai.assistance.operit.core.tools.defaultTool.admin +import android.content.ActivityNotFoundException +import android.content.ClipData import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.debugger.DebuggerFileSystemTools +import android.content.Intent +import android.webkit.MimeTypeMap +import androidx.core.content.FileProvider +import com.ai.assistance.operit.BuildConfig +import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.DirectoryListingData +import com.ai.assistance.operit.core.tools.FileContentData +import com.ai.assistance.operit.core.tools.FileExistsData +import com.ai.assistance.operit.core.tools.FileInfoData +import com.ai.assistance.operit.core.tools.FileOperationData +import com.ai.assistance.operit.core.tools.FilePartContentData +import com.ai.assistance.operit.core.tools.FindFilesResultData +import com.ai.assistance.operit.core.tools.StringResultData +import com.ai.assistance.operit.core.tools.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.defaultTool.PathValidator import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardFileSystemTools import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver import com.ai.assistance.operit.core.tools.permissions.PermissionOperationRouter +import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor import com.ai.assistance.operit.data.model.AITool +import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult +import com.ai.assistance.operit.util.files.AndroidUserPathUtils +import com.ai.assistance.operit.util.files.FileUtils +import com.ai.assistance.operit.util.logging.AppLogger +import java.io.BufferedInputStream +import java.io.BufferedOutputStream +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.concurrent.atomic.AtomicInteger +import java.util.zip.ZipEntry +import java.util.zip.ZipFile +import java.util.zip.ZipInputStream +import java.util.zip.ZipOutputStream +import kotlin.math.exp +import kotlinx.coroutines.cancelAndJoin +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch + +/** 管理员文件工具按实际授权选择标准或 Shell 操作,Root 复用同一能力路由。 */ +open class AdminFileSystemTools(context: Context) : StandardFileSystemTools(context) { + companion object { + private const val TAG = "AdminFileSystemTools" + internal fun isOperitInternalPath(path: String): Boolean { + val normalizedPath = path.trim() + val appPackage = BuildConfig.APPLICATION_ID + return normalizedPath.startsWith("/data/data/$appPackage") || + AndroidUserPathUtils.isCurrentUserPackageDataPath(normalizedPath, appPackage) + } + } + + /** + * 判断路径是否为Operit应用的内部存储路径 + * 仅针对 Operit 应用自身数据目录路径返回true + */ + protected fun isOperitInternalPath(path: String): Boolean { + return Companion.isOperitInternalPath(path) + } + + private fun shQuote(value: String): String { + return "'" + value.replace("'", "'\"'\"'") + "'" + } + + private fun smoothProgress(count: Int, scale: Float): Float { + if (count <= 0) return 0f + return (1f - exp(-count / scale)).coerceIn(0f, 0.99f) + } + + private fun updateProgressFloor(progressFloor: AtomicInteger, candidate: Int) { + while (true) { + val old = progressFloor.get() + if (candidate <= old) return + if (progressFloor.compareAndSet(old, candidate)) return + } + } + + /** List files in a directory */ + private suspend fun listFilesWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.listFiles(tool) + } + if (isSafEnvironment(environment)) { + return super.listFiles(tool) + } + + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 应用内部路径由标准文件实现处理,保留应用自身访问能力。 + if (isOperitInternalPath(path)) { + return super.listFiles(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Path parameter is required" + ) + } + + return try { + // 确保目录路径末尾有斜杠 + val normalizedPath = if (path.endsWith("/")) path else "$path/" + + // 使用ls -la命令获取详细的文件列表 + AppLogger.d(TAG, "Using ls -la command for path: $normalizedPath") + val listResult = AndroidShellExecutor.executeShellCommand("ls -la '$normalizedPath'") + + if (listResult.success) { + AppLogger.d(TAG, "ls -la command output: ${listResult.stdout}") + + // 解析ls -la命令输出 + val entries = parseDetailedDirectoryListing(listResult.stdout, normalizedPath) + + AppLogger.d(TAG, "Parsed ${entries.size} entries from ls -la output") + + return ToolResult( + toolName = tool.name, + success = true, + result = DirectoryListingData(path, entries), + error = "" + ) + } else { + AppLogger.w(TAG, "ls -la command failed: ${listResult.stderr}") + + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to list directory: ${listResult.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error listing directory", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error listing directory: ${e.message}" + ) + } + } + + /** Parse the output of the ls -la command into structured data */ + protected fun parseDetailedDirectoryListing( + output: String, + path: String + ): List { + val lines = output.trim().split("\n") + val entries = mutableListOf() + + AppLogger.d(TAG, "Parsing ${lines.size} lines from ls -la output") + + // 跳过第一行总计行 + val startIndex = if (lines.isNotEmpty() && lines[0].startsWith("total")) 1 else 0 + + // 日期格式化器,用于解析日期时间字符串 + val dateFormat = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm", java.util.Locale.US) + + for (i in startIndex until lines.size) { + try { + val line = lines[i] + if (line.isBlank()) continue + + // 打印每一行以便调试 + AppLogger.d(TAG, "Parsing line: $line") + + // Android上ls -la输出格式: crwxrw--- 2 u0_a425 media_rw 4056 2025-03-14 + // 06:04 Android + // 符号链接格式: lrwxrwxrwx 1 root root 12 2025-03-14 06:04 filename -> + // /path/to/target + + // 使用正则表达式解析Android上的ls -la输出 + val androidRegex = + """^(\S+)\s+(\d+)\s+(\S+\s*\S*)\s+(\S+)\s+(\d+)\s+(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2})\s+(.+)$""".toRegex() + val androidMatch = androidRegex.find(line) + + if (androidMatch != null) { + // 特定于Android的格式解析 + val permissions = androidMatch.groupValues[1] + val size = androidMatch.groupValues[5].toLongOrNull() ?: 0 + val date = androidMatch.groupValues[6] + val time = androidMatch.groupValues[7] + var name = androidMatch.groupValues[8] + val isDirectory = permissions.startsWith("d") || permissions.startsWith("c") + val isSymlink = permissions.startsWith("l") + + // 处理符号链接格式 "name -> target" + if (isSymlink && name.contains(" -> ")) { + name = name.substringBefore(" -> ") + AppLogger.d(TAG, "Found symlink: $name") + } + + // 跳过 . 和 .. 条目 + if (name == "." || name == "..") continue + + // 将日期和时间转换为时间戳 + val dateTimeStr = "$date $time" + val timestamp = + try { + val parsedDate = dateFormat.parse(dateTimeStr) + parsedDate?.time?.toString() ?: "0" + } catch (e: Exception) { + AppLogger.e(TAG, "Error parsing date: $dateTimeStr", e) + "0" // 解析失败时使用默认时间戳 + } + + AppLogger.d( + TAG, + "Successfully parsed $name with date $dateTimeStr -> timestamp $timestamp" + ) + + entries.add( + DirectoryListingData.FileEntry( + name = name, + isDirectory = isDirectory, + size = size, + permissions = permissions, + lastModified = timestamp // 使用时间戳字符串 + ) + ) + continue + } + + // 如果Android特定格式不匹配,尝试通用格式 + val genericRegex = + """^([\-ld][\w-]{9})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+([\w\d\s\-:\.]+)\s+(.+)$""".toRegex() + val match = genericRegex.find(line) + + if (match != null) { + val permissions = match.groupValues[1] + val size = match.groupValues[5].toLongOrNull() ?: 0 + val dateTimeStr = match.groupValues[6].trim() + var name = match.groupValues[7] + val isDirectory = permissions.startsWith("d") + val isSymlink = permissions.startsWith("l") + + // 处理符号链接格式 "name -> target" + if (isSymlink && name.contains(" -> ")) { + name = name.substringBefore(" -> ") + AppLogger.d(TAG, "Found symlink (generic): $name") + } + + // 跳过 . 和 .. 条目 + if (name == "." || name == "..") continue + + // 尝试解析通用格式的日期时间 + val timestamp = + try { + if (dateTimeStr.matches( + """^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}$""".toRegex() + ) + ) { + val parsedDate = dateFormat.parse(dateTimeStr) + parsedDate?.time?.toString() ?: "0" + } else { + // 如果不是YYYY-MM-DD HH:MM格式,返回当前时间 + System.currentTimeMillis().toString() + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error parsing generic date: $dateTimeStr", e) + "0" + } + + entries.add( + DirectoryListingData.FileEntry( + name = name, + isDirectory = isDirectory, + size = size, + permissions = permissions, + lastModified = timestamp + ) + ) + } else { + // 如果标准正则表达式也不匹配,使用更宽松的解析方法 + // 权限字段始终是10个字符 + if (line.length < 10) continue + + val permissions = line.substring(0, 10).trim() + val isDirectory = permissions.startsWith("d") || permissions.startsWith("c") + + // 解析剩余部分 + val parts = line.substring(10).trim().split("\\s+".toRegex()) + + if (parts.size < 6) { + AppLogger.w(TAG, "Invalid ls -la format: $line") + continue + } + + // 查找日期部分 - Android上通常是YYYY-MM-DD格式 + val dateIndex = + parts.indexOfFirst { it.matches("""^\d{4}-\d{2}-\d{2}$""".toRegex()) } + + if (dateIndex < 0 || dateIndex + 1 >= parts.size) { + AppLogger.w(TAG, "Cannot find date in line: $line") + continue + } + + // 日期后面的字段通常是时间 (HH:MM) + val timeIndex = dateIndex + 1 + + // 时间后面的所有内容都是文件名 + val nameStartIndex = timeIndex + 1 + if (nameStartIndex >= parts.size) { + AppLogger.w(TAG, "Cannot find filename position: $line") + continue + } + + var name = parts.subList(nameStartIndex, parts.size).joinToString(" ") + val isSymlink = permissions.startsWith("l") + + // 处理符号链接格式 "name -> target" + if (isSymlink && name.contains(" -> ")) { + name = name.substringBefore(" -> ") + AppLogger.d(TAG, "Found symlink (fallback): $name") + } + + // 跳过 . 和 .. 条目 + if (name == "." || name == "..") continue + + // 文件大小通常在用户和组之后,日期之前 + val sizeIndex = dateIndex - 1 + val size = if (sizeIndex >= 0) parts[sizeIndex].toLongOrNull() ?: 0 else 0 + + // 组合日期和时间,并转换为时间戳 + val dateTimeStr = "${parts[dateIndex]} ${parts[timeIndex]}" + val timestamp = + try { + val parsedDate = dateFormat.parse(dateTimeStr) + parsedDate?.time?.toString() ?: "0" + } catch (e: Exception) { + AppLogger.e(TAG, "Error parsing fallback date: $dateTimeStr", e) + "0" + } + + entries.add( + DirectoryListingData.FileEntry( + name = name, + isDirectory = isDirectory, + size = size, + permissions = permissions, + lastModified = timestamp + ) + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error parsing directory entry: ${lines[i]}", e) + // 跳过这一行但继续处理其他行 + } + } + + return entries + } + + /** 将八进制权限格式转换为字符串表示 (如 "rwxr-xr-x") */ + protected fun convertOctalPermToString(octalPerm: String): String { + try { + val permInt = octalPerm.toInt(8) + val permChars = CharArray(9) + + // 所有者权限 + permChars[0] = if (permInt and 0x100 != 0) 'r' else '-' + permChars[1] = if (permInt and 0x80 != 0) 'w' else '-' + permChars[2] = if (permInt and 0x40 != 0) 'x' else '-' + + // 组权限 + permChars[3] = if (permInt and 0x20 != 0) 'r' else '-' + permChars[4] = if (permInt and 0x10 != 0) 'w' else '-' + permChars[5] = if (permInt and 0x8 != 0) 'x' else '-' + + // 其他用户权限 + permChars[6] = if (permInt and 0x4 != 0) 'r' else '-' + permChars[7] = if (permInt and 0x2 != 0) 'w' else '-' + permChars[8] = if (permInt and 0x1 != 0) 'x' else '-' + + return String(permChars) + } catch (e: Exception) { + AppLogger.e(TAG, "Error converting octal permission: $octalPerm", e) + return "???" + } + } + + /** + * Reads the full content of a file as a new tool, handling different file types. + * This function does not enforce a size limit. + */ + private suspend fun readFileFullWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.readFileFull(tool) + } + if (isSafEnvironment(environment)) { + return super.readFileFull(tool) + } + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + val textOnly = tool.parameters.find { it.name == "text_only" }?.value?.toBoolean() ?: false + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.readFileFull(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Path parameter is required" + ) + } + + try { + // First check if the file exists using shell command + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -f '$path' && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "File does not exist: $path" + ) + } + + // Check file extension + val fileExt = path.substringAfterLast('.', "").lowercase() + + // Handle special file types by calling the parent's handler + val specialReadResult = super.handleSpecialFileRead(tool, path, fileExt) + if (specialReadResult != null) { + // If the parent handled it, return its result. + // But if it failed, we might want to fall back to shell `cat` for some types. + if (specialReadResult.success) { + return specialReadResult + } + // Optional: Could add fallback logic here if superclass fails for some reason + } + + // Check if file is text-like by reading first few bytes (if text_only is enabled) + if (textOnly) { + // First, get a sample of the file + val sampleResult = AndroidShellExecutor.executeShellCommand("head -c 512 '$path'") + if (!sampleResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to sample file: ${sampleResult.stderr}" + ) + } + + // Analyze the sample bytes + val sampleBytes = sampleResult.stdout.toByteArray() + if (!FileUtils.isTextLike(sampleBytes)) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Skipped non-text file: $path" + ) + } + } + + // For text-like files, use shell `cat` to read full content + val result = AndroidShellExecutor.executeShellCommand("cat '$path'") + if (result.success) { + val sizeResult = + AndroidShellExecutor.executeShellCommand("stat -c %s '$path'") + val size = + sizeResult.stdout.trim().toLongOrNull() + ?: result.stdout.length.toLong() + + return ToolResult( + toolName = tool.name, + success = true, + result = + FileContentData( + path = path, + content = result.stdout, + size = size + ), + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to read file: ${result.stderr}" + ) + } + + } catch (e: Exception) { + AppLogger.e(TAG, "Error reading file", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error reading file: ${e.message}" + ) + } + } + + /** Read file content */ + private suspend fun readFileWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.readFile(tool) + } + if (isSafEnvironment(environment)) { + return super.readFile(tool) + } + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.readFile(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Path parameter is required" + ) + } + + try { + val fileExt = path.substringAfterLast('.', "").lowercase() + + // For special types, full read then truncate text is the only way. + if (isSpecialFileType(fileExt)) { + val fullResult = readFileFull(tool) + if (!fullResult.success) return fullResult + + val contentData = fullResult.result as FileContentData + var content = contentData.content + val isTruncated = content.length > ToolExecutionLimits.MAX_FILE_READ_BYTES + if (isTruncated) { + content = content.substring(0, ToolExecutionLimits.MAX_FILE_READ_BYTES) + } + + var contentWithLineNumbers = addLineNumbers(content) + if (isTruncated) { + contentWithLineNumbers += "\n\n... (file content truncated) ..." + } + + return ToolResult( + toolName = tool.name, + success = true, + result = FileContentData(path = path, content = contentWithLineNumbers, size = contentWithLineNumbers.length.toLong()), + error = "" + ) + } + + // For text-based files, read only the beginning. + // Check if file is text-like by analyzing a sample + val sampleResult = AndroidShellExecutor.executeShellCommand("head -c 512 '$path'") + if (sampleResult.success) { + val sampleBytes = sampleResult.stdout.toByteArray() + if (!FileUtils.isTextLike(sampleBytes)) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "File does not appear to be a text file. Use readFileFull tool for special file types." + ) + } + } + + // Check file size to see if truncation is needed + val sizeResult = AndroidShellExecutor.executeShellCommand("stat -c %s '$path'") + val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 + val truncated = size > ToolExecutionLimits.MAX_FILE_READ_BYTES + + val readCommand = "head -c ${ToolExecutionLimits.MAX_FILE_READ_BYTES} '$path'" + val readResult = AndroidShellExecutor.executeShellCommand(readCommand) + + if (!readResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to read file: ${readResult.stderr}" + ) + } + + var content = readResult.stdout + var contentWithLineNumbers = addLineNumbers(content) + if (truncated) { + contentWithLineNumbers += "\n\n... (file content truncated) ..." + } + + return ToolResult( + toolName = tool.name, + success = true, + result = + FileContentData( + path = path, + content = contentWithLineNumbers, + size = contentWithLineNumbers.length.toLong() + ), + error = "" + ) + } catch (e: Exception) { + AppLogger.e(TAG, "Error reading file", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error reading file: ${e.message}" + ) + } + } + + /** 按行号范围读取文件内容(行号从1开始,包括开始行和结束行) */ + private suspend fun readFilePartWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.readFilePart(tool) + } + if (isSafEnvironment(environment)) { + return super.readFilePart(tool) + } + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.readFilePart(tool) + } + val startLineParam = tool.parameters.find { it.name == "start_line" }?.value?.toIntOrNull() ?: 1 + val endLineParam = tool.parameters.find { it.name == "end_line" }?.value?.toIntOrNull() + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Path parameter is required" + ) + } + + return try { + // 0. 特殊文件类型检查 + // 如果是Word/PDF/图片等特殊文件,使用父类(StandardFileSystemTools)的逻辑处理 + // 因为Shell命令(cat/sed)无法正确解析这些二进制格式 + val fileExt = path.substringAfterLast('.', "").lowercase() + if (isSpecialFileType(fileExt)) { + return super.readFilePart(tool) + } + + // 1. Check if file exists + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -f '$path' && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "File does not exist: $path" + ) + } + + // 2. Get total number of lines + val wcResult = AndroidShellExecutor.executeShellCommand("cat '$path' | wc -l") + if (!wcResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to count lines in file: ${wcResult.stderr}" + ) + } + + val totalLines = wcResult.stdout.trim().split(" ")[0].toIntOrNull() ?: 0 + + // 3. 计算实际的行号范围(行号从1开始) + val startLine = maxOf(1, startLineParam).coerceIn(1, maxOf(1, totalLines)) + val endLine = + (endLineParam + ?: (startLine + ToolExecutionLimits.DEFAULT_FILE_READ_PART_LINES - 1)) + .coerceIn(startLine, maxOf(1, totalLines)) + + if (totalLines == 0 || startLine > endLine) { + return ToolResult( + toolName = tool.name, + success = true, + result = + FilePartContentData( + path = path, + content = "", + partIndex = 0, // 保留兼容性,但不再使用 + totalParts = 1, // 保留兼容性,但不再使用 + startLine = startLine - 1, // 转为0-based + endLine = endLine, + totalLines = totalLines + ), + error = "" + ) + } + + // 4. Extract the specific part using sed + val sedCommand = "sed -n '${startLine},${endLine}p' '$path'" + val partResult = AndroidShellExecutor.executeShellCommand(sedCommand) + + if (!partResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to read file part: ${partResult.stderr}" + ) + } + + val maxFileSizeBytes = ToolExecutionLimits.MAX_FILE_READ_BYTES + var content = partResult.stdout + val isTruncated = content.length > maxFileSizeBytes + if (isTruncated) { + content = content.substring(0, maxFileSizeBytes) + } + + var contentWithLineNumbers = addLineNumbers(content, startLine, totalLines) + if (isTruncated) { + contentWithLineNumbers += "\n\n... (file content truncated) ..." + } + + ToolResult( + toolName = tool.name, + success = true, + result = + FilePartContentData( + path = path, + content = contentWithLineNumbers.trimEnd(), + partIndex = 0, // 保留兼容性,但不再使用 + totalParts = 1, // 保留兼容性,但不再使用 + startLine = startLine - 1, // To 0-indexed for response + endLine = endLine, + totalLines = totalLines + ), + error = "" + ) + } catch (e: Exception) { + AppLogger.e(TAG, "Error reading file part", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error reading file part: ${e.message}" + ) + } + } + + /** + * 重写特殊文件读取逻辑 + * 对于受保护的路径(如 /Android/data),先通过Shell命令复制到缓存目录, + * 再调用父类的解析逻辑。 + */ + override suspend fun handleSpecialFileRead( + tool: AITool, + path: String, + fileExt: String + ): ToolResult? { + val file = File(path) + + if (isOperitInternalPath(path)) { + return super.handleSpecialFileRead(tool, path, fileExt) + } + + // 如果文件可读,直接使用父类逻辑(更高效) + if (file.exists() && file.canRead()) { + return super.handleSpecialFileRead(tool, path, fileExt) + } + + AppLogger.d(TAG, "File not directly readable (permission restricted), trying Shell copy for: $path") + + // 创建临时文件用于中转 + val tempFile = File(context.cacheDir, "shell_copy_${System.currentTimeMillis()}.$fileExt") + + return try { + // 使用cat命令复制文件内容 + // 注意:使用cat而不是cp,因为cp可能保留权限属性导致仍然无法读取 + val copyResult = AndroidShellExecutor.executeShellCommand("cat '$path' > '${tempFile.absolutePath}'") + + if (!copyResult.success) { + AppLogger.w(TAG, "Shell copy failed: ${copyResult.stderr}") + // 复制失败,回退到父类逻辑(虽然很可能也失败,但能返回一致的错误信息) + return super.handleSpecialFileRead(tool, path, fileExt) + } + + // 检查临时文件是否有效 + if (!tempFile.exists() || tempFile.length() == 0L) { + AppLogger.w(TAG, "Temp file is empty or does not exist after copy") + return super.handleSpecialFileRead(tool, path, fileExt) + } + + // 使用临时文件路径调用父类处理逻辑 + val tempToolResult = super.handleSpecialFileRead(tool, tempFile.absolutePath, fileExt) + + // 如果处理成功,修正返回结果中的 path 为原始路径 + if (tempToolResult != null && tempToolResult.success) { + val resultData = tempToolResult.result + if (resultData is FileContentData) { + return tempToolResult.copy( + result = resultData.copy(path = path) + ) + } + } + + tempToolResult + + } catch (e: Exception) { + AppLogger.e(TAG, "Error in shell copy strategy", e) + super.handleSpecialFileRead(tool, path, fileExt) + } finally { + // 清理临时文件 + try { + if (tempFile.exists()) { + tempFile.delete() + } + } catch (e: Exception) { + AppLogger.e(TAG, "Failed to clean up temp file", e) + } + } + } + + /** Write content to a file */ + private suspend fun writeFileWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.writeFile(tool) + } + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + if (isSafEnvironment(environment)) { + return super.writeFile(tool) + } + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + val content = tool.parameters.find { it.name == "content" }?.value ?: "" + val append = tool.parameters.find { it.name == "append" }?.value?.toBoolean() ?: false + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.writeFile(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "write", + path = "", + successful = false, + details = "Path parameter is required" + ), + error = "Path parameter is required" + ) + } + + return try { + // 确保目标目录存在 + val directory = File(path).parent + if (directory != null) { + val mkdirResult = AndroidShellExecutor.executeShellCommand("mkdir -p '$directory'") + if (!mkdirResult.success) { + AppLogger.w(TAG, "Warning: Failed to create parent directory: ${mkdirResult.stderr}") + } + } + + // 直接使用echo命令写入内容 + // 对内容进行base64编码,避免特殊字符问题 + val contentBase64 = + android.util.Base64.encodeToString( + content.toByteArray(), + android.util.Base64.NO_WRAP + ) + + // 使用 base64 写入;大内容分块,失败后不重新提交已写入的数据。 + val redirectOperator = if (append) ">>" else ">" + val maxInlineBase64 = 32768 + val base64ChunkSize = 16384 // 4的倍数,保证base64解码边界正确 + val writeResult = + if (contentBase64.length <= maxInlineBase64) { + AndroidShellExecutor.executeShellCommand( + "echo '$contentBase64' | base64 -d $redirectOperator '$path'" + ) + } else { + var chunkSuccess = true + var firstChunk = true + var index = 0 + while (index < contentBase64.length) { + val end = (index + base64ChunkSize).coerceAtMost(contentBase64.length) + val chunk = contentBase64.substring(index, end) + val chunkRedirect = if (firstChunk) redirectOperator else ">>" + val chunkResult = + AndroidShellExecutor.executeShellCommand( + "echo '$chunk' | base64 -d $chunkRedirect '$path'" + ) + if (!chunkResult.success) { + AppLogger.e( + TAG, + "Failed to write base64 chunk: ${chunkResult.stderr}" + ) + chunkSuccess = false + break + } + firstChunk = false + index = end + } + if (chunkSuccess) { + AndroidShellExecutor.CommandResult(true, "", "", 0) + } else { + AndroidShellExecutor.CommandResult(false, "", "Failed to write base64 chunks") + } + } + + if (!writeResult.success) { + AppLogger.e(TAG, "Failed to write with base64 method: ${writeResult.stderr}") + return ToolResult( + toolName = tool.name, + success = false, + result = FileOperationData( + operation = if (append) "append" else "write", + path = path, + successful = false, + details = "Failed to write to file: ${writeResult.stderr}" + ), + error = "Failed to write to file: ${writeResult.stderr}" + ) + } + + // 验证写入是否成功 + val verifyResult = + AndroidShellExecutor.executeShellCommand( + "test -f '$path' && echo 'exists' || echo 'not exists'" + ) + if (verifyResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = if (append) "append" else "write", + path = path, + successful = false, + details = + "Write command completed but file does not exist. Possible permission issue." + ), + error = + "Write command completed but file does not exist. Possible permission issue." + ) + } + + // 检查文件大小确认内容被写入 + val sizeResult = + AndroidShellExecutor.executeShellCommand( + "stat -c %s '$path' 2>/dev/null || echo '0'" + ) + val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 + if (size == 0L && content.isNotEmpty()) { + // 文件存在但是大小为0,可能写入失败 + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = if (append) "append" else "write", + path = path, + successful = false, + details = + "File was created but appears to be empty. Possible write failure." + ), + error = "File was created but appears to be empty. Possible write failure." + ) + } + + val operation = if (append) "append" else "write" + val details = if (append) "Content appended to $path" else "Content written to $path" + + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = operation, + path = path, + successful = true, + details = details + ), + error = "" + ) + } catch (e: Exception) { + AppLogger.e(TAG, "Error writing to file", e) + + // 提供更具体的错误信息 + val errorMessage = + when { + e is InterruptedException || + e.message?.contains("interrupted", ignoreCase = true) == true -> + "ADB connection interrupted, possibly due to network instability. Please check ADB connection and retry. Error details: ${e.message}" + e is java.net.SocketException || + e.message?.contains("socket", ignoreCase = true) == true -> + "ADB network connection exception, please check if device is still connected and retry. Error details: ${e.message}" + e is java.io.IOException -> "File IO error: ${e.message}. Please check if the file path has write permission." + e.message?.contains("permission", ignoreCase = true) == true -> + "Permission denied, cannot write to file: ${e.message}. Please check if the app has appropriate permissions." + else -> "Error writing to file: ${e.message}" + } + + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = if (append) "append" else "write", + path = path, + successful = false, + details = errorMessage + ), + error = errorMessage + ) + } + } + + /** Delete a file or directory */ + private suspend fun deleteFileWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.deleteFile(tool) + } + + if (isSafEnvironment(environment)) { + return super.deleteFile(tool) + } + + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.deleteFile(tool) + } + val recursive = tool.parameters.find { it.name == "recursive" }?.value?.toBoolean() ?: false + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "delete", + path = "", + successful = false, + details = "Path parameter is required" + ), + error = "Path parameter is required" + ) + } + + + return try { + val quotedPath = shQuote(path) + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -e $quotedPath && echo 'exists' || echo 'missing'" + ) + if (existsResult.stdout.trim() != "exists") { + ToolProgressBus.update(tool.name, 1f, "Delete failed") + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "delete", + path = path, + successful = false, + details = "File or directory does not exist: $path" + ), + error = "File or directory does not exist: $path" + ) + } + + val typeResult = + AndroidShellExecutor.executeShellCommand( + "if test -d $quotedPath; then echo 'directory'; elif test -f $quotedPath; then echo 'file'; else echo 'other'; fi" + ) + val isDirectory = typeResult.stdout.trim() == "directory" + + ToolProgressBus.update( + tool.name, + 0.1f, + if (isDirectory) "Deleting directory..." else "Deleting file..." + ) + + val deleteCommand = + if (recursive) "rm -rf $quotedPath" else if (isDirectory) "rmdir $quotedPath" else "rm -f $quotedPath" + val result = AndroidShellExecutor.executeShellCommand(deleteCommand) + + if (result.success && isDirectory && recursive) { + ToolProgressBus.update(tool.name, 0.85f, "Finalizing directory deletion...") + AndroidShellExecutor.executeShellCommand("rmdir $quotedPath") + } + + val verifyDeletedResult = + AndroidShellExecutor.executeShellCommand( + "test -e $quotedPath && echo 'exists' || echo 'missing'" + ) + val deleted = verifyDeletedResult.stdout.trim() != "exists" + + if (result.success && deleted) { + ToolProgressBus.update(tool.name, 1f, "Delete completed") + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "delete", + path = path, + successful = true, + details = "Successfully deleted $path" + ), + error = "" + ) + } else { + val errorMessage = + when { + !result.success && result.stderr.isNotBlank() -> + "Failed to delete: ${result.stderr}" + !deleted -> "Failed to delete: target still exists after delete command" + else -> "Failed to delete: unknown error" + } + ToolProgressBus.update(tool.name, 1f, "Delete failed") + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "delete", + path = path, + successful = false, + details = errorMessage + ), + error = errorMessage + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error deleting file/directory", e) + ToolProgressBus.update(tool.name, 1f, "Delete failed") + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "delete", + path = path, + successful = false, + details = "Error deleting file/directory: ${e.message}" + ), + error = "Error deleting file/directory: ${e.message}" + ) + } + } + + /** Check if a file or directory exists */ + private suspend fun fileExistsWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.fileExists(tool) + } + + if (isSafEnvironment(environment)) { + return super.fileExists(tool) + } + + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.fileExists(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Path parameter is required" + ) + } + + return try { + // Check if the path exists + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -e '$path' && echo 'exists' || echo 'not exists'" + ) + val exists = existsResult.success && existsResult.stdout.trim() == "exists" + + if (!exists) { + // If it doesn't exist, return a simple FileExistsData with + // exists=false + return ToolResult( + toolName = tool.name, + success = true, + result = FileExistsData(path = path, exists = false), + error = "" + ) + } + + // If it exists, check if it's a directory + val isDirResult = + AndroidShellExecutor.executeShellCommand( + "test -d '$path' && echo 'true' || echo 'false'" + ) + val isDirectory = isDirResult.success && isDirResult.stdout.trim() == "true" + + // Get the size + val sizeResult = + AndroidShellExecutor.executeShellCommand( + "stat -c %s '$path' 2>/dev/null || echo '0'" + ) + val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 + + return ToolResult( + toolName = tool.name, + success = true, + result = + FileExistsData( + path = path, + exists = true, + isDirectory = isDirectory, + size = size + ), + error = "" + ) + } catch (e: Exception) { + AppLogger.e(TAG, "Error checking file existence", e) + return ToolResult( + toolName = tool.name, + success = false, + result = + FileExistsData( + path = path, + exists = false, + isDirectory = false, + size = 0 + ), + error = "Error checking file existence: ${e.message}" + ) + } + } + + /** Move or rename a file or directory */ + private suspend fun moveFileWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.moveFile(tool) + } + val sourcePath = tool.parameters.find { it.name == "source" }?.value ?: "" + val destPath = tool.parameters.find { it.name == "destination" }?.value ?: "" + if (isSafEnvironment(environment)) { + return super.moveFile(tool) + } + PathValidator.validateAndroidPath(sourcePath, tool.name)?.let { return it } + PathValidator.validateAndroidPath(destPath, tool.name)?.let { return it } + + // 如果源文件或目标文件在Operit内部存储,使用super的高权限方法 + if (isOperitInternalPath(sourcePath) || isOperitInternalPath(destPath)) { + return super.moveFile(tool) + } + PathValidator.validateAndroidPath(destPath, tool.name, "destination")?.let { return it } + + if (sourcePath.isBlank() || destPath.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "move", + path = sourcePath, + successful = false, + details = "Source and destination parameters are required" + ), + error = "Source and destination parameters are required" + ) + } + + + return try { + val result = AndroidShellExecutor.executeShellCommand("mv '$sourcePath' '$destPath'") + + if (result.success) { + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "move", + path = sourcePath, + successful = true, + details = "Successfully moved $sourcePath to $destPath" + ), + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "move", + path = sourcePath, + successful = false, + details = "Failed to move file: ${result.stderr}" + ), + error = "Failed to move file: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error moving file", e) + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "move", + path = sourcePath, + successful = false, + details = "Error moving file: ${e.message}" + ), + error = "Error moving file: ${e.message}" + ) + } + } + + /** Copy a file or directory */ + private suspend fun copyFileWithShell(tool: AITool): ToolResult { + // 检查是否是 Linux 环境或跨环境操作 + val environment = tool.parameters.find { it.name == "environment" }?.value + val sourceEnvironment = tool.parameters.find { it.name == "source_environment" }?.value + val destEnvironment = tool.parameters.find { it.name == "dest_environment" }?.value + + // 确定源和目标环境 + val srcEnv = sourceEnvironment ?: environment ?: "android" + val dstEnv = destEnvironment ?: environment ?: "android" + + // 如果是 Linux 环境或跨环境操作,委托给父类处理 + if (srcEnv.lowercase() == "linux" || dstEnv.lowercase() == "linux") { + return super.copyFile(tool) + } + + val sourcePath = tool.parameters.find { it.name == "source" }?.value ?: "" + val destPath = tool.parameters.find { it.name == "destination" }?.value ?: "" + val recursive = tool.parameters.find { it.name == "recursive" }?.value?.toBoolean() ?: true + if (sourcePath.startsWith("content://", ignoreCase = true) || destPath.startsWith("content://", ignoreCase = true)) { + return super.copyFile(tool) + } + PathValidator.validateAndroidPath(sourcePath, tool.name, "source")?.let { return it } + PathValidator.validateAndroidPath(destPath, tool.name, "destination")?.let { return it } + + // 如果源文件或目标文件在Operit内部存储,使用super的高权限方法 + if (isOperitInternalPath(sourcePath) || isOperitInternalPath(destPath)) { + return super.copyFile(tool) + } + + if (sourcePath.isBlank() || destPath.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "copy", + path = sourcePath, + successful = false, + details = "Source and destination parameters are required" + ), + error = "Source and destination parameters are required" + ) + } + + return try { + // 首先检查源路径是否存在 + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -e '$sourcePath' && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "copy", + path = sourcePath, + successful = false, + details = "Source path does not exist: $sourcePath" + ), + error = "Source path does not exist: $sourcePath" + ) + } + + // 检查是否为目录 + val isDirResult = + AndroidShellExecutor.executeShellCommand( + "test -d '$sourcePath' && echo 'true' || echo 'false'" + ) + val isDirectory = isDirResult.stdout.trim() == "true" + + // 确保目标父目录存在 + val destParentDir = destPath.substringBeforeLast('/') + if (destParentDir.isNotEmpty()) { + AndroidShellExecutor.executeShellCommand("mkdir -p '$destParentDir'") + } + + // 根据是否为目录选择不同的复制命令 + val copyCommand = + if (isDirectory && recursive) { + "cp -r '$sourcePath' '$destPath'" + } else if (!isDirectory) { + "cp '$sourcePath' '$destPath'" + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "copy", + path = sourcePath, + successful = false, + details = + "Cannot copy directory without recursive flag" + ), + error = "Cannot copy directory without recursive flag" + ) + } + + val result = AndroidShellExecutor.executeShellCommand(copyCommand) + + if (result.success) { + // 验证复制是否成功 + val verifyResult = + AndroidShellExecutor.executeShellCommand( + "test -e '$destPath' && echo 'exists' || echo 'not exists'" + ) + if (verifyResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "copy", + path = sourcePath, + successful = false, + details = + "Copy command completed but destination does not exist" + ), + error = "Copy command completed but destination does not exist" + ) + } + + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "copy", + path = sourcePath, + successful = true, + details = + "Successfully copied ${if (isDirectory) "directory" else "file"} $sourcePath to $destPath" + ), + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "copy", + path = sourcePath, + successful = false, + details = "Failed to copy: ${result.stderr}" + ), + error = "Failed to copy: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error copying file/directory", e) + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "copy", + path = sourcePath, + successful = false, + details = "Error copying file/directory: ${e.message}" + ), + error = "Error copying file/directory: ${e.message}" + ) + } + } + + /** Create a directory */ + private suspend fun makeDirectoryWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.makeDirectory(tool) + } + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + if (isSafEnvironment(environment)) { + return super.makeDirectory(tool) + } + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.makeDirectory(tool) + } + val createParents = + tool.parameters.find { it.name == "create_parents" }?.value?.toBoolean() ?: false + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "mkdir", + path = "", + successful = false, + details = "Path parameter is required" + ), + error = "Path parameter is required" + ) + } + + return try { + // 首先检查目录是否已存在 + val checkDirResult = + AndroidShellExecutor.executeShellCommand( + "test -d '$path' && echo 'exists' || echo 'not exists'" + ) + + if (checkDirResult.success && checkDirResult.stdout.trim() == "exists") { + // 目录已存在,返回成功 + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "mkdir", + path = path, + successful = true, + details = "Directory already exists: $path" + ), + error = "" + ) + } + + val mkdirCommand = if (createParents) "mkdir -p '$path'" else "mkdir '$path'" + val result = AndroidShellExecutor.executeShellCommand(mkdirCommand) + + if (result.success) { + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "mkdir", + path = path, + successful = true, + details = "Successfully created directory $path" + ), + error = "" + ) + } else { + // 创建失败后再次检查是否已存在(可能在执行过程中被创建) + val recheckDirResult = + AndroidShellExecutor.executeShellCommand( + "test -d '$path' && echo 'exists' || echo 'not exists'" + ) + + if (recheckDirResult.success && recheckDirResult.stdout.trim() == "exists") { + // 目录已存在,返回成功 + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "mkdir", + path = path, + successful = true, + details = "Directory already exists: $path" + ), + error = "" + ) + } + + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "mkdir", + path = path, + successful = false, + details = "Failed to create directory: ${result.stderr}" + ), + error = "Failed to create directory: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error creating directory", e) + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "mkdir", + path = path, + successful = false, + details = "Error creating directory: ${e.message}" + ), + error = "Error creating directory: ${e.message}" + ) + } + } + + /** Search for files matching a pattern */ + private suspend fun findFilesWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.findFiles(tool) + } + + if (isSafEnvironment(environment)) { + return super.findFiles(tool) + } + + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + val pattern = tool.parameters.find { it.name == "pattern" }?.value ?: "" + + if (isOperitInternalPath(path)) { + return super.findFiles(tool) + } + + if (path.isBlank() || pattern.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FindFilesResultData( + path = path, + pattern = pattern, + files = emptyList() + ), + error = "Path and pattern parameters are required" + ) + } + + return try { + ToolProgressBus.update(tool.name, 0.02f, "Searching (device)...") + // Add options for different search modes + val usePathPattern = + tool.parameters.find { it.name == "use_path_pattern" }?.value?.toBoolean() + ?: false + val caseInsensitive = + tool.parameters.find { it.name == "case_insensitive" }?.value?.toBoolean() + ?: false + + val isFileResult = + AndroidShellExecutor.executeShellCommand( + "test -f ${shQuote(path)} && echo file || echo not_file" + ) + if (isFileResult.success && isFileResult.stdout.trim() == "file") { + val fileName = path.substringAfterLast('/') + val testString = if (usePathPattern) path else fileName + val regex = globToRegex(pattern, caseInsensitive) + val files = if (regex.matches(testString)) listOf(path) else emptyList() + + ToolProgressBus.update(tool.name, 1f, "Search completed, found ${files.size}") + + return ToolResult( + toolName = tool.name, + success = true, + result = FindFilesResultData(path = path, pattern = pattern, files = files), + error = "" + ) + } + + // Add depth control parameter (default to -1 for unlimited depth/fully + // recursive) + val maxDepth = + tool.parameters.find { it.name == "max_depth" }?.value?.toIntOrNull() ?: -1 + + // Determine which search option to use + val searchOption = + if (usePathPattern) { + if (caseInsensitive) "-ipath" else "-path" + } else { + if (caseInsensitive) "-iname" else "-name" + } + + // Properly escape the pattern if quotes are required + val escapedPattern = pattern.replace("'", "'\\''") + val patternForCommand = "'$escapedPattern'" + + // Build the command with depth control if specified + val depthOption = if (maxDepth >= 0) "-maxdepth $maxDepth" else "" + val command = + "find '${if(path.endsWith("/")) path else "$path/"}' $depthOption $searchOption $patternForCommand" + + val files = mutableListOf() + val foundCount = AtomicInteger(0) + val progressFloor = AtomicInteger(2) + val stderrBuilder = StringBuilder() + + val process = AndroidShellExecutor.startShellProcess(command) + try { + val exitCode = coroutineScope { + val stdoutJob = launch { + process.stdout.collect { line -> + val v = line.trim() + if (v.isNotEmpty()) { + files.add(v) + val found = foundCount.incrementAndGet() + val p = (smoothProgress(found, 250f) * 100).toInt().coerceIn(0, 99) + updateProgressFloor(progressFloor, p) + if (found % 20 == 0) { + ToolProgressBus.update( + tool.name, + progressFloor.get() / 100f, + "Searching... found $found" + ) + } + } + } + } + val stderrJob = launch { + process.stderr.collect { line -> + if (line.isNotBlank()) { + stderrBuilder.appendLine(line) + } + } + } + val tickerJob = launch { + while (isActive && process.isAlive) { + delay(500) + val current = progressFloor.get() + if (current < 95) { + progressFloor.compareAndSet(current, current + 1) + ToolProgressBus.update( + tool.name, + progressFloor.get() / 100f, + "Searching... found ${foundCount.get()}" + ) + } + } + } + + val code = process.waitFor() + stdoutJob.cancelAndJoin() + stderrJob.cancelAndJoin() + tickerJob.cancelAndJoin() + code + } + + if (exitCode != 0) { + val err = stderrBuilder.toString().trim() + return ToolResult( + toolName = tool.name, + success = false, + result = FindFilesResultData(path = path, pattern = pattern, files = emptyList()), + error = if (err.isNotBlank()) err else "find command failed with exitCode=$exitCode" + ) + } + } finally { + if (process.isAlive) { + process.destroy() + } + } + + ToolProgressBus.update(tool.name, 1f, "Search completed, found ${files.size}") + + return ToolResult( + toolName = tool.name, + success = true, + result = FindFilesResultData(path = path, pattern = pattern, files = files), + error = "" + ) + } catch (e: Exception) { + AppLogger.e(TAG, "Error searching for files", e) + ToolProgressBus.update(tool.name, 1f, "Search failed") + return ToolResult( + toolName = tool.name, + success = false, + result = + FindFilesResultData( + path = path, + pattern = pattern, + files = emptyList() + ), + error = "Error searching for files: ${e.message}" + ) + } + } + + /** Get file information */ + private suspend fun fileInfoWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.fileInfo(tool) + } + + if (isSafEnvironment(environment)) { + return super.fileInfo(tool) + } + + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + // 如果是Operit内部存储路径,使用super的高权限方法 + if (isOperitInternalPath(path)) { + return super.fileInfo(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileInfoData( + path = "", + exists = false, + fileType = "", + size = 0, + permissions = "", + owner = "", + group = "", + lastModified = "", + rawStatOutput = "" + ), + error = "Path parameter is required" + ) + } + + return try { + // Check if file exists + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -e '$path' && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileInfoData( + path = path, + exists = false, + fileType = "", + size = 0, + permissions = "", + owner = "", + group = "", + lastModified = "", + rawStatOutput = "" + ), + error = "File or directory does not exist: $path" + ) + } + + // Get file details using stat + val statResult = AndroidShellExecutor.executeShellCommand("stat '$path'") + + if (statResult.success) { + // Get file type + val fileTypeResult = + AndroidShellExecutor.executeShellCommand( + "test -d '$path' && echo 'directory' || (test -f '$path' && echo 'file' || echo 'other')" + ) + val fileType = fileTypeResult.stdout.trim() + + // Get file size + val sizeResult = + AndroidShellExecutor.executeShellCommand( + "stat -c %s '$path' 2>/dev/null || echo '0'" + ) + val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 + + // Get file permissions + val permissionsResult = + AndroidShellExecutor.executeShellCommand( + "stat -c %A '$path' 2>/dev/null || echo ''" + ) + val permissions = permissionsResult.stdout.trim() + + // Get owner and group + val ownerResult = + AndroidShellExecutor.executeShellCommand( + "stat -c %U '$path' 2>/dev/null || echo ''" + ) + val owner = ownerResult.stdout.trim() + + val groupResult = + AndroidShellExecutor.executeShellCommand( + "stat -c %G '$path' 2>/dev/null || echo ''" + ) + val group = groupResult.stdout.trim() + + // Get last modified time + val modifiedResult = + AndroidShellExecutor.executeShellCommand( + "stat -c %Y '$path' 2>/dev/null || echo ''" + ) + val lastModifiedEpochSec = modifiedResult.stdout.trim().toLongOrNull() + val lastModified = + if (lastModifiedEpochSec != null && lastModifiedEpochSec > 0) { + SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US) + .format(Date(lastModifiedEpochSec * 1000L)) + } else { + "" + } + + return ToolResult( + toolName = tool.name, + success = true, + result = + FileInfoData( + path = path, + exists = true, + fileType = fileType, + size = size, + permissions = permissions, + owner = owner, + group = group, + lastModified = lastModified, + rawStatOutput = statResult.stdout + ), + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileInfoData( + path = path, + exists = true, + fileType = "", + size = 0, + permissions = "", + owner = "", + group = "", + lastModified = "", + rawStatOutput = "" + ), + error = "Failed to get file information: ${statResult.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error getting file information", e) + return ToolResult( + toolName = tool.name, + success = false, + result = + FileInfoData( + path = path, + exists = false, + fileType = "", + size = 0, + permissions = "", + owner = "", + group = "", + lastModified = "", + rawStatOutput = "" + ), + error = "Error getting file information: ${e.message}" + ) + } + } + + /** Zip files or directories */ + private suspend fun zipFilesWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.zipFiles(tool) + } + val sourcePath = tool.parameters.find { it.name == "source" }?.value ?: "" + val zipPath = tool.parameters.find { it.name == "destination" }?.value ?: "" + val includeRootDirectoryParameter = tool.parameters.find { it.name == "include_root_directory" } + val includeRootDirectory = + if (includeRootDirectoryParameter == null) { + true + } else { + includeRootDirectoryParameter.value.toBooleanStrictOrNull() + ?: return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "include_root_directory must be true or false" + ) + } + PathValidator.validateAndroidPath(sourcePath, tool.name, "source")?.let { return it } + PathValidator.validateAndroidPath(zipPath, tool.name, "destination")?.let { return it } + + if (isOperitInternalPath(sourcePath) || isOperitInternalPath(zipPath)) { + return super.zipFiles(tool) + } + + if (sourcePath.isBlank() || zipPath.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Source and destination parameters are required" + ) + } + + return try { + val archiveSourcePath = + sourcePath.trimEnd('/').let { + if (it.isEmpty() && sourcePath.startsWith("/")) "/" else it + } + // First, check if the source path exists + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -e ${shQuote(archiveSourcePath)} && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Source file or directory does not exist: $sourcePath" + ) + } + + // Check if source is a directory + val isDirResult = + AndroidShellExecutor.executeShellCommand( + "test -d ${shQuote(archiveSourcePath)} && echo 'true' || echo 'false'" + ) + val isDirectory = isDirResult.stdout.trim() == "true" + + // Create parent directory for zip file if needed + val zipDir = File(zipPath).parent + if (zipDir != null) { + AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(zipDir)}") + } + + // Use Java's ZipOutputStream to create the zip file + // We'll use ADB to copy files to/from the device and process locally + val sourceFile = File(archiveSourcePath) + + // Initialize buffer for file copy + val buffer = ByteArray(1024) + + // Create temporary file for processing - using external files directory for + // better + // permissions + val tempDir = context.getExternalFilesDir(null) ?: context.cacheDir + val tempSourceFile = File(tempDir, "temp_source_${System.currentTimeMillis()}") + val tempZipFile = File(tempDir, "temp_zip_${System.currentTimeMillis()}.zip") + + try { + // Make sure the temp directory exists + tempDir.mkdirs() + + if (isDirectory) { + // For directories, we need to list all files and add them + // to the zip + val listResult = + AndroidShellExecutor.executeShellCommand("find ${shQuote(archiveSourcePath)} -type f") + val fileList = listResult.stdout.trim().split("\n").filter { it.isNotEmpty() } + + // Create ZIP output stream + val fos = FileOutputStream(tempZipFile) + val zos = ZipOutputStream(BufferedOutputStream(fos)) + + try { + for (filePath in fileList) { + // Get the file path relative to the source + // directory + val pathInsideSource = + if (archiveSourcePath == "/") { + filePath.removePrefix("/") + } else { + filePath.removePrefix("$archiveSourcePath/") + } + val relativePath = + if (includeRootDirectory && sourceFile.name.isNotEmpty()) { + "${sourceFile.name}/$pathInsideSource" + } else { + pathInsideSource + } + + // Copy the file from device to temp file + val pullResult = + AndroidShellExecutor.executeShellCommand( + "cat ${shQuote(filePath)} > ${shQuote(tempSourceFile.absolutePath)}" + ) + if (!pullResult.success) { + continue // Skip this file if we + // can't pull it + } + + // Add the file to the ZIP + val fis = FileInputStream(tempSourceFile) + val bis = BufferedInputStream(fis) + + try { + // Add ZIP entry + val entry = ZipEntry(relativePath) + zos.putNextEntry(entry) + + // Write file content to ZIP + var len: Int + while (bis.read(buffer).also { len = it } > 0) { + zos.write(buffer, 0, len) + } + + zos.closeEntry() + } finally { + bis.close() + fis.close() + tempSourceFile.delete() + } + } + } finally { + zos.close() + fos.close() + } + } else { + // For a single file, simpler process + // Copy the file from device to temp file + val pullResult = + AndroidShellExecutor.executeShellCommand( + "cat ${shQuote(archiveSourcePath)} > ${shQuote(tempSourceFile.absolutePath)}" + ) + if (!pullResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to read source file: ${pullResult.stderr}" + ) + } + + // Create zip file with single entry + val fos = FileOutputStream(tempZipFile) + val zos = ZipOutputStream(BufferedOutputStream(fos)) + + try { + val fis = FileInputStream(tempSourceFile) + val bis = BufferedInputStream(fis) + + try { + // Add ZIP entry + val entry = ZipEntry(sourceFile.name) + zos.putNextEntry(entry) + + // Write file content to ZIP + var len: Int + while (bis.read(buffer).also { len = it } > 0) { + zos.write(buffer, 0, len) + } + + zos.closeEntry() + } finally { + bis.close() + fis.close() + } + } finally { + zos.close() + fos.close() + } + } + + // Log information about the temp ZIP file + AppLogger.d( + TAG, + "Temp ZIP file created at: ${tempZipFile.absolutePath}, size: ${tempZipFile.length()} bytes" + ) + + // Push the ZIP file to the destination + val pushResult = + AndroidShellExecutor.executeShellCommand( + "cat ${shQuote(tempZipFile.absolutePath)} > ${shQuote(zipPath)}" + ) + if (!pushResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to write ZIP file: ${pushResult.stderr}" + ) + } + + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "zip", + path = sourcePath, + successful = true, + details = "Successfully compressed $sourcePath to $zipPath" + ), + error = "" + ) + } finally { + // Clean up temporary files + tempSourceFile.delete() + tempZipFile.delete() + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error compressing files", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error compressing files: ${e.message}" + ) + } + } + + /** Unzip a zip file */ + private suspend fun unzipFilesWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.unzipFiles(tool) + } + val zipPath = tool.parameters.find { it.name == "source" }?.value ?: "" + val destPath = tool.parameters.find { it.name == "destination" }?.value ?: "" + PathValidator.validateAndroidPath(zipPath, tool.name, "source")?.let { return it } + PathValidator.validateAndroidPath(destPath, tool.name, "destination")?.let { return it } + + if (isOperitInternalPath(zipPath) || isOperitInternalPath(destPath)) { + return super.unzipFiles(tool) + } + + val actualZipPath = zipPath + val actualDestPath = destPath + + if (zipPath.isBlank() || destPath.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Source and destination parameters are required" + ) + } + + return try { + ToolProgressBus.update(tool.name, -1f, "Unzipping...") + // Check if the zip file exists + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -f ${shQuote(zipPath)} && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Zip file does not exist: $zipPath" + ) + } + + // Create destination directory if it doesn't exist + AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(destPath)};") + + val deviceUnzipCommands = + listOf( + "unzip -o ${shQuote(zipPath)} -d ${shQuote(destPath)}", + "toybox unzip -o ${shQuote(zipPath)} -d ${shQuote(destPath)}", + "busybox unzip -o ${shQuote(zipPath)} -d ${shQuote(destPath)}" + ) + + for (cmd in deviceUnzipCommands) { + try { + ToolProgressBus.update(tool.name, 0.02f, "Unzipping (device)...") + val extractedCount = AtomicInteger(0) + val progressFloor = AtomicInteger(2) + val stderrBuilder = StringBuilder() + + val process = AndroidShellExecutor.startShellProcess("$cmd;") + try { + val exitCode = coroutineScope { + val stdoutJob = launch { + process.stdout.collect { line -> + val t = line.trimStart() + val isProgressLine = + t.startsWith("inflating:") || + t.startsWith("extracting:") || + t.startsWith("creating:") || + t.startsWith(" inflating:") || + t.startsWith(" extracting:") + + if (isProgressLine) { + val extracted = extractedCount.incrementAndGet() + val p = (smoothProgress(extracted, 120f) * 100).toInt().coerceIn(0, 99) + updateProgressFloor(progressFloor, p) + if (extracted % 10 == 0) { + ToolProgressBus.update( + tool.name, + progressFloor.get() / 100f, + "Unzipping... extracted $extracted" + ) + } + } + } + } + val stderrJob = launch { + process.stderr.collect { line -> + if (line.isNotBlank()) { + stderrBuilder.appendLine(line) + } + + val t = line.trimStart() + val isProgressLine = + t.startsWith("inflating:") || + t.startsWith("extracting:") || + t.startsWith("creating:") || + t.startsWith(" inflating:") || + t.startsWith(" extracting:") + + if (isProgressLine) { + val extracted = extractedCount.incrementAndGet() + val p = (smoothProgress(extracted, 120f) * 100).toInt().coerceIn(0, 99) + updateProgressFloor(progressFloor, p) + if (extracted % 10 == 0) { + ToolProgressBus.update( + tool.name, + progressFloor.get() / 100f, + "Unzipping... extracted $extracted" + ) + } + } + } + } + val tickerJob = launch { + while (isActive && process.isAlive) { + delay(500) + val current = progressFloor.get() + if (current < 95) { + progressFloor.compareAndSet(current, current + 1) + ToolProgressBus.update( + tool.name, + progressFloor.get() / 100f, + "Unzipping..." + ) + } + } + } + + val code = process.waitFor() + stdoutJob.cancelAndJoin() + stderrJob.cancelAndJoin() + tickerJob.cancelAndJoin() + code + } + + if (exitCode == 0) { + ToolProgressBus.update(tool.name, 1f, "Unzip completed") + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "unzip", + path = zipPath, + successful = true, + details = "Successfully extracted $zipPath to $destPath" + ), + error = "" + ) + } + } finally { + if (process.isAlive) { + process.destroy() + } + } + } catch (e: Exception) { + AppLogger.w(TAG, "Device-side unzip failed for cmd: $cmd", e) + } + } + + // Create temporary files for processing - using external files directory + // for better + // permissions + val tempDir = context.getExternalFilesDir(null) ?: context.cacheDir + val tempZipFile = File(tempDir, "temp_zip_${System.currentTimeMillis()}.zip") + + try { + // Make sure the temp directory exists + tempDir.mkdirs() + + // Copy the zip file from device to temp file + val pullResult = + AndroidShellExecutor.executeShellCommand( + "cat ${shQuote(zipPath)} > ${shQuote(tempZipFile.absolutePath)}" + ) + if (!pullResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to read zip file: ${pullResult.stderr}" + ) + } + + // Log information about the temp ZIP file + AppLogger.d( + TAG, + "Temp ZIP file loaded at: ${tempZipFile.absolutePath}, size: ${tempZipFile.length()} bytes" + ) + + val totalEntries = try { + ZipFile(tempZipFile).use { it.size() } + } catch (_: Exception) { + null + } + var processedEntries = 0 + + // Extract files using ZipInputStream + val buffer = ByteArray(64 * 1024) + val zipInputStream = + ZipInputStream(BufferedInputStream(FileInputStream(tempZipFile))) + + try { + var zipEntry: ZipEntry? = zipInputStream.nextEntry + while (zipEntry != null) { + val fileName = zipEntry.name + if (fileName.startsWith("/") || fileName.contains("..") || fileName.contains("\\")) { + zipInputStream.closeEntry() + zipEntry = zipInputStream.nextEntry + continue + } + + val newFile = File(tempDir, fileName) + + val newFileCanonical = newFile.canonicalPath + val tempDirCanonical = tempDir.canonicalPath + File.separator + if (!newFileCanonical.startsWith(tempDirCanonical)) { + zipInputStream.closeEntry() + zipEntry = zipInputStream.nextEntry + continue + } + + // Skip directories, but make sure they exist + if (zipEntry.isDirectory) { + newFile.mkdirs() + val dirPath = "$destPath/$fileName" + AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(dirPath)};") + zipInputStream.closeEntry() + zipEntry = zipInputStream.nextEntry + continue + } + + // Create parent directories if needed + val filePath = "$destPath/$fileName" + val parentDirPath = File(filePath).parent + if (parentDirPath != null) { + AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(parentDirPath)};") + } + + newFile.parentFile?.mkdirs() + + // Extract file + val fileOutputStream = FileOutputStream(newFile) + + try { + var len: Int + while (zipInputStream.read(buffer).also { len = it } > 0) { + fileOutputStream.write(buffer, 0, len) + } + } finally { + fileOutputStream.close() + } + + // Copy the extracted file to device + val pushResult = + AndroidShellExecutor.executeShellCommand( + "cat ${shQuote(newFile.absolutePath)} > ${shQuote(filePath)}" + ) + if (!pushResult.success) { + AppLogger.w(TAG, "Failed to copy extracted file: $fileName to $filePath") + // Continue with next file + } + + // Clean up temp file + newFile.delete() + + zipInputStream.closeEntry() + processedEntries++ + val progress = + if (totalEntries != null && totalEntries > 0) { + (processedEntries.toFloat() / totalEntries.toFloat()).coerceIn(0f, 1f) + } else { + -1f + } + val msg = + if (totalEntries != null && totalEntries > 0) { + "Unzipping... ($processedEntries/$totalEntries)" + } else { + "Unzipping..." + } + ToolProgressBus.update(tool.name, progress, msg) + zipEntry = zipInputStream.nextEntry + } + } finally { + zipInputStream.close() + } + + ToolProgressBus.update(tool.name, 1f, "Unzip completed") + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "unzip", + path = zipPath, + successful = true, + details = "Successfully extracted $zipPath to $destPath" + ), + error = "" + ) + } finally { + tempZipFile.delete() + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error extracting zip file", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error extracting zip file: ${e.message}" + ) + } finally { + ToolProgressBus.clear() + } + } + + /** 打开文件 使用系统默认应用打开文件 */ + private suspend fun openFileWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.openFile(tool) + } + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + + if (isOperitInternalPath(path)) { + return super.openFile(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "open", + path = "", + successful = false, + details = "Must provide path parameter" + ), + error = "Must provide path parameter" + ) + } + + return try { + // 首先检查文件是否存在 + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -f '$path' && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "open", + path = path, + successful = false, + details = "File does not exist: $path" + ), + error = "File does not exist: $path" + ) + } + + // 获取文件MIME类型 + val mimeTypeResult = + AndroidShellExecutor.executeShellCommand("file --mime-type -b '$path'") + val mimeType = + if (mimeTypeResult.success) mimeTypeResult.stdout.trim() + else "application/octet-stream" + + // 使用Android intent打开文件 + val command = "am start -a android.intent.action.VIEW -d 'file://$path' -t '$mimeType'" + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success) { + return ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "open", + path = path, + successful = true, + details = "Opened file with system app: $path" + ), + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "open", + path = path, + successful = false, + details = "Failed to open file: ${result.stderr}" + ), + error = "Failed to open file: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error opening file", e) + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "open", + path = path, + successful = false, + details = "Error opening file: ${e.message}" + ), + error = "Error opening file: ${e.message}" + ) + } + } + + /** 分享文件 调用系统分享功能 */ + private suspend fun shareFileWithShell(tool: AITool): ToolResult { + val environment = tool.parameters.find { it.name == "environment" }?.value + if (environment == "linux") { + return super.shareFile(tool) + } + val path = tool.parameters.find { it.name == "path" }?.value ?: "" + PathValidator.validateAndroidPath(path, tool.name)?.let { return it } + val title = tool.parameters.find { it.name == "title" }?.value ?: "Share File" + + if (isOperitInternalPath(path)) { + return super.shareFile(tool) + } + + if (path.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "share", + path = "", + successful = false, + details = "Must provide path parameter" + ), + error = "Must provide path parameter" + ) + } + + return try { + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -f ${shQuote(path)} && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "share", + path = path, + successful = false, + details = "File does not exist: $path" + ), + error = "File does not exist: $path" + ) + } + + val stagingRoot = (context.getExternalFilesDir(null) ?: context.cacheDir) + val stagingDir = File(stagingRoot, "share_tmp") + if (!stagingDir.exists()) { + stagingDir.mkdirs() + } + + val sourceName = File(path).name.ifBlank { "shared_file" } + val stagedFile = File(stagingDir, "${System.currentTimeMillis()}_$sourceName") + val copyResult = + AndroidShellExecutor.executeShellCommand( + "cat ${shQuote(path)} > ${shQuote(stagedFile.absolutePath)}" + ) + + if (!copyResult.success || !stagedFile.exists()) { + return ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "share", + path = path, + successful = false, + details = "Failed to prepare file for sharing: ${copyResult.stderr}" + ), + error = "Failed to prepare file for sharing: ${copyResult.stderr}" + ) + } + + val extension = stagedFile.extension.lowercase(Locale.US) + val mimeType = + if (extension.isNotEmpty()) { + MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) + ?: "application/octet-stream" + } else { + "application/octet-stream" + } + + val authority = "${context.packageName}.fileprovider" + val contentUri = FileProvider.getUriForFile(context, authority, stagedFile) + val shareIntent = + Intent(Intent.ACTION_SEND).apply { + type = mimeType + putExtra(Intent.EXTRA_STREAM, contentUri) + putExtra(Intent.EXTRA_SUBJECT, title) + clipData = + ClipData.newUri( + context.contentResolver, + stagedFile.name, + contentUri + ) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + } + val chooserIntent = + Intent.createChooser(shareIntent, title).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } + context.startActivity(chooserIntent) + + ToolResult( + toolName = tool.name, + success = true, + result = + FileOperationData( + operation = "share", + path = path, + successful = true, + details = "Opened share interface, sharing file: $path" + ), + error = "" + ) + } catch (e: ActivityNotFoundException) { + AppLogger.e(TAG, "No activity found to handle sharing file: $path", e) + ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "share", + path = path, + successful = false, + details = "No application found to share this file type." + ), + error = "No application found to share this file type." + ) + } catch (e: Exception) { + AppLogger.e(TAG, "Error sharing file", e) + ToolResult( + toolName = tool.name, + success = false, + result = + FileOperationData( + operation = "share", + path = path, + successful = false, + details = "Error sharing file: ${e.message}" + ), + error = "Error sharing file: ${e.message}" + ) + } + } + + /** 下载文件 从网络URL下载文件到指定路径 */ + private suspend fun downloadFileWithShell(tool: AITool): ToolResult { + return super.downloadFile(tool) + } + + /** Write base64 encoded content to a binary file */ + +// if (path.isBlank()) { +// return ToolResult( +// toolName = tool.name, +// success = false, +// result = +// FileOperationData( +// operation = "write_binary", +// path = "", +// successful = false, +// details = "Path parameter is required" +// ), +// error = "Path parameter is required" +// ) +// } + +// return try { +// // Ensure parent directory exists +// val directory = File(path).parent +// if (directory != null) { +// AndroidShellExecutor.executeShellCommand("mkdir -p '$directory'") +// } + +// // Write content using echo and base64 decode +// val writeResult = +// AndroidShellExecutor.executeShellCommand( +// "echo '$base64Content' | base64 -d > '$path'" +// ) + +// if (!writeResult.success) { +// return ToolResult( +// toolName = tool.name, +// success = false, +// result = +// FileOperationData( +// operation = "write_binary", +// path = path, +// successful = false, +// details = "Failed to write binary file: ${writeResult.stderr}" +// ), +// error = "Failed to write binary file: ${writeResult.stderr}" +// ) +// } + +// // Verify write was successful +// val sizeResult = +// AndroidShellExecutor.executeShellCommand("stat -c %s '$path' 2>/dev/null || echo '0'") +// val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 +// val originalSize = +// android.util.Base64.decode(base64Content, android.util.Base64.NO_WRAP).size + +// if (size.toLong() != originalSize.toLong()) { +// return ToolResult( +// toolName = tool.name, +// success = false, +// result = +// FileOperationData( +// operation = "write_binary", +// path = path, +// successful = false, +// details = "Write completed but file size mismatch. Expected: $originalSize, Got: $size. Possible write failure." +// ), +// error = "Write completed but file size mismatch. Expected: $originalSize, Got: $size. Possible write failure." +// ) +// } + +// return ToolResult( +// toolName = tool.name, +// success = true, +// result = +// FileOperationData( +// operation = "write_binary", +// path = path, +// successful = true, +// details = "Binary content written to $path" +// ), +// error = "" +// ) +// } catch (e: Exception) { +// AppLogger.e(TAG, "Error writing binary file", e) +// return ToolResult( +// toolName = tool.name, +// success = false, +// result = +// FileOperationData( +// operation = "write_binary", +// path = path, +// successful = false, +// details = "Error writing binary file: ${e.message}" +// ), +// error = "Error writing binary file: ${e.message}" +// ) +// } +// } + + // 路由与具体操作放在同一工具中,避免通过历史权限等级继承改变分派。 -/** 管理员文件工具在每次操作前选择可用后端,复用现有标准和 Shell 实现。 */ -open class AdminFileSystemTools(context: Context) : DebuggerFileSystemTools(context) { private val standardTools = StandardFileSystemTools(context) private suspend fun route( @@ -25,53 +2947,53 @@ open class AdminFileSystemTools(context: Context) : DebuggerFileSystemTools(cont ) override suspend fun listFiles(tool: AITool): ToolResult = - route(true, { super.listFiles(tool) }, { standardTools.listFiles(tool) }) + route(true, { listFilesWithShell(tool) }, { standardTools.listFiles(tool) }) override suspend fun readFileFull(tool: AITool): ToolResult = - route(true, { super.readFileFull(tool) }, { standardTools.readFileFull(tool) }) + route(true, { readFileFullWithShell(tool) }, { standardTools.readFileFull(tool) }) override suspend fun readFile(tool: AITool): ToolResult = - route(true, { super.readFile(tool) }, { standardTools.readFile(tool) }) + route(true, { readFileWithShell(tool) }, { standardTools.readFile(tool) }) override suspend fun readFilePart(tool: AITool): ToolResult = - route(true, { super.readFilePart(tool) }, { standardTools.readFilePart(tool) }) + route(true, { readFilePartWithShell(tool) }, { standardTools.readFilePart(tool) }) override suspend fun fileExists(tool: AITool): ToolResult = - route(true, { super.fileExists(tool) }, { standardTools.fileExists(tool) }) + route(true, { fileExistsWithShell(tool) }, { standardTools.fileExists(tool) }) override suspend fun findFiles(tool: AITool): ToolResult = - route(true, { super.findFiles(tool) }, { standardTools.findFiles(tool) }) + route(true, { findFilesWithShell(tool) }, { standardTools.findFiles(tool) }) override suspend fun fileInfo(tool: AITool): ToolResult = - route(true, { super.fileInfo(tool) }, { standardTools.fileInfo(tool) }) + route(true, { fileInfoWithShell(tool) }, { standardTools.fileInfo(tool) }) override suspend fun writeFile(tool: AITool): ToolResult = - route(false, { super.writeFile(tool) }, { standardTools.writeFile(tool) }) + route(false, { writeFileWithShell(tool) }, { standardTools.writeFile(tool) }) override suspend fun deleteFile(tool: AITool): ToolResult = - route(false, { super.deleteFile(tool) }, { standardTools.deleteFile(tool) }) + route(false, { deleteFileWithShell(tool) }, { standardTools.deleteFile(tool) }) override suspend fun moveFile(tool: AITool): ToolResult = - route(false, { super.moveFile(tool) }, { standardTools.moveFile(tool) }) + route(false, { moveFileWithShell(tool) }, { standardTools.moveFile(tool) }) override suspend fun copyFile(tool: AITool): ToolResult = - route(false, { super.copyFile(tool) }, { standardTools.copyFile(tool) }) + route(false, { copyFileWithShell(tool) }, { standardTools.copyFile(tool) }) override suspend fun makeDirectory(tool: AITool): ToolResult = - route(false, { super.makeDirectory(tool) }, { standardTools.makeDirectory(tool) }) + route(false, { makeDirectoryWithShell(tool) }, { standardTools.makeDirectory(tool) }) override suspend fun zipFiles(tool: AITool): ToolResult = - route(false, { super.zipFiles(tool) }, { standardTools.zipFiles(tool) }) + route(false, { zipFilesWithShell(tool) }, { standardTools.zipFiles(tool) }) override suspend fun unzipFiles(tool: AITool): ToolResult = - route(false, { super.unzipFiles(tool) }, { standardTools.unzipFiles(tool) }) + route(false, { unzipFilesWithShell(tool) }, { standardTools.unzipFiles(tool) }) override suspend fun openFile(tool: AITool): ToolResult = - route(false, { super.openFile(tool) }, { standardTools.openFile(tool) }) + route(false, { openFileWithShell(tool) }, { standardTools.openFile(tool) }) override suspend fun shareFile(tool: AITool): ToolResult = - route(false, { super.shareFile(tool) }, { standardTools.shareFile(tool) }) + route(false, { shareFileWithShell(tool) }, { standardTools.shareFile(tool) }) override suspend fun downloadFile(tool: AITool): ToolResult = - route(false, { super.downloadFile(tool) }, { standardTools.downloadFile(tool) }) + route(false, { downloadFileWithShell(tool) }, { standardTools.downloadFile(tool) }) } diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt index c17312da43..101d5a2fe1 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt @@ -1,9 +1,526 @@ package com.ai.assistance.operit.core.tools.defaultTool.admin import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.debugger.DebuggerSystemOperationTools +import com.ai.assistance.operit.core.tools.AppOperationData +import com.ai.assistance.operit.core.tools.NotificationData +import com.ai.assistance.operit.core.tools.StringResultData +import com.ai.assistance.operit.core.tools.SystemSettingData +import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardSystemOperationTools +import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver +import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor +import com.ai.assistance.operit.data.model.AITool +import com.ai.assistance.operit.data.model.ToolResult +import com.ai.assistance.operit.util.logging.AppLogger -/** 管理员级别的系统操作工具,继承调试版本 */ -open class AdminSystemOperationTools(context: Context) : DebuggerSystemOperationTools(context) { - // 当前阶段不添加新功能,仅继承调试实现 +/** 管理员系统工具按现有授权能力执行 Shell 或标准系统操作。 */ +open class AdminSystemOperationTools(private val context: Context) : StandardSystemOperationTools(context) { + + private val TAG = "DebuggerSystemTools" + + override suspend fun modifySystemSetting(tool: AITool): ToolResult { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return super.modifySystemSetting(tool) + } + + val setting = tool.parameters.find { it.name == "setting" }?.value ?: "" + val value = tool.parameters.find { it.name == "value" }?.value ?: "" + val namespace = tool.parameters.find { it.name == "namespace" }?.value ?: "system" + + if (setting.isBlank() || value.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Must provide setting and value parameters" + ) + } + + val validNamespaces = listOf("system", "secure", "global") + if (!validNamespaces.contains(namespace)) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Namespace must be one of: ${validNamespaces.joinToString(", ")}" + ) + } + + return try { + val command = "settings put $namespace $setting $value" + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success) { + val resultData = + SystemSettingData(namespace = namespace, setting = setting, value = value) + + return ToolResult( + toolName = tool.name, + success = true, + result = resultData, + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to set setting: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error modifying system setting", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error modifying system setting: ${e.message}" + ) + } + } + + override suspend fun getSystemSetting(tool: AITool): ToolResult { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return super.getSystemSetting(tool) + } + + val setting = tool.parameters.find { it.name == "setting" }?.value ?: "" + val namespace = tool.parameters.find { it.name == "namespace" }?.value ?: "system" + + if (setting.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Must provide setting parameter" + ) + } + + val validNamespaces = listOf("system", "secure", "global") + if (!validNamespaces.contains(namespace)) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Namespace must be one of: ${validNamespaces.joinToString(", ")}" + ) + } + + return try { + val command = "settings get $namespace $setting" + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success) { + val resultData = + SystemSettingData( + namespace = namespace, + setting = setting, + value = result.stdout.trim() + ) + + return ToolResult( + toolName = tool.name, + success = true, + result = resultData, + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to get setting: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error getting system setting", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error getting system setting: ${e.message}" + ) + } + } + + override suspend fun installApp(tool: AITool): ToolResult { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return super.installApp(tool) + } + + val apkPath = tool.parameters.find { it.name == "path" }?.value ?: "" + + if (apkPath.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Must provide apk_path parameter" + ) + } + + if (AdminFileSystemTools.isOperitInternalPath(apkPath)) { + AppLogger.d( + TAG, + "installApp detected Operit internal path, using standard application access" + ) + return super.installApp(tool) + } + + val existsResult = + AndroidShellExecutor.executeShellCommand( + "test -f $apkPath && echo 'exists' || echo 'not exists'" + ) + if (existsResult.stdout.trim() != "exists") { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "APK file does not exist: $apkPath" + ) + } + + return try { + val command = "pm install -r $apkPath" + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success && result.stdout.contains("Success")) { + val resultData = + AppOperationData( + operationType = "install", + packageName = apkPath, + success = true + ) + + return ToolResult( + toolName = tool.name, + success = true, + result = resultData, + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Installation failed: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error installing app", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error installing app: ${e.message}" + ) + } + } + + override suspend fun uninstallApp(tool: AITool): ToolResult { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return super.uninstallApp(tool) + } + + val packageName = tool.parameters.find { it.name == "package_name" }?.value ?: "" + val keepData = tool.parameters.find { it.name == "keep_data" }?.value?.toBoolean() ?: false + + if (packageName.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Must provide package_name parameter" + ) + } + + val checkCommand = "pm list packages | grep -c \"$packageName\"" + val checkResult = AndroidShellExecutor.executeShellCommand(checkCommand) + + if (checkResult.stdout.trim() == "0") { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "App not installed: $packageName" + ) + } + + return try { + val command = + if (keepData) { + "pm uninstall -k $packageName" + } else { + "pm uninstall $packageName" + } + + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success && result.stdout.contains("Success")) { + val details = if (keepData) "(keep data)" else "" + val resultData = + AppOperationData( + operationType = "uninstall", + packageName = packageName, + success = true, + details = details + ) + + return ToolResult( + toolName = tool.name, + success = true, + result = resultData, + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Uninstallation failed: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error uninstalling app", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error uninstalling app: ${e.message}" + ) + } + } + + override suspend fun startApp(tool: AITool): ToolResult { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return super.startApp(tool) + } + + val packageName = tool.parameters.find { it.name == "package_name" }?.value ?: "" + val activity = tool.parameters.find { it.name == "activity" }?.value ?: "" + + if (packageName.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Must provide package_name parameter" + ) + } + + return try { + val command: String + if (activity.isBlank()) { + // 使用 am start 命令而不是 monkey,避免修改系统设置(如屏幕旋转) + // 先获取应用的主 Activity,然后使用 -n 参数启动 + val resolveCmd = "cmd package resolve-activity --brief $packageName 2>/dev/null | tail -n 1" + val resolveResult = AndroidShellExecutor.executeShellCommand(resolveCmd) + + if (resolveResult.success && resolveResult.stdout.isNotBlank()) { + val output = resolveResult.stdout.trim() + // resolve-activity 返回格式可能是:package/activity 或只有 activity + // 也可能返回多行,最后一行是组件名 + val lines = output.lines().filter { it.isNotBlank() && !it.startsWith("name=") } + val mainActivity = lines.lastOrNull()?.trim() ?: output.trim() + + // 如果返回的是完整组件名(package/activity),直接使用 + command = if (mainActivity.contains('/')) { + "am start -n $mainActivity" + } else { + // 如果只返回了 Activity 名,拼接包名 + "am start -n $packageName/$mainActivity" + } + AppLogger.d(TAG, "Resolved main Activity: $mainActivity, using command: $command") + } else { + // 如果无法解析 Activity,返回错误 + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Cannot resolve app main Activity. Please provide activity parameter or ensure app is properly installed. Package: $packageName" + ) + } + } else { + command = "am start -n $packageName/$activity" + } + + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success) { + val details = if (activity.isNotBlank()) "Activity: $activity" else "" + val resultData = + AppOperationData( + operationType = "start", + packageName = packageName, + success = true, + details = details + ) + + return ToolResult( + toolName = tool.name, + success = true, + result = resultData, + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to start app: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error starting app", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error starting app: ${e.message}" + ) + } + } + + override suspend fun stopApp(tool: AITool): ToolResult { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return super.stopApp(tool) + } + + val packageName = tool.parameters.find { it.name == "package_name" }?.value ?: "" + + if (packageName.isBlank()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Must provide package_name parameter" + ) + } + + return try { + val command = "am force-stop $packageName" + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success) { + val resultData = + AppOperationData( + operationType = "stop", + packageName = packageName, + success = true + ) + + return ToolResult( + toolName = tool.name, + success = true, + result = resultData, + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to stop app: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error stopping app", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error stopping app: ${e.message}" + ) + } + } + + override suspend fun getNotifications(tool: AITool): ToolResult { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return super.getNotifications(tool) + } + + val limit = tool.parameters.find { it.name == "limit" }?.value?.toIntOrNull() ?: 10 + val includeOngoing = + tool.parameters.find { it.name == "include_ongoing" }?.value?.toBoolean() ?: false + + return try { + val command = + if (includeOngoing) { + "dumpsys notification --noredact | grep -E 'pkg=|text=' | head -${limit * 2}" + } else { + "dumpsys notification --noredact | grep -v 'ongoing' | grep -E 'pkg=|text=' | head -${limit * 2}" + } + + val result = AndroidShellExecutor.executeShellCommand(command) + + if (result.success) { + val lines = result.stdout.split("\n") + val notifications = mutableListOf() + + var currentPackage = "" + var currentText = "" + + for (line in lines) { + when { + line.contains("pkg=") -> { + if (currentPackage.isNotEmpty() && currentText.isNotEmpty()) { + notifications.add( + NotificationData.Notification( + packageName = currentPackage, + text = currentText, + timestamp = System.currentTimeMillis() + ) + ) + currentText = "" + } + + val pkgMatch = Regex("pkg=(\\S+)").find(line) + currentPackage = pkgMatch?.groupValues?.getOrNull(1) ?: "" + } + line.contains("text=") -> { + val textMatch = Regex("text=(.+)").find(line) + currentText = textMatch?.groupValues?.getOrNull(1) ?: "" + } + } + } + + if (currentPackage.isNotEmpty() && currentText.isNotEmpty()) { + notifications.add( + NotificationData.Notification( + packageName = currentPackage, + text = currentText, + timestamp = System.currentTimeMillis() + ) + ) + } + + val resultData = + NotificationData( + notifications = notifications, + timestamp = System.currentTimeMillis() + ) + + return ToolResult( + toolName = tool.name, + success = true, + result = resultData, + error = "" + ) + } else { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to get notifications: ${result.stderr}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error getting notifications", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error getting notifications: ${e.message}" + ) + } + } } diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt index 00f73d3118..e51a064513 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt @@ -1,9 +1,2123 @@ package com.ai.assistance.operit.core.tools.defaultTool.admin +import android.annotation.SuppressLint +import android.content.ClipData +import android.content.ClipboardManager import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.debugger.DebuggerUITools +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import com.ai.assistance.operit.core.tools.SimplifiedUINode +import com.ai.assistance.operit.core.tools.StringResultData +import com.ai.assistance.operit.core.tools.UIActionResultData +import com.ai.assistance.operit.core.tools.UIPageResultData +import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardUITools +import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver +import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.system.uiautomator.UiAutomatorDumpGuard +import com.ai.assistance.operit.data.model.AITool +import com.ai.assistance.operit.data.model.ToolResult +import com.ai.assistance.operit.data.repository.UIHierarchyManager +import com.ai.assistance.operit.util.files.OperitPaths +import com.ai.assistance.operit.util.logging.AppLogger +import com.ai.assistance.operit.util.media.ImagePoolManager +import java.io.File +import java.io.StringReader +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.withContext +import org.json.JSONObject +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserFactory -/** 管理员级别的UI工具,继承调试版本 */ -open class AdminUITools(context: Context) : DebuggerUITools(context) { - // 当前阶段不添加新功能,仅继承调试实现 +/** 管理员 UI 工具在一次操作前按实际授权选择无障碍或 Shell,Root 复用公共能力。 */ +open class AdminUITools(context: Context) : StandardUITools(context) { + + companion object { + private const val TAG = "AdminUITools" + private const val MAX_RETRY_COUNT = 3 + private const val RETRY_DELAY_MS = 300L + } + + protected open val uiShellIdentity: ShellIdentity? = null + + protected suspend fun executeUiShellCommand(command: String): AndroidShellExecutor.CommandResult { + // 读取页面和按元素点击共用入口;Root 子类也必须保存并恢复调用前的旋转设置。 + if (command.startsWith("uiautomator dump ")) { + return UiAutomatorDumpGuard.execute(command) { protectedCommand -> + AndroidShellExecutor.executeShellCommand(protectedCommand, uiShellIdentity) + } + } + return AndroidShellExecutor.executeShellCommand(command, uiShellIdentity) + } + + protected suspend fun shouldUseAccessibility(tool: AITool): Boolean = + !hasDisplayParam(tool) && PermissionCapabilityResolver.uiSnapshot(context).canUseAccessibility + + /** 是否包含 display 相关参数(有的话强制走 Shell,不走无障碍) */ + private fun hasDisplayParam(tool: AITool): Boolean { + return tool.parameters.any { param -> + param.name.equals("display", ignoreCase = true) + } + } + + private fun getDisplayArg(tool: AITool): String { + val display = tool.parameters.find { it.name.equals("display", ignoreCase = true) }?.value?.trim() + return if (!display.isNullOrEmpty()) "-d $display " else "" + } + + /** 使用Shell命令实现点击操作 */ + override suspend fun tap(tool: AITool): ToolResult { + if (shouldUseAccessibility(tool)) { + AppLogger.d(TAG, "无障碍服务已启用,使用无障碍点击") + return tapWithAccessibility(tool) + } + + val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() + val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() + + if (x == null || y == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = + "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." + ) + } + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + + // 使用Shell命令执行点击 + try { + AppLogger.d(TAG, "Attempting to tap at coordinates: ($x, $y) via shell command") + val command = "input ${getDisplayArg(tool)}tap $x $y" + val result = executeUiShellCommand(command) + + if (result.success) { + AppLogger.d(TAG, "Tap successful at coordinates: ($x, $y)") + withContext(Dispatchers.Main) { + operationOverlay.showTap(x, y) + operationOverlay.hide() + } + return ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "tap", + actionDescription = + "Successfully tapped at coordinates ($x, $y) via shell command", + coordinates = Pair(x, y) + ), + error = "" + ) + } else { + AppLogger.e(TAG, "Tap failed at coordinates: ($x, $y), error: ${result.stderr}") + withContext(Dispatchers.Main) { + operationOverlay.hide() // 隐藏反馈(在主线程上执行) + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = + "Failed to tap at coordinates ($x, $y): ${result.stderr ?: "Unknown error"}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error tapping at coordinates ($x, $y)", e) + withContext(Dispatchers.Main) { + operationOverlay.hide() // 隐藏反馈(在主线程上执行) + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error tapping at coordinates: ${e.message ?: "Unknown exception"}" + ) + } + } + + override suspend fun longPress(tool: AITool): ToolResult { + if (shouldUseAccessibility(tool)) { + AppLogger.d(TAG, "无障碍服务已启用,使用无障碍长按") + return longPressWithAccessibility(tool) + } + + val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() + val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() + + if (x == null || y == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." + ) + } + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + + try { + AppLogger.d(TAG, "Attempting to long press at coordinates: ($x, $y) via shell command") + // Use swipe to simulate long press + val command = "input ${getDisplayArg(tool)}swipe $x $y $x $y 800" + val result = executeUiShellCommand(command) + + if (result.success) { + AppLogger.d(TAG, "Long press successful at coordinates: ($x, $y)") + withContext(Dispatchers.Main) { + operationOverlay.showTap(x, y) + operationOverlay.hide() + } + return ToolResult( + toolName = tool.name, + success = true, + result = UIActionResultData( + actionType = "long_press", + actionDescription = "Successfully long pressed at ($x, $y) via shell command", + coordinates = Pair(x, y) + ), + error = "" + ) + } else { + AppLogger.e(TAG, "Long press failed at coordinates: ($x, $y), error: ${result.stderr}") + withContext(Dispatchers.Main) { operationOverlay.hide() } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to long press at coordinates ($x, $y): ${result.stderr ?: "Unknown error"}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error long pressing at coordinates ($x, $y)", e) + withContext(Dispatchers.Main) { operationOverlay.hide() } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error long pressing at coordinates: ${e.message ?: "Unknown exception"}" + ) + } + } + + /** 使用Shell命令实现滑动操作 */ + override suspend fun swipe(tool: AITool): ToolResult { + if (shouldUseAccessibility(tool)) { + AppLogger.d(TAG, "无障碍服务已启用,使用无障碍滑动") + return swipeWithAccessibility(tool) + } + + val startX = tool.parameters.find { it.name == "start_x" }?.value?.toIntOrNull() + val startY = tool.parameters.find { it.name == "start_y" }?.value?.toIntOrNull() + val endX = tool.parameters.find { it.name == "end_x" }?.value?.toIntOrNull() + val endY = tool.parameters.find { it.name == "end_y" }?.value?.toIntOrNull() + val duration = tool.parameters.find { it.name == "duration" }?.value?.toIntOrNull() ?: 300 + + if (startX == null || startY == null || endX == null || endY == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = + "Missing or invalid coordinates. 'start_x', 'start_y', 'end_x', and 'end_y' must be valid integers." + ) + } + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + + try { + AppLogger.d( + TAG, + "Attempting to swipe from ($startX, $startY) to ($endX, $endY) with duration $duration ms via shell command" + ) + val command = "input ${getDisplayArg(tool)}swipe $startX $startY $endX $endY $duration" + val result = executeUiShellCommand(command) + + if (result.success) { + AppLogger.d(TAG, "Swipe successful from ($startX, $startY) to ($endX, $endY)") + withContext(Dispatchers.Main) { + operationOverlay.showSwipe(startX, startY, endX, endY) + operationOverlay.hide() + } + return ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "swipe", + actionDescription = + "Successfully performed swipe from ($startX, $startY) to ($endX, $endY) via shell command" + ), + error = "" + ) + } else { + AppLogger.e(TAG, "Swipe failed: ${result.stderr}") + withContext(Dispatchers.Main) { + operationOverlay.hide() // 隐藏反馈(在主线程上执行) + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to perform swipe: ${result.stderr ?: "Unknown error"}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error performing swipe", e) + withContext(Dispatchers.Main) { + operationOverlay.hide() // 隐藏反馈(在主线程上执行) + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error performing swipe: ${e.message ?: "Unknown exception"}" + ) + } + } + + /** 使用Shell命令点击元素 */ + override suspend fun clickElement(tool: AITool): ToolResult { + if (shouldUseAccessibility(tool)) { + AppLogger.d(TAG, "无障碍服务已启用,使用无障碍点击元素") + return clickElementWithAccessibility(tool) + } + + val resourceId = tool.parameters.find { it.name == "resourceId" }?.value + val className = tool.parameters.find { it.name == "className" }?.value + val contentDesc = tool.parameters.find { it.name == "contentDesc" }?.value + // index kept for future use + tool.parameters.find { it.name == "index" }?.value?.toIntOrNull() ?: 0 + val bounds = tool.parameters.find { it.name == "bounds" }?.value + + if (resourceId == null && className == null && bounds == null && contentDesc == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = + "Missing element identifier. Provide at least one of: 'resourceId', 'className', 'contentDesc', or 'bounds'." + ) + } + + // 如果提供了边界坐标,直接点击 + if (bounds != null) { + try { + // 解析边界坐标格式 [left,top][right,bottom] + val boundsPattern = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]".toRegex() + val matchResult = boundsPattern.find(bounds) + + if (matchResult == null || matchResult.groupValues.size < 5) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Invalid bounds format. Should be: [left,top][right,bottom]" + ) + } + + // 提取坐标 + val x1 = matchResult.groupValues[1].toInt() + val y1 = matchResult.groupValues[2].toInt() + val x2 = matchResult.groupValues[3].toInt() + val y2 = matchResult.groupValues[4].toInt() + + // 计算中心点 + val centerX = (x1 + x2) / 2 + val centerY = (y1 + y2) / 2 + + // 利用tap方法点击中心点 + val tapTool = + AITool( + name = "tap", + parameters = + listOf( + com.ai.assistance.operit.data.model.ToolParameter( + "x", + centerX.toString() + ), + com.ai.assistance.operit.data.model.ToolParameter( + "y", + centerY.toString() + ) + ) + ) + + return tap(tapTool) + } catch (e: Exception) { + AppLogger.e(TAG, "Error processing bounds", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error processing bounds: ${e.message}" + ) + } + } + + // 使用uiautomator获取和点击元素 + return clickElementWithUiautomator(tool) + } + + /** 使用Shell命令设置输入文本 */ + override suspend fun setInputText(tool: AITool): ToolResult { + if (shouldUseAccessibility(tool)) { + AppLogger.d(TAG, "无障碍服务已启用,使用无障碍设置文本") + return setInputTextWithAccessibility(tool) + } + + val text = tool.parameters.find { it.name == "text" }?.value ?: "" + + try { + // 获取屏幕中心作为文本输入的位置 + val displayMetrics = context.resources.displayMetrics + val centerX = displayMetrics.widthPixels / 2 + val centerY = displayMetrics.heightPixels / 2 + + // 显示文本输入反馈(在主线程上执行) + withContext(Dispatchers.Main) { operationOverlay.showTextInput(centerX, centerY, text) } + + // 使用KEYCODE_CLEAR清除字段,这比模拟CTRL+A和DEL更直接 + AppLogger.d(TAG, "Clearing text field with KEYCODE_CLEAR") + val clearCommand = "input ${getDisplayArg(tool)}keyevent KEYCODE_CLEAR" + executeUiShellCommand(clearCommand) + + // 短暂延迟 + kotlinx.coroutines.delay(300) + + // 如果文本为空,只需清除字段 + if (text.isEmpty()) { + // 成功后主动隐藏overlay + withContext(Dispatchers.Main) { operationOverlay.hide() } + return ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "textInput", + actionDescription = + "Successfully cleared input field via shell command" + ), + error = "" + ) + } + + // 使用原生复制和ADB粘贴来输入文本,这比'input text'更可靠 + AppLogger.d(TAG, "Setting text to clipboard and pasting via ADB: $text") + withContext(Dispatchers.Main) { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clip = ClipData.newPlainText("operit_input", text) + clipboard.setPrimaryClip(clip) + } + + // 短暂延迟以确保剪贴板操作完成 + kotlinx.coroutines.delay(100) + + // 执行粘贴命令 + val pasteCommand = "input ${getDisplayArg(tool)}keyevent KEYCODE_PASTE" + val pasteResult = executeUiShellCommand(pasteCommand) + + if (pasteResult.success) { + // 成功后主动隐藏overlay + withContext(Dispatchers.Main) { operationOverlay.hide() } + return ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "textInput", + actionDescription = + "Successfully set input text to: $text via clipboard paste" + ), + error = "" + ) + } else { + withContext(Dispatchers.Main) { + operationOverlay.hide() // 隐藏反馈(在主线程上执行) + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to paste text from clipboard: ${pasteResult.stderr ?: "Unknown error"}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error setting input text", e) + withContext(Dispatchers.Main) { + operationOverlay.hide() // 隐藏反馈(在主线程上执行) + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error setting input text: ${e.message ?: "Unknown exception"}" + ) + } + } + + /** 使用Shell命令实现按键操作 */ + override suspend fun pressKey(tool: AITool): ToolResult { + val keyCode = tool.parameters.find { it.name == "key_code" }?.value + + if (keyCode == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Missing 'key_code' parameter." + ) + } + + if (shouldUseAccessibility(tool) && + (accessibilityKeyAction(keyCode) != null || + !PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) + ) { + return pressKeyWithAccessibility(tool) + } + + val command = "input ${getDisplayArg(tool)}keyevent $keyCode" + + return try { + val result = executeUiShellCommand(command) + + if (result.success) { + ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "keyPress", + actionDescription = + "Successfully pressed key: $keyCode via shell command" + ), + error = "" + ) + } else { + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to press key: ${result.stderr ?: "Unknown error"}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error pressing key", e) + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error pressing key: ${e.message ?: "Unknown exception"}" + ) + } + } + + override suspend fun captureScreenshotToFile(tool: AITool): Pair?> { + if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { + return if (hasDisplayParam(tool)) Pair(null, null) else captureScreenshotToFileWithAccessibility(tool) + } + return try { + val screenshotDir = OperitPaths.cleanOnExitDir() + + val shortName = System.currentTimeMillis().toString().takeLast(4) + val file = File(screenshotDir, "$shortName.png") + + // 1) Debugger 模式下优先尝试 Shell 模式 (ADB) 截图 + AppLogger.d(TAG, "captureScreenshotToFile: Attempting shell screencap") + val command = "screencap -p ${file.absolutePath}" + val result = executeUiShellCommand(command) + + if (result.success && file.exists()) { + val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } + BitmapFactory.decodeFile(file.absolutePath, options) + val dimensions = if (options.outWidth > 0 && options.outHeight > 0) { + Pair(options.outWidth, options.outHeight) + } else { + null + } + AppLogger.d(TAG, "captureScreenshotToFile: Shell screencap success") + return Pair(file.absolutePath, dimensions) + } + + // 2) 如果 Shell 失败,作为回退尝试无障碍截图 (调用父类) + AppLogger.w(TAG, "captureScreenshotToFile: Shell screencap failed, falling back to accessibility") + if (hasDisplayParam(tool)) Pair(null, null) else captureScreenshotToFileWithAccessibility(tool) + } catch (e: Exception) { + AppLogger.e(TAG, "captureScreenshotToFile failed in Debugger", e) + Pair(null, null) + } + } + + override suspend fun captureScreenshot(tool: AITool): Pair?> { + return captureScreenshotToFile(tool) + } + + override suspend fun captureScreenshotBitmap(tool: AITool): Pair?> { + val (filePath, dimensions) = captureScreenshot(tool) + if (filePath == null) { + return Pair(null, dimensions) + } + + val bitmap = BitmapFactory.decodeFile(filePath) ?: return Pair(null, dimensions) + val resolvedDimensions = dimensions ?: Pair(bitmap.width, bitmap.height) + return Pair(bitmap, resolvedDimensions) + } + + /** 使用Shell命令获取页面信息 */ + override suspend fun getPageInfo(tool: AITool): ToolResult { + if (shouldUseAccessibility(tool)) { + AppLogger.d(TAG, "无障碍服务已启用,使用无障碍获取页面信息") + val result = getPageInfoWithAccessibility(tool) + if (result.success || !PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) return result + } + + val format = tool.parameters.find { it.name == "format" }?.value ?: "xml" + // detail kept for future use + tool.parameters.find { it.name == "detail" }?.value ?: "summary" + + if (format !in listOf("xml", "json")) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Invalid format specified. Must be 'xml' or 'json'." + ) + } + + return try { + // 获取UI数据 + val uiData = getUIDataFromShell(tool) + if (uiData == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to retrieve UI data." + ) + } + + // 解析当前窗口信息 + val focusInfo = extractFocusInfoFromShell(uiData.windowInfo) + + // 简化布局信息 + val simplifiedLayout = simplifyLayoutFromXml(uiData.uiXml) + + // 创建结构化数据 + val resultData = + UIPageResultData( + packageName = focusInfo.packageName ?: "Unknown", + activityName = focusInfo.activityName ?: "Unknown", + uiElements = simplifiedLayout + ) + + ToolResult(toolName = tool.name, success = true, result = resultData, error = "") + } catch (e: Exception) { + AppLogger.e(TAG, "Error getting page info", e) + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error getting page info: ${e.message}" + ) + } + } + + /** UI数据类,保存XML和窗口信息 */ + private data class UIData(val uiXml: String, val windowInfo: String) + + /** 获取UI数据,使用Shell命令,严格遵守工具参数中的 display(如有) */ + private suspend fun getUIDataFromShell(tool: AITool): UIData? { + return try { + // 使用ADB命令获取UI dump + AppLogger.d(TAG, "使用ADB命令获取UI数据") + + val displayId = tool.parameters + .find { it.name.equals("display", ignoreCase = true) } + ?.value + ?.trim() + ?.takeIf { it.isNotEmpty() } + + // 执行UI dump命令,只有在显式提供 display 参数时才使用 --display-id + val dumpResult = if (displayId != null) { + val cmd = "uiautomator dump --display-id $displayId /sdcard/window_dump.xml" + AppLogger.d(TAG, "UI dump using explicit display-id=$displayId") + executeUiShellCommand(cmd) + } else { + executeUiShellCommand("uiautomator dump /sdcard/window_dump.xml") + } + + if (!dumpResult.success) { + AppLogger.e(TAG, "uiautomator dump失败: ${dumpResult.stderr}") + return null + } + AppLogger.d(TAG, "uiautomator dump成功: ${dumpResult.stdout}") + + // 读取dump文件内容 + val readResult = executeUiShellCommand("cat /sdcard/window_dump.xml") + if (!readResult.success) { + AppLogger.e(TAG, "读取UI dump文件失败: ${readResult.stderr}") + return null + } + + // 获取窗口信息 + var windowInfo = getWindowInfoFromShell() + + // 如果窗口信息为空,尝试延迟后重试一次 + if (windowInfo.isEmpty()) { + AppLogger.w(TAG, "首次获取窗口信息失败,延迟500ms后重试") + kotlinx.coroutines.delay(500) + windowInfo = getWindowInfoFromShell() + } + + UIData(readResult.stdout, windowInfo) + } catch (e: Exception) { + AppLogger.e(TAG, "获取UI数据时出错", e) + null + } + } + + /** 获取窗口信息,使用多种命令尝试 */ + private suspend fun getWindowInfoFromShell(): String { + // 尝试多种命令来获取窗口信息 + val commands = + listOf( + // 标准命令,获取当前焦点和焦点应用 + "dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp'", + // 备用命令,只获取当前焦点 + "dumpsys window | grep -E 'mCurrentFocus'", + // 备用命令,只获取焦点应用 + "dumpsys window | grep -E 'mFocusedApp'", + // 最后的备用命令,尝试获取任何窗口信息 + "dumpsys window | grep -E 'Window #|Focus'", + // 极端情况下,尝试获取前台应用包名 + "dumpsys activity recents | grep 'Recent #0' -A2" + ) + + // 依次尝试每个命令,直到有一个成功 + for (command in commands) { + try { + val result = executeUiShellCommand(command) + if (result.success && result.stdout.isNotEmpty()) { + AppLogger.d(TAG, "成功获取窗口信息: ${result.stdout.take(100)}") + return result.stdout + } + // 如果命令执行失败或返回空结果,尝试下一个命令 + AppLogger.w(TAG, "窗口信息命令 '$command' 失败或返回空结果") + } catch (e: Exception) { + AppLogger.e(TAG, "执行窗口信息命令 '$command' 出错", e) + // 继续尝试下一个命令 + } + } + + // 所有命令都失败时,尝试获取topActivity作为最后的手段 + try { + val topActivityCommand = + "dumpsys activity activities | grep -E 'topResumedActivity|topActivity'" + val result = executeUiShellCommand(topActivityCommand) + if (result.success && result.stdout.isNotEmpty()) { + AppLogger.d(TAG, "使用topActivity作为窗口信息替代: ${result.stdout.take(100)}") + return result.stdout + } + } catch (e: Exception) { + AppLogger.e(TAG, "获取topActivity失败", e) + } + + AppLogger.e(TAG, "所有获取窗口信息的尝试均失败") + return "" + } + + /** UI节点数据类,仅在Shell实现中使用 */ + private data class UINodeShell( + val className: String?, + val text: String?, + val contentDesc: String?, + val resourceId: String?, + val bounds: String?, + val isClickable: Boolean, + val children: MutableList = mutableListOf() + ) + + /** 简化布局,从XML中提取UI元素,Shell版本 */ + private fun simplifyLayoutFromXml(xml: String): SimplifiedUINode { + val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } + val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } + + val nodeStack = mutableListOf() + var rootNode: UINodeShell? = null + + while (parser.eventType != XmlPullParser.END_DOCUMENT) { + when (parser.eventType) { + XmlPullParser.START_TAG -> { + if (parser.name == "node") { + val newNode = createNodeShell(parser) + if (rootNode == null) { + rootNode = newNode + nodeStack.add(newNode) + } else { + nodeStack.lastOrNull()?.children?.add(newNode) + nodeStack.add(newNode) + } + } + } + XmlPullParser.END_TAG -> { + if (parser.name == "node") { + nodeStack.removeLastOrNull() + } + } + } + parser.next() + } + + // 创建默认根节点,如果解析失败 + return rootNode?.toUINodeSimplified() + ?: SimplifiedUINode( + className = null, + text = null, + contentDesc = null, + resourceId = null, + bounds = null, + isClickable = false, + children = emptyList() + ) + } + + // 转换内部UINodeShell为SimplifiedUINode + private fun UINodeShell.toUINodeSimplified(): SimplifiedUINode { + return SimplifiedUINode( + className = className, + text = text, + contentDesc = contentDesc, + resourceId = resourceId, + bounds = bounds, + isClickable = isClickable, + children = children.map { it.toUINodeSimplified() } + ) + } + + private fun createNodeShell(parser: XmlPullParser): UINodeShell { + // 解析关键属性 + val className = parser.getAttributeValue(null, "class")?.substringAfterLast('.') + val text = parser.getAttributeValue(null, "text")?.replace(" ", "\n") + val contentDesc = parser.getAttributeValue(null, "content-desc") + val resourceId = parser.getAttributeValue(null, "resource-id") + val bounds = parser.getAttributeValue(null, "bounds") + val isClickable = parser.getAttributeValue(null, "clickable") == "true" + + return UINodeShell( + className = className, + text = text, + contentDesc = contentDesc, + resourceId = resourceId, + bounds = bounds, + isClickable = isClickable + ) + } + + /** 窗口焦点信息数据类 */ + private data class FocusInfoShell( + var packageName: String? = null, + var activityName: String? = null + ) + + /** 从窗口焦点数据中提取包名和活动名 */ + private fun extractFocusInfoFromShell(windowInfo: String): FocusInfoShell { + val result = FocusInfoShell() + + try { + if (windowInfo.isBlank()) { + AppLogger.w(TAG, "Window info is empty, cannot extract focus information") + // 即使窗口信息为空,也设置默认值,确保不会返回Unknown + result.packageName = "android" + result.activityName = "ForegroundActivity" + return result + } + + AppLogger.d(TAG, "Window info for extraction: ${windowInfo.take(200)}") + + // 尝试不同的提取方法,按照特异性顺序 + if (!extractFromCurrentFocusShell(windowInfo, result) && + !extractFromFocusedAppShell(windowInfo, result) && + !extractFromLauncherInfoShell(windowInfo, result) && + !extractFromTopActivityShell(windowInfo, result) && + !extractUsingGenericPatternsShell(windowInfo, result) + ) { + + AppLogger.w(TAG, "Could not extract focus information using any method") + } + + // 最后的回退:如果我们仍然无法确定任何信息,使用默认值 + if (result.packageName == null) { + if (windowInfo.contains("statusbar") || windowInfo.contains("SystemUI")) { + result.packageName = "com.android.systemui" + result.activityName = "SystemUI" + AppLogger.d(TAG, "Using SystemUI fallback") + } else if (windowInfo.contains("recents")) { + result.packageName = "com.android.systemui" + result.activityName = "Recents" + AppLogger.d(TAG, "Using Recents fallback") + } else { + result.packageName = "android" + result.activityName = "ForegroundActivity" + AppLogger.d(TAG, "Using last-resort fallback values") + } + } + + // 记录提取结果 + AppLogger.d( + TAG, + "Final extraction result - package: ${result.packageName}, activity: ${result.activityName}" + ) + } catch (e: Exception) { + AppLogger.e(TAG, "Error parsing window info", e) + // 确保即使出现异常,我们也有至少一些默认值 + if (result.packageName == null) result.packageName = "android" + if (result.activityName == null) result.activityName = "ForegroundActivity" + } + + return result + } + + /** + * 从mCurrentFocus格式提取 例如:mCurrentFocus=Window{1234567 u0 + * com.example.app/com.example.app.MainActivity} + */ + private fun extractFromCurrentFocusShell(windowInfo: String, result: FocusInfoShell): Boolean { + // 尝试多种mCurrentFocus格式模式 + val currentFocusPatterns = + listOf( + // 标准格式,具有包/活动(同时也支持 mFocusedWindow) + "(?:mCurrentFocus|mFocusedWindow)=.*?\\{.*?\\s+([a-zA-Z0-9_.]+)/([^\\s}]+)".toRegex(), + // 有时会看到的替代格式 + "(?:mCurrentFocus|mFocusedWindow)=.*?\\s+([a-zA-Z0-9_.]+)/([^\\s}]+)\\}".toRegex(), + // 只有包名的格式(活动将单独处理) + "(?:mCurrentFocus|mFocusedWindow)=.*?\\{.*?\\s+([a-zA-Z0-9_.]+)(?:/|\\s)".toRegex() + ) + + for (pattern in currentFocusPatterns) { + val match = pattern.find(windowInfo) + if (match != null) { + if (match.groupValues.size >= 3) { + // 包含包和活动的模式 + result.packageName = match.groupValues[1] + result.activityName = match.groupValues[2] + AppLogger.d(TAG, "Extracted from mCurrentFocus pattern (full): ${pattern.pattern}") + return true + } else if (match.groupValues.size >= 2) { + // 只有包名的模式 + result.packageName = match.groupValues[1] + AppLogger.d(TAG, "Extracted package from mCurrentFocus pattern: ${pattern.pattern}") + // 返回false以允许其他方法提取活动名称 + return false + } + } + } + return false + } + + /** + * 从mFocusedApp格式提取 例如:mFocusedApp=AppWindowToken{token=Token{12345 ActivityRecord{67890 u0 + * com.example.app/.MainActivity t123}}} + */ + private fun extractFromFocusedAppShell(windowInfo: String, result: FocusInfoShell): Boolean { + // mFocusedApp格式的多种模式 + val focusedAppPatterns = + listOf( + // 带有ActivityRecord的标准格式 + "mFocusedApp=.*?ActivityRecord\\{.*?\\s+([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex(), + // 处理类似于 mFocusedApp=null 后的真实输出行 + "ActivityRecord\\{.*?\\s+([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex(), + // 有时会看到的替代格式 + "mFocusedApp=.*?\\s+([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)\\s".toRegex(), + // 只有包名的格式 + "mFocusedApp=.*?\\s+([a-zA-Z0-9_.]+)(?:/|\\s)".toRegex() + ) + + for (pattern in focusedAppPatterns) { + val match = pattern.find(windowInfo) + if (match != null) { + if (match.groupValues.size >= 3) { + // 包含包和活动的完全匹配 + result.packageName = match.groupValues[1] + result.activityName = match.groupValues[2] + AppLogger.d(TAG, "Extracted from mFocusedApp pattern (full): ${pattern.pattern}") + return true + } else if (match.groupValues.size >= 2) { + // 只有包的部分匹配 + result.packageName = match.groupValues[1] + AppLogger.d(TAG, "Extracted package from mFocusedApp pattern: ${pattern.pattern}") + // 返回false以允许通过其他方法提取活动名称 + return false + } + } + } + return false + } + + /** 为启动器窗口提取信息 例如:mCurrentFocus=Window{1a23bc4 u0 Launcher} */ + private fun extractFromLauncherInfoShell(windowInfo: String, result: FocusInfoShell): Boolean { + // 查找启动器特定模式 + if (windowInfo.contains("mCurrentFocus") && windowInfo.contains("Launcher")) { + val launcherPatterns = + listOf( + "\\{.*?\\s+([a-zA-Z0-9_.]+\\.launcher)/".toRegex(), + "\\{.*?\\s+([a-zA-Z0-9_.]+\\.home)/".toRegex(), + "\\{.*?\\s+Launcher\\}".toRegex() + ) + + for (pattern in launcherPatterns) { + val match = pattern.find(windowInfo) + if (match != null && match.groupValues.size >= 2) { + result.packageName = match.groupValues[1] + result.activityName = "Launcher" + AppLogger.d(TAG, "Extracted launcher info") + return true + } + } + + // 如果我们检测到Launcher但无法提取特定的包, + // 使用默认的启动器包和名称 + result.packageName = "com.android.launcher3" + result.activityName = "Launcher" + AppLogger.d(TAG, "Using default launcher info") + return true + } + return false + } + + /** + * 从topActivity/topResumedActivity输出格式提取 + * 例如:topActivity=ComponentInfo{com.example.app/.MainActivity} + */ + private fun extractFromTopActivityShell(windowInfo: String, result: FocusInfoShell): Boolean { + // topActivity格式的模式 + val topActivityPatterns = + listOf( + "topActivity=ComponentInfo\\{([a-zA-Z0-9_.]+)/\\.?([^}]+)\\}".toRegex(), + "topResumedActivity=ComponentInfo\\{([a-zA-Z0-9_.]+)/\\.?([^}]+)\\}".toRegex(), + "ResumedActivity:\\s+\\{([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex() + ) + + for (pattern in topActivityPatterns) { + val match = pattern.find(windowInfo) + if (match != null && match.groupValues.size >= 3) { + result.packageName = match.groupValues[1] + result.activityName = match.groupValues[2] + AppLogger.d(TAG, "Extracted from topActivity pattern: ${pattern.pattern}") + return true + } + } + + // 还要查找Recent tasks格式 + val recentPattern = "Recent #0.*?\\{([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex() + val recentMatch = recentPattern.find(windowInfo) + if (recentMatch != null && recentMatch.groupValues.size >= 3) { + result.packageName = recentMatch.groupValues[1] + result.activityName = recentMatch.groupValues[2] + AppLogger.d(TAG, "Extracted from Recent tasks pattern") + return true + } + + return false + } + + /** 作为后备使用更通用的模式提取 */ + private fun extractUsingGenericPatternsShell( + windowInfo: String, + result: FocusInfoShell + ): Boolean { + var foundAny = false + + // 尝试用各种模式提取包名 + if (result.packageName == null) { + // 查找常见的包模式,如com.android.something + val packagePatterns = + listOf( + "\\s([a-zA-Z][a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+){2,})/".toRegex(), // com.example.app/ + "\\s([a-zA-Z][a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+){2,})\\s".toRegex(), // com.example.app (空格后) + "([a-zA-Z][a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+){2,})".toRegex() // 只查找任何包名类似的名称 + ) + + for (pattern in packagePatterns) { + val match = pattern.find(windowInfo) + if (match != null && match.groupValues.size >= 2) { + val potentialPackage = match.groupValues[1] + // 验证这看起来像一个真实的包(避免匹配随机字符串) + if (potentialPackage.split(".").size >= 3 && + !potentialPackage.contains("@") && + !potentialPackage.startsWith("1") && + !potentialPackage.startsWith("0") + ) { + + result.packageName = potentialPackage + foundAny = true + AppLogger.d(TAG, "Found package name using fallback pattern: ${pattern.pattern}") + break + } + } + } + } + + // 如果我们还没有活动名称,尝试提取它 + if (result.activityName == null) { + // 查找活动名称模式 + val activityPatterns = + listOf( + "/\\.?([A-Z][a-zA-Z0-9_]+Activity)".toRegex(), // /.MainActivity or + // /MainActivity + "/([^\\s/}]+)".toRegex(), // 斜杠后的任何段 + "\\.([A-Z][a-zA-Z0-9_]+)".toRegex() // .MainActivity + ) + + for (pattern in activityPatterns) { + val match = pattern.find(windowInfo) + if (match != null && match.groupValues.size >= 2) { + val activityName = match.groupValues[1] + // 验证它看起来像一个活动名称(以大写字母开头) + if (activityName.isNotEmpty() && + activityName[0].isUpperCase() && + !activityName.contains("@") + ) { + + result.activityName = activityName + foundAny = true + AppLogger.d(TAG, "Found activity name using fallback pattern: ${pattern.pattern}") + break + } + } + } + } + + // 特殊情况处理:如果我们有包名但没有活动名称 + if (result.packageName != null && result.activityName == null) { + // 尝试根据包猜测主活动名称 + val packageParts = result.packageName!!.split(".") + if (packageParts.isNotEmpty()) { + val lastPart = packageParts.last().replaceFirstChar { if (it.isLowerCase()) it.titlecase(java.util.Locale.getDefault()) else it.toString() } + result.activityName = "${lastPart}Activity" + AppLogger.d(TAG, "Guessed activity name from package: ${result.activityName}") + foundAny = true + } + } + + // 如果我们找到了包或活动,将其视为部分成功 + return foundAny + } + + + + /** 使用uiautomator点击元素 */ + private suspend fun clickElementWithUiautomator(tool: AITool): ToolResult { + AppLogger.d(TAG, "Using uiautomator to click element") + + val resourceId = tool.parameters.find { it.name == "resourceId" }?.value + val className = tool.parameters.find { it.name == "className" }?.value + val contentDesc = tool.parameters.find { it.name == "contentDesc" }?.value + val index = tool.parameters.find { it.name == "index" }?.value?.toIntOrNull() ?: 0 + val partialMatch = + tool.parameters.find { it.name == "partialMatch" }?.value?.toBoolean() ?: false + + try { + // 先尝试获取UI dump + AppLogger.d(TAG, "Dumping UI hierarchy to find element") + val dumpCommand = "uiautomator dump /sdcard/window_dump.xml" + val result = executeUiShellCommand(dumpCommand) + + if (!result.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to dump UI hierarchy: ${result.stderr ?: "Unknown error"}" + ) + } + + // 读取dump文件 + val readCommand = "cat /sdcard/window_dump.xml" + val readResult = executeUiShellCommand(readCommand) + + if (!readResult.success) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to read UI dump: ${readResult.stderr ?: "Unknown error"}" + ) + } + + val xml = readResult.stdout + + // 使用XML Parser查找匹配的元素(取代有问题的正则方式) + val hasSelectors = resourceId != null || className != null || contentDesc != null + if (!hasSelectors) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "No element selector provided." + ) + } + + // 用XmlPullParser逐节点匹配,避免正则跨节点匹配的问题 + data class MatchedNode(val bounds: String?) + val matchingNodes = mutableListOf() + + try { + val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } + val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } + + while (parser.eventType != XmlPullParser.END_DOCUMENT) { + if (parser.eventType == XmlPullParser.START_TAG && parser.name == "node") { + val actualId = parser.getAttributeValue(null, "resource-id") + val actualClass = parser.getAttributeValue(null, "class") + val actualDesc = parser.getAttributeValue(null, "content-desc") + val actualBounds = parser.getAttributeValue(null, "bounds") + + var matches = true + + if (resourceId != null) { + if (actualId == null) { + matches = false + } else if (partialMatch) { + matches = actualId.contains(resourceId) + } else { + // 支持短ID (expand_search) 和完整ID (tv.danmaku.bili:id/expand_search) + matches = actualId == resourceId || actualId.endsWith(":id/$resourceId") + } + } + + if (matches && className != null) { + if (actualClass == null) { + matches = false + } else if (partialMatch) { + matches = actualClass.contains(className) + } else { + // 支持短类名 (ImageView) 和完整类名 (android.widget.ImageView) + matches = actualClass == className || actualClass.endsWith(".$className") + } + } + + if (matches && contentDesc != null) { + if (actualDesc == null) { + matches = false + } else if (partialMatch) { + matches = actualDesc.contains(contentDesc, ignoreCase = true) + } else { + matches = actualDesc.equals(contentDesc, ignoreCase = true) + } + } + + if (matches) { + matchingNodes.add(MatchedNode(bounds = actualBounds)) + } + } + parser.next() + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error parsing UI XML", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to parse UI hierarchy XML: ${e.message}" + ) + } + + if (matchingNodes.isEmpty()) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "No matching element found." + ) + } + + if (index < 0 || index >= matchingNodes.size) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = + "Index out of range. Found ${matchingNodes.size} elements, but requested index $index." + ) + } + + // 获取指定索引的节点bounds + val nodeBounds = matchingNodes[index].bounds + if (nodeBounds == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Target element has no bounds." + ) + } + + // 提取边界坐标 + val boundsPattern = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]".toRegex() + val boundsMatch = boundsPattern.find(nodeBounds) + if (boundsMatch == null || boundsMatch.groupValues.size < 5) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to extract bounds from the element: $nodeBounds" + ) + } + + // 提取坐标 + val x1 = boundsMatch.groupValues[1].toInt() + val y1 = boundsMatch.groupValues[2].toInt() + val x2 = boundsMatch.groupValues[3].toInt() + val y2 = boundsMatch.groupValues[4].toInt() + + // 计算中心点 + val centerX = (x1 + x2) / 2 + val centerY = (y1 + y2) / 2 + + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + + val tapCommand = "input tap $centerX $centerY" + val tapResult = executeUiShellCommand(tapCommand) + + if (tapResult.success) { + val identifierDescription = + when { + resourceId != null -> " with resource ID: $resourceId" + contentDesc != null -> " with content description: $contentDesc" + else -> " with class name: $className" + } + + val matchCount = + if (matchingNodes.size > 1) { + " (index $index of ${matchingNodes.size} matches)" + } else "" + + withContext(Dispatchers.Main) { + operationOverlay.showTap(centerX, centerY) + operationOverlay.hide() + } + return ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "click", + actionDescription = + "Successfully clicked element$identifierDescription$matchCount at coordinates ($centerX, $centerY) via shell command", + coordinates = Pair(centerX, centerY), + elementId = resourceId ?: className ?: contentDesc + ), + error = "" + ) + } else { + withContext(Dispatchers.Main) { + operationOverlay.hide() + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to click element: ${tapResult.stderr ?: "Unknown error"}" + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error clicking element with uiautomator", e) + withContext(Dispatchers.Main) { + operationOverlay.hide() + } + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error clicking element: ${e.message ?: "Unknown exception"}" + ) + } finally { + // 清理临时文件 + try { + Runtime.getRuntime().exec("rm /sdcard/window_dump.xml") + } catch (cleanupEx: Exception) { + AppLogger.e(TAG, "Error cleaning up temp file", cleanupEx) + } + } + } + + /** 从边界字符串提取中心坐标 返回中心点坐标,或null如果格式无效 */ + protected fun extractCenterCoordinates(bounds: String): Pair? { + val boundsPattern = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]".toRegex() + val matchResult = boundsPattern.find(bounds) ?: return null + + if (matchResult.groupValues.size < 5) return null + + // 提取坐标 + val x1 = matchResult.groupValues[1].toInt() + val y1 = matchResult.groupValues[2].toInt() + val x2 = matchResult.groupValues[3].toInt() + val y2 = matchResult.groupValues[4].toInt() + + // 计算并返回中心点 + val centerX = (x1 + x2) / 2 + val centerY = (y1 + y2) / 2 + + return Pair(centerX, centerY) + } + + // 无障碍是管理员的执行能力,以下方法不再形成独立权限等级。 + + + + /** + * 检查无障碍服务是否正在运行 + */ + private suspend fun isAccessibilityServiceEnabled(): Boolean { + return UIHierarchyManager.isAccessibilityServiceEnabled(context) + } + + /** + * 为需要无障碍服务的工具创建一个前置检查的包装器 + */ + private suspend fun withAccessibilityCheck(tool: AITool, block: suspend () -> T): T { + if (!isAccessibilityServiceEnabled()) { + throw IllegalStateException("Accessibility Service is not enabled. Please enable it in system settings to use this feature.") + } + return block() + } + + /** + * 获取UI层次结构,失败时重试 + * @return UI层次结构XML字符串,获取失败返回空字符串 + */ + private suspend fun getUIHierarchyWithRetry(): String { + var retryCount = 0 + var uiXml = "" + + while (retryCount < MAX_RETRY_COUNT) { + uiXml = UIHierarchyManager.getUIHierarchy(context) + if (uiXml.isNotEmpty()) { + return uiXml + } + + retryCount++ + if (retryCount < MAX_RETRY_COUNT) { + AppLogger.d(TAG, "获取UI层次结构失败,正在重试 #$retryCount") + delay(RETRY_DELAY_MS) + } + } + + AppLogger.w(TAG, "获取UI层次结构失败,已重试${MAX_RETRY_COUNT}次") + return uiXml + } + + /** Gets the current UI page/window information */ + private suspend fun getPageInfoWithAccessibility(tool: AITool): ToolResult { + return try { + withAccessibilityCheck(tool) { + val format = tool.parameters.find { it.name == "format" }?.value ?: "xml" + val detail = tool.parameters.find { it.name == "detail" }?.value ?: "summary" + + if (format !in listOf("xml", "json")) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Invalid format specified. Must be 'xml' or 'json'." + ) + } + + // 使用无障碍服务获取UI数据(带重试) + val uiXml = getUIHierarchyWithRetry() + if (uiXml.isEmpty()) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to retrieve UI data via accessibility service." + ) + } + + // 解析当前窗口信息 + val focusInfo = extractFocusInfoFromAccessibility() + + // 简化布局信息 + val simplifiedLayout = simplifyLayout(uiXml) + + // 创建结构化数据 + val resultData = + UIPageResultData( + packageName = focusInfo.packageName ?: "Unknown", + activityName = focusInfo.activityName ?: "Unknown", + uiElements = simplifiedLayout + ) + + ToolResult(toolName = tool.name, success = true, result = resultData, error = "") + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error getting page info", e) + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error getting page info: ${e.message}" + ) + } + } + + /** 从无障碍服务获取焦点信息 */ + private suspend fun extractFocusInfoFromAccessibility(): FocusInfo { + val focusInfo = FocusInfo() + try { + // 1. 获取UI层次结构的XML快照(带重试) + val hierarchyXml = getUIHierarchyWithRetry() + if (hierarchyXml.isEmpty()) { + AppLogger.w(TAG, "无法获取UI层次结构XML,使用默认值。") + focusInfo.packageName = "android" + // 即使XML获取失败,仍然尝试获取Activity名称 + focusInfo.activityName = UIHierarchyManager.getCurrentActivityName(context) ?: "ForegroundActivity" + return focusInfo + } + + // 2. 从XML中解析包名 + val (packageName, _) = UIHierarchyManager.extractWindowInfo(hierarchyXml) + // 3. 从服务中直接获取当前Activity名称 + val activityName = UIHierarchyManager.getCurrentActivityName(context) + + focusInfo.packageName = packageName + focusInfo.activityName = activityName // 使用从服务获取的Activity名称 + + // 如果没有获取到,使用默认值 + if (focusInfo.packageName == null) focusInfo.packageName = "android" + if (focusInfo.activityName == null) focusInfo.activityName = "ForegroundActivity" + } catch (e: Exception) { + AppLogger.e(TAG, "从XML解析焦点信息时出错", e) + // 设置默认值 + focusInfo.packageName = "android" + focusInfo.activityName = "ForegroundActivity" + } + return focusInfo + } + + /** 简化XML布局为节点树 */ + fun simplifyLayout(xml: String): SimplifiedUINode { + val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } + val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } + + val nodeStack = mutableListOf() + var rootNode: UINode? = null + + while (parser.eventType != XmlPullParser.END_DOCUMENT) { + when (parser.eventType) { + XmlPullParser.START_TAG -> { + if (parser.name == "node") { + val newNode = createNode(parser) + if (rootNode == null) { + rootNode = newNode + nodeStack.add(newNode) + } else { + nodeStack.lastOrNull()?.children?.add(newNode) + nodeStack.add(newNode) + } + } + } + XmlPullParser.END_TAG -> { + if (parser.name == "node") { + nodeStack.removeLastOrNull() + } + } + } + parser.next() + } + + return rootNode?.toUINode() + ?: SimplifiedUINode( + className = null, + text = null, + contentDesc = null, + resourceId = null, + bounds = null, + isClickable = false, + children = emptyList() + ) + } + + private fun createNode(parser: XmlPullParser): UINode { + // 解析关键属性 + val className = parser.getAttributeValue(null, "class")?.substringAfterLast('.') + val text = parser.getAttributeValue(null, "text")?.replace(" ", "\n") + val contentDesc = parser.getAttributeValue(null, "content-desc") + val resourceId = parser.getAttributeValue(null, "resource-id") + val bounds = parser.getAttributeValue(null, "bounds") + val isClickable = parser.getAttributeValue(null, "clickable") == "true" + + return UINode( + className = className, + text = text, + contentDesc = contentDesc, + resourceId = resourceId, + bounds = bounds, + isClickable = isClickable + ) + } + + /** 点击元素 */ + private suspend fun clickElementWithAccessibility(tool: AITool): ToolResult { + return try { + withAccessibilityCheck(tool) { + val resourceId = tool.parameters.find { it.name == "resourceId" }?.value + val className = tool.parameters.find { it.name == "className" }?.value + val contentDesc = tool.parameters.find { it.name == "contentDesc" }?.value + val index = tool.parameters.find { it.name == "index" }?.value?.toIntOrNull() ?: 0 + val bounds = tool.parameters.find { it.name == "bounds" }?.value + + if (resourceId == null && className == null && bounds == null && contentDesc == null) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Missing element identifier. Provide at least one of 'resourceId', 'className', 'contentDesc', or 'bounds'." + ) + } + + // 如果提供了边界坐标,直接解析并点击中心点 + if (bounds != null) { + return@withAccessibilityCheck handleClickByBounds(tool, bounds) + } + + // 获取UI层次结构XML(带重试) + val uiXml = getUIHierarchyWithRetry() + if (uiXml.isEmpty()) { + return@withAccessibilityCheck ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Unable to get UI hierarchy.") + } + + // 在XML中查找匹配的节点 + val matchedNodes = findNodesInXml(uiXml) { parser -> + val hasSelectors = resourceId != null || className != null || contentDesc != null + if (!hasSelectors) { + return@findNodesInXml false + } + + val actualId = parser.getAttributeValue(null, "resource-id") + val actualClass = parser.getAttributeValue(null, "class") + val actualDesc = parser.getAttributeValue(null, "content-desc") + + if(resourceId != null && (actualId == null || !actualId.endsWith(resourceId))){ + return@findNodesInXml false + } + + if(className != null && (actualClass == null || actualClass != className)){ + return@findNodesInXml false + } + + if(contentDesc != null && (actualDesc == null || !actualDesc.equals(contentDesc, ignoreCase = true))){ + return@findNodesInXml false + } + + true + } + + if (matchedNodes.isEmpty()) { + return@withAccessibilityCheck ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "No matching element found.") + } + + // 检查索引是否有效 + if (index < 0 || index >= matchedNodes.size) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Index out of range. Found ${matchedNodes.size} elements, but requested index $index." + ) + } + + // 获取目标节点的bounds + val targetNodeBounds = matchedNodes[index].bounds + if (targetNodeBounds == null) { + return@withAccessibilityCheck ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Target element has no bounds.") + } + + // 解析bounds并点击 + handleClickByBounds(tool, targetNodeBounds) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error clicking element", e) + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error clicking element: ${e.message}" + ) + } + } + + private suspend fun handleClickByBounds(tool: AITool, bounds: String): ToolResult { + try { + val rect = parseBounds(bounds) + if (rect.isEmpty) { + return ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Invalid bounds format: $bounds") + } + + val centerX = rect.centerX() + val centerY = rect.centerY() + + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + val clickSuccess = performAccessibilityClick(centerX, centerY) + + return if (clickSuccess) { + withContext(Dispatchers.Main) { + operationOverlay.showTap(centerX, centerY) + operationOverlay.hide() + } + ToolResult( + toolName = tool.name, + success = true, + result = UIActionResultData( + actionType = "click", + actionDescription = "Successfully clicked at bounds $bounds", + coordinates = Pair(centerX, centerY) + ) + ) + } else { + operationOverlay.hide() + ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Failed to click at bounds $bounds via accessibility service.") + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error clicking by bounds", e) + operationOverlay.hide() + return ToolResult(toolName = tool.name, success = false, result = StringResultData(""), error = "Error clicking at bounds: ${e.message}") + } + } + + private fun findNodesInXml(xml: String, predicate: (parser: XmlPullParser) -> Boolean): List { + val matchedNodes = mutableListOf() + val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } + val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } + + while (parser.eventType != XmlPullParser.END_DOCUMENT) { + if (parser.eventType == XmlPullParser.START_TAG && parser.name == "node") { + if (predicate(parser)) { + matchedNodes.add( + NodeInfo( + bounds = parser.getAttributeValue(null, "bounds"), + text = parser.getAttributeValue(null, "text") + ) + ) + } + } + parser.next() + } + return matchedNodes + } + + private data class NodeInfo(val bounds: String?, val text: String?) + + /** 设置输入文本 */ + private suspend fun setInputTextWithAccessibility(tool: AITool): ToolResult { + return try { + withAccessibilityCheck(tool) { + val text = tool.parameters.find { it.name == "text" }?.value ?: "" + + // 通过UIHierarchyManager请求远程服务找到焦点节点的ID + val focusedNodeId = UIHierarchyManager.findFocusedNodeId(context) + if (focusedNodeId.isNullOrEmpty()) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "No focused editable field found." + ) + } + + // 显示反馈 + val rect = parseBounds(focusedNodeId) + if (!rect.isEmpty) { + operationOverlay.showTextInput(rect.centerX(), rect.centerY(), text) + } + + // 通过UIHierarchyManager请求远程服务设置文本 + val result = UIHierarchyManager.setTextOnNode(context, focusedNodeId, text) + + if (result) { + // 成功后主动隐藏overlay + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "textInput", + actionDescription = + "Successfully set input text via accessibility service" + ), + error = "" + ) + } else { + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to set text via accessibility service." + ) + } + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error setting input text", e) + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error setting input text: ${e.message}" + ) + } + } + + /** 执行轻触操作 */ + private suspend fun tapWithAccessibility(tool: AITool): ToolResult { + return try { + withAccessibilityCheck(tool) { + val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() + val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() + + if (x == null || y == null) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." + ) + } + + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + + // 使用无障碍服务执行点击 + val result = performAccessibilityClick(x, y) + + if (result) { + withContext(Dispatchers.Main) { + operationOverlay.showTap(x, y) + operationOverlay.hide() + } + ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "tap", + actionDescription = + "Successfully tapped at coordinates ($x, $y) via accessibility service", + coordinates = Pair(x, y) + ), + error = "" + ) + } else { + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to tap at coordinates via accessibility service." + ) + } + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error tapping at coordinates", e) + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error tapping at coordinates: ${e.message}" + ) + } + } + + /** 执行长按操作 */ + private suspend fun longPressWithAccessibility(tool: AITool): ToolResult { + return try { + withAccessibilityCheck(tool) { + val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() + val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() + + if (x == null || y == null) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." + ) + } + + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + + // 使用无障碍服务执行长按 + val result = performAccessibilityLongPress(x, y) + + if (result) { + withContext(Dispatchers.Main) { + operationOverlay.showTap(x, y) + operationOverlay.hide() + } + ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "long_press", + actionDescription = + "Successfully long pressed at coordinates ($x, $y) via accessibility service", + coordinates = Pair(x, y) + ), + error = "" + ) + } else { + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to long press at coordinates via accessibility service." + ) + } + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error long pressing at coordinates", e) + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error long pressing at coordinates: ${e.message}" + ) + } + } + + /** 执行滑动操作 */ + private suspend fun swipeWithAccessibility(tool: AITool): ToolResult { + return try { + withAccessibilityCheck(tool) { + val startX = tool.parameters.find { it.name == "start_x" }?.value?.toIntOrNull() + val startY = tool.parameters.find { it.name == "start_y" }?.value?.toIntOrNull() + val endX = tool.parameters.find { it.name == "end_x" }?.value?.toIntOrNull() + val endY = tool.parameters.find { it.name == "end_y" }?.value?.toIntOrNull() + val duration = tool.parameters.find { it.name == "duration" }?.value?.toIntOrNull() ?: 300 + + if (startX == null || startY == null || endX == null || endY == null) { + return@withAccessibilityCheck ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Missing or invalid coordinates. 'start_x', 'start_y', 'end_x', and 'end_y' must be valid integers." + ) + } + + withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } + + // 使用无障碍服务执行滑动 + val result = performAccessibilitySwipe(startX, startY, endX, endY, duration) + + if (result) { + withContext(Dispatchers.Main) { + operationOverlay.showSwipe(startX, startY, endX, endY) + operationOverlay.hide() + } + ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "swipe", + actionDescription = + "Successfully performed swipe from ($startX, $startY) to ($endX, $endY) via accessibility service" + ), + error = "" + ) + } else { + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Failed to perform swipe via accessibility service." + ) + } + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error performing swipe", e) + operationOverlay.hide() + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error performing swipe: ${e.message}" + ) + } + } + + // 使用无障碍服务执行点击的辅助方法 + private suspend fun performAccessibilityClick(x: Int, y: Int): Boolean { + return try { + UIHierarchyManager.performClick(context, x, y) + } catch (e: Exception) { + AppLogger.e(TAG, "Error performing accessibility click", e) + return false + } + } + + // 使用无障碍服务执行长按的辅助方法 + private suspend fun performAccessibilityLongPress(x: Int, y: Int): Boolean { + return try { + UIHierarchyManager.performLongPress(context, x, y) + } catch (e: Exception) { + AppLogger.e(TAG, "Error performing accessibility long press", e) + return false + } + } + + // 使用无障碍服务执行滑动的辅助方法 + private suspend fun performAccessibilitySwipe( + startX: Int, + startY: Int, + endX: Int, + endY: Int, + duration: Int + ): Boolean { + return try { + UIHierarchyManager.performSwipe(context, startX, startY, endX, endY, duration.toLong()) + } catch (e: Exception) { + AppLogger.e(TAG, "Error performing accessibility swipe", e) + return false + } + } + + protected fun accessibilityKeyAction(keyCode: String): Int? = when (keyCode) { + "KEYCODE_BACK" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_BACK + "KEYCODE_HOME" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_HOME + "KEYCODE_RECENTS" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_RECENTS + "KEYCODE_NOTIFICATIONS" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS + "KEYCODE_QUICK_SETTINGS" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS + "KEYCODE_POWER_DIALOG" -> android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_POWER_DIALOG + else -> null + } + + /** 模拟按键操作 */ + private suspend fun pressKeyWithAccessibility(tool: AITool): ToolResult { + val keyCode = tool.parameters.find { it.name == "key_code" }?.value + + if (keyCode == null) { + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Missing 'key_code' parameter." + ) + } + + try { + // 将字符串keyCode转换为AccessibilityService中的常量 + val keyAction = accessibilityKeyAction(keyCode) + + if (keyAction != null) { + // 通过UIHierarchyManager请求远程服务执行操作 + val success = UIHierarchyManager.performGlobalAction(context, keyAction) + return if (success) { + ToolResult( + toolName = tool.name, + success = true, + result = + UIActionResultData( + actionType = "keyPress", + actionDescription = + "Successfully pressed key: $keyCode via accessibility service" + ), + error = "" + ) + } else { + ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = + "Failed to press key: $keyCode via accessibility service. Not all keys are supported." + ) + } + } else { + // 如果不是标准全局操作,返回不支持的错误 + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = + "Key: $keyCode is not supported via accessibility service. Only system keys like BACK, HOME, etc. are supported." + ) + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error pressing key", e) + return ToolResult( + toolName = tool.name, + success = false, + result = StringResultData(""), + error = "Error pressing key: ${e.message ?: "Unknown exception"}" + ) + } + } + + private suspend fun captureScreenshotToFileWithAccessibility(tool: AITool): Pair?> { + return try { + val screenshotDir = OperitPaths.cleanOnExitDir() + + val shortName = System.currentTimeMillis().toString().takeLast(4) + val file = File(screenshotDir, "$shortName.png") + + val success = UIHierarchyManager.takeScreenshot(context, file.absolutePath, "png") + if (!success) { + AppLogger.w(TAG, "captureScreenshotForAgent: AIDL takeScreenshot failed") + return Pair(null, null) + } + + val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } + BitmapFactory.decodeFile(file.absolutePath, options) + val dimensions = if (options.outWidth > 0 && options.outHeight > 0) { + Pair(options.outWidth, options.outHeight) + } else { + null + } + + Pair(file.absolutePath, dimensions) + } catch (e: Exception) { + AppLogger.e(TAG, "captureScreenshot via accessibility failed", e) + Pair(null, null) + } + } + + private suspend fun captureScreenshotWithAccessibility(tool: AITool): Pair?> { + return captureScreenshotToFile(tool) + } + + private suspend fun captureScreenshotBitmapWithAccessibility(tool: AITool): Pair?> { + val (filePath, dimensions) = captureScreenshot(tool) + if (filePath == null) { + return Pair(null, dimensions) + } + + val bitmap = BitmapFactory.decodeFile(filePath) ?: return Pair(null, dimensions) + val resolvedDimensions = dimensions ?: Pair(bitmap.width, bitmap.height) + return Pair(bitmap, resolvedDimensions) + } + + private fun parseBounds(boundsString: String): android.graphics.Rect { + // 解析 "[left,top][right,bottom]" 格式的边界字符串 + val rect = android.graphics.Rect() + try { + val parts = boundsString.replace("[", "").replace("]", ",").split(",") + if (parts.size >= 4) { + rect.left = parts[0].toInt() + rect.top = parts[1].toInt() + rect.right = parts[2].toInt() + rect.bottom = parts[3].toInt() + } + } catch (e: Exception) { + AppLogger.e(TAG, "Error parsing bounds: $boundsString", e) + } + return rect + } } diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerDeviceInfoToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerDeviceInfoToolExecutor.kt deleted file mode 100644 index 2f7a134df3..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerDeviceInfoToolExecutor.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.debugger - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.accessbility.AccessibilityDeviceInfoToolExecutor - -/** 调试级别的设备信息工具,继承无障碍版本 */ -open class DebuggerDeviceInfoToolExecutor(context: Context) : - AccessibilityDeviceInfoToolExecutor(context) { - // 当前阶段不添加新功能,仅继承无障碍实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerFileSystemTools.kt deleted file mode 100644 index 89bc40e8fe..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerFileSystemTools.kt +++ /dev/null @@ -1,2930 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.debugger - -import android.content.ActivityNotFoundException -import android.content.ClipData -import android.content.Context -import android.content.Intent -import android.webkit.MimeTypeMap -import androidx.core.content.FileProvider -import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.DirectoryListingData -import com.ai.assistance.operit.core.tools.FileContentData -import com.ai.assistance.operit.core.tools.FileExistsData -import com.ai.assistance.operit.core.tools.FileInfoData -import com.ai.assistance.operit.core.tools.FileOperationData -import com.ai.assistance.operit.core.tools.FilePartContentData -import com.ai.assistance.operit.core.tools.FindFilesResultData -import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutionLimits -import com.ai.assistance.operit.BuildConfig -import com.ai.assistance.operit.core.tools.defaultTool.accessbility.AccessibilityFileSystemTools -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor -import com.ai.assistance.operit.data.model.AITool -import com.ai.assistance.operit.data.model.ToolParameter -import com.ai.assistance.operit.data.model.ToolResult -import com.ai.assistance.operit.core.tools.defaultTool.PathValidator -import java.io.BufferedInputStream -import java.io.BufferedOutputStream -import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.concurrent.atomic.AtomicInteger -import java.util.zip.ZipEntry -import java.util.zip.ZipFile -import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream -import kotlin.math.exp -import com.ai.assistance.operit.util.files.FileUtils -import com.ai.assistance.operit.core.tools.ToolProgressBus -import com.ai.assistance.operit.util.files.AndroidUserPathUtils -import kotlinx.coroutines.cancelAndJoin -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.isActive -import kotlinx.coroutines.launch -import kotlinx.coroutines.flow.collect - -/** 调试者级别的文件系统工具,继承无障碍版本 */ -open class DebuggerFileSystemTools(context: Context) : AccessibilityFileSystemTools(context) { - companion object { - private const val TAG = "DebuggerFileSystemTools" - internal fun isOperitInternalPath(path: String): Boolean { - val normalizedPath = path.trim() - val appPackage = BuildConfig.APPLICATION_ID - return normalizedPath.startsWith("/data/data/$appPackage") || - AndroidUserPathUtils.isCurrentUserPackageDataPath(normalizedPath, appPackage) - } - } - - /** - * 判断路径是否为Operit应用的内部存储路径 - * 仅针对 Operit 应用自身数据目录路径返回true - */ - protected fun isOperitInternalPath(path: String): Boolean { - return Companion.isOperitInternalPath(path) - } - - private fun shQuote(value: String): String { - return "'" + value.replace("'", "'\"'\"'") + "'" - } - - private fun smoothProgress(count: Int, scale: Float): Float { - if (count <= 0) return 0f - return (1f - exp(-count / scale)).coerceIn(0f, 0.99f) - } - - private fun updateProgressFloor(progressFloor: AtomicInteger, candidate: Int) { - while (true) { - val old = progressFloor.get() - if (candidate <= old) return - if (progressFloor.compareAndSet(old, candidate)) return - } - } - - /** List files in a directory */ - override suspend fun listFiles(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.listFiles(tool) - } - if (isSafEnvironment(environment)) { - return super.listFiles(tool) - } - - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super(AccessibilityFileSystemTools)的高权限方法 - if (isOperitInternalPath(path)) { - return super.listFiles(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Path parameter is required" - ) - } - - return try { - // 确保目录路径末尾有斜杠 - val normalizedPath = if (path.endsWith("/")) path else "$path/" - - // 使用ls -la命令获取详细的文件列表 - AppLogger.d(TAG, "Using ls -la command for path: $normalizedPath") - val listResult = AndroidShellExecutor.executeShellCommand("ls -la '$normalizedPath'") - - if (listResult.success) { - AppLogger.d(TAG, "ls -la command output: ${listResult.stdout}") - - // 解析ls -la命令输出 - val entries = parseDetailedDirectoryListing(listResult.stdout, normalizedPath) - - AppLogger.d(TAG, "Parsed ${entries.size} entries from ls -la output") - - return ToolResult( - toolName = tool.name, - success = true, - result = DirectoryListingData(path, entries), - error = "" - ) - } else { - AppLogger.w(TAG, "ls -la command failed: ${listResult.stderr}") - - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to list directory: ${listResult.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error listing directory", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error listing directory: ${e.message}" - ) - } - } - - /** Parse the output of the ls -la command into structured data */ - protected fun parseDetailedDirectoryListing( - output: String, - path: String - ): List { - val lines = output.trim().split("\n") - val entries = mutableListOf() - - AppLogger.d(TAG, "Parsing ${lines.size} lines from ls -la output") - - // 跳过第一行总计行 - val startIndex = if (lines.isNotEmpty() && lines[0].startsWith("total")) 1 else 0 - - // 日期格式化器,用于解析日期时间字符串 - val dateFormat = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm", java.util.Locale.US) - - for (i in startIndex until lines.size) { - try { - val line = lines[i] - if (line.isBlank()) continue - - // 打印每一行以便调试 - AppLogger.d(TAG, "Parsing line: $line") - - // Android上ls -la输出格式: crwxrw--- 2 u0_a425 media_rw 4056 2025-03-14 - // 06:04 Android - // 符号链接格式: lrwxrwxrwx 1 root root 12 2025-03-14 06:04 filename -> - // /path/to/target - - // 使用正则表达式解析Android上的ls -la输出 - val androidRegex = - """^(\S+)\s+(\d+)\s+(\S+\s*\S*)\s+(\S+)\s+(\d+)\s+(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2})\s+(.+)$""".toRegex() - val androidMatch = androidRegex.find(line) - - if (androidMatch != null) { - // 特定于Android的格式解析 - val permissions = androidMatch.groupValues[1] - val size = androidMatch.groupValues[5].toLongOrNull() ?: 0 - val date = androidMatch.groupValues[6] - val time = androidMatch.groupValues[7] - var name = androidMatch.groupValues[8] - val isDirectory = permissions.startsWith("d") || permissions.startsWith("c") - val isSymlink = permissions.startsWith("l") - - // 处理符号链接格式 "name -> target" - if (isSymlink && name.contains(" -> ")) { - name = name.substringBefore(" -> ") - AppLogger.d(TAG, "Found symlink: $name") - } - - // 跳过 . 和 .. 条目 - if (name == "." || name == "..") continue - - // 将日期和时间转换为时间戳 - val dateTimeStr = "$date $time" - val timestamp = - try { - val parsedDate = dateFormat.parse(dateTimeStr) - parsedDate?.time?.toString() ?: "0" - } catch (e: Exception) { - AppLogger.e(TAG, "Error parsing date: $dateTimeStr", e) - "0" // 解析失败时使用默认时间戳 - } - - AppLogger.d( - TAG, - "Successfully parsed $name with date $dateTimeStr -> timestamp $timestamp" - ) - - entries.add( - DirectoryListingData.FileEntry( - name = name, - isDirectory = isDirectory, - size = size, - permissions = permissions, - lastModified = timestamp // 使用时间戳字符串 - ) - ) - continue - } - - // 如果Android特定格式不匹配,尝试通用格式 - val genericRegex = - """^([\-ld][\w-]{9})\s+(\d+)\s+(\w+)\s+(\w+)\s+(\d+)\s+([\w\d\s\-:\.]+)\s+(.+)$""".toRegex() - val match = genericRegex.find(line) - - if (match != null) { - val permissions = match.groupValues[1] - val size = match.groupValues[5].toLongOrNull() ?: 0 - val dateTimeStr = match.groupValues[6].trim() - var name = match.groupValues[7] - val isDirectory = permissions.startsWith("d") - val isSymlink = permissions.startsWith("l") - - // 处理符号链接格式 "name -> target" - if (isSymlink && name.contains(" -> ")) { - name = name.substringBefore(" -> ") - AppLogger.d(TAG, "Found symlink (generic): $name") - } - - // 跳过 . 和 .. 条目 - if (name == "." || name == "..") continue - - // 尝试解析通用格式的日期时间 - val timestamp = - try { - if (dateTimeStr.matches( - """^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}$""".toRegex() - ) - ) { - val parsedDate = dateFormat.parse(dateTimeStr) - parsedDate?.time?.toString() ?: "0" - } else { - // 如果不是YYYY-MM-DD HH:MM格式,返回当前时间 - System.currentTimeMillis().toString() - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error parsing generic date: $dateTimeStr", e) - "0" - } - - entries.add( - DirectoryListingData.FileEntry( - name = name, - isDirectory = isDirectory, - size = size, - permissions = permissions, - lastModified = timestamp - ) - ) - } else { - // 如果标准正则表达式也不匹配,使用更宽松的解析方法 - // 权限字段始终是10个字符 - if (line.length < 10) continue - - val permissions = line.substring(0, 10).trim() - val isDirectory = permissions.startsWith("d") || permissions.startsWith("c") - - // 解析剩余部分 - val parts = line.substring(10).trim().split("\\s+".toRegex()) - - if (parts.size < 6) { - AppLogger.w(TAG, "Invalid ls -la format: $line") - continue - } - - // 查找日期部分 - Android上通常是YYYY-MM-DD格式 - val dateIndex = - parts.indexOfFirst { it.matches("""^\d{4}-\d{2}-\d{2}$""".toRegex()) } - - if (dateIndex < 0 || dateIndex + 1 >= parts.size) { - AppLogger.w(TAG, "Cannot find date in line: $line") - continue - } - - // 日期后面的字段通常是时间 (HH:MM) - val timeIndex = dateIndex + 1 - - // 时间后面的所有内容都是文件名 - val nameStartIndex = timeIndex + 1 - if (nameStartIndex >= parts.size) { - AppLogger.w(TAG, "Cannot find filename position: $line") - continue - } - - var name = parts.subList(nameStartIndex, parts.size).joinToString(" ") - val isSymlink = permissions.startsWith("l") - - // 处理符号链接格式 "name -> target" - if (isSymlink && name.contains(" -> ")) { - name = name.substringBefore(" -> ") - AppLogger.d(TAG, "Found symlink (fallback): $name") - } - - // 跳过 . 和 .. 条目 - if (name == "." || name == "..") continue - - // 文件大小通常在用户和组之后,日期之前 - val sizeIndex = dateIndex - 1 - val size = if (sizeIndex >= 0) parts[sizeIndex].toLongOrNull() ?: 0 else 0 - - // 组合日期和时间,并转换为时间戳 - val dateTimeStr = "${parts[dateIndex]} ${parts[timeIndex]}" - val timestamp = - try { - val parsedDate = dateFormat.parse(dateTimeStr) - parsedDate?.time?.toString() ?: "0" - } catch (e: Exception) { - AppLogger.e(TAG, "Error parsing fallback date: $dateTimeStr", e) - "0" - } - - entries.add( - DirectoryListingData.FileEntry( - name = name, - isDirectory = isDirectory, - size = size, - permissions = permissions, - lastModified = timestamp - ) - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error parsing directory entry: ${lines[i]}", e) - // 跳过这一行但继续处理其他行 - } - } - - return entries - } - - /** 将八进制权限格式转换为字符串表示 (如 "rwxr-xr-x") */ - protected fun convertOctalPermToString(octalPerm: String): String { - try { - val permInt = octalPerm.toInt(8) - val permChars = CharArray(9) - - // 所有者权限 - permChars[0] = if (permInt and 0x100 != 0) 'r' else '-' - permChars[1] = if (permInt and 0x80 != 0) 'w' else '-' - permChars[2] = if (permInt and 0x40 != 0) 'x' else '-' - - // 组权限 - permChars[3] = if (permInt and 0x20 != 0) 'r' else '-' - permChars[4] = if (permInt and 0x10 != 0) 'w' else '-' - permChars[5] = if (permInt and 0x8 != 0) 'x' else '-' - - // 其他用户权限 - permChars[6] = if (permInt and 0x4 != 0) 'r' else '-' - permChars[7] = if (permInt and 0x2 != 0) 'w' else '-' - permChars[8] = if (permInt and 0x1 != 0) 'x' else '-' - - return String(permChars) - } catch (e: Exception) { - AppLogger.e(TAG, "Error converting octal permission: $octalPerm", e) - return "???" - } - } - - /** - * Reads the full content of a file as a new tool, handling different file types. - * This function does not enforce a size limit. - */ - override suspend fun readFileFull(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.readFileFull(tool) - } - if (isSafEnvironment(environment)) { - return super.readFileFull(tool) - } - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - val textOnly = tool.parameters.find { it.name == "text_only" }?.value?.toBoolean() ?: false - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.readFileFull(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Path parameter is required" - ) - } - - try { - // First check if the file exists using shell command - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -f '$path' && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "File does not exist: $path" - ) - } - - // Check file extension - val fileExt = path.substringAfterLast('.', "").lowercase() - - // Handle special file types by calling the parent's handler - val specialReadResult = super.handleSpecialFileRead(tool, path, fileExt) - if (specialReadResult != null) { - // If the parent handled it, return its result. - // But if it failed, we might want to fall back to shell `cat` for some types. - if (specialReadResult.success) { - return specialReadResult - } - // Optional: Could add fallback logic here if superclass fails for some reason - } - - // Check if file is text-like by reading first few bytes (if text_only is enabled) - if (textOnly) { - // First, get a sample of the file - val sampleResult = AndroidShellExecutor.executeShellCommand("head -c 512 '$path'") - if (!sampleResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to sample file: ${sampleResult.stderr}" - ) - } - - // Analyze the sample bytes - val sampleBytes = sampleResult.stdout.toByteArray() - if (!FileUtils.isTextLike(sampleBytes)) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Skipped non-text file: $path" - ) - } - } - - // For text-like files, use shell `cat` to read full content - val result = AndroidShellExecutor.executeShellCommand("cat '$path'") - if (result.success) { - val sizeResult = - AndroidShellExecutor.executeShellCommand("stat -c %s '$path'") - val size = - sizeResult.stdout.trim().toLongOrNull() - ?: result.stdout.length.toLong() - - return ToolResult( - toolName = tool.name, - success = true, - result = - FileContentData( - path = path, - content = result.stdout, - size = size - ), - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to read file: ${result.stderr}" - ) - } - - } catch (e: Exception) { - AppLogger.e(TAG, "Error reading file", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error reading file: ${e.message}" - ) - } - } - - /** Read file content */ - override suspend fun readFile(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.readFile(tool) - } - if (isSafEnvironment(environment)) { - return super.readFile(tool) - } - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.readFile(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Path parameter is required" - ) - } - - try { - val fileExt = path.substringAfterLast('.', "").lowercase() - - // For special types, full read then truncate text is the only way. - if (isSpecialFileType(fileExt)) { - val fullResult = readFileFull(tool) - if (!fullResult.success) return fullResult - - val contentData = fullResult.result as FileContentData - var content = contentData.content - val isTruncated = content.length > ToolExecutionLimits.MAX_FILE_READ_BYTES - if (isTruncated) { - content = content.substring(0, ToolExecutionLimits.MAX_FILE_READ_BYTES) - } - - var contentWithLineNumbers = addLineNumbers(content) - if (isTruncated) { - contentWithLineNumbers += "\n\n... (file content truncated) ..." - } - - return ToolResult( - toolName = tool.name, - success = true, - result = FileContentData(path = path, content = contentWithLineNumbers, size = contentWithLineNumbers.length.toLong()), - error = "" - ) - } - - // For text-based files, read only the beginning. - // Check if file is text-like by analyzing a sample - val sampleResult = AndroidShellExecutor.executeShellCommand("head -c 512 '$path'") - if (sampleResult.success) { - val sampleBytes = sampleResult.stdout.toByteArray() - if (!FileUtils.isTextLike(sampleBytes)) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "File does not appear to be a text file. Use readFileFull tool for special file types." - ) - } - } - - // Check file size to see if truncation is needed - val sizeResult = AndroidShellExecutor.executeShellCommand("stat -c %s '$path'") - val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 - val truncated = size > ToolExecutionLimits.MAX_FILE_READ_BYTES - - val readCommand = "head -c ${ToolExecutionLimits.MAX_FILE_READ_BYTES} '$path'" - val readResult = AndroidShellExecutor.executeShellCommand(readCommand) - - if (!readResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to read file: ${readResult.stderr}" - ) - } - - var content = readResult.stdout - var contentWithLineNumbers = addLineNumbers(content) - if (truncated) { - contentWithLineNumbers += "\n\n... (file content truncated) ..." - } - - return ToolResult( - toolName = tool.name, - success = true, - result = - FileContentData( - path = path, - content = contentWithLineNumbers, - size = contentWithLineNumbers.length.toLong() - ), - error = "" - ) - } catch (e: Exception) { - AppLogger.e(TAG, "Error reading file", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error reading file: ${e.message}" - ) - } - } - - /** 按行号范围读取文件内容(行号从1开始,包括开始行和结束行) */ - override suspend fun readFilePart(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.readFilePart(tool) - } - if (isSafEnvironment(environment)) { - return super.readFilePart(tool) - } - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.readFilePart(tool) - } - val startLineParam = tool.parameters.find { it.name == "start_line" }?.value?.toIntOrNull() ?: 1 - val endLineParam = tool.parameters.find { it.name == "end_line" }?.value?.toIntOrNull() - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Path parameter is required" - ) - } - - return try { - // 0. 特殊文件类型检查 - // 如果是Word/PDF/图片等特殊文件,使用父类(StandardFileSystemTools)的逻辑处理 - // 因为Shell命令(cat/sed)无法正确解析这些二进制格式 - val fileExt = path.substringAfterLast('.', "").lowercase() - if (isSpecialFileType(fileExt)) { - return super.readFilePart(tool) - } - - // 1. Check if file exists - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -f '$path' && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "File does not exist: $path" - ) - } - - // 2. Get total number of lines - val wcResult = AndroidShellExecutor.executeShellCommand("cat '$path' | wc -l") - if (!wcResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to count lines in file: ${wcResult.stderr}" - ) - } - - val totalLines = wcResult.stdout.trim().split(" ")[0].toIntOrNull() ?: 0 - - // 3. 计算实际的行号范围(行号从1开始) - val startLine = maxOf(1, startLineParam).coerceIn(1, maxOf(1, totalLines)) - val endLine = - (endLineParam - ?: (startLine + ToolExecutionLimits.DEFAULT_FILE_READ_PART_LINES - 1)) - .coerceIn(startLine, maxOf(1, totalLines)) - - if (totalLines == 0 || startLine > endLine) { - return ToolResult( - toolName = tool.name, - success = true, - result = - FilePartContentData( - path = path, - content = "", - partIndex = 0, // 保留兼容性,但不再使用 - totalParts = 1, // 保留兼容性,但不再使用 - startLine = startLine - 1, // 转为0-based - endLine = endLine, - totalLines = totalLines - ), - error = "" - ) - } - - // 4. Extract the specific part using sed - val sedCommand = "sed -n '${startLine},${endLine}p' '$path'" - val partResult = AndroidShellExecutor.executeShellCommand(sedCommand) - - if (!partResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to read file part: ${partResult.stderr}" - ) - } - - val maxFileSizeBytes = ToolExecutionLimits.MAX_FILE_READ_BYTES - var content = partResult.stdout - val isTruncated = content.length > maxFileSizeBytes - if (isTruncated) { - content = content.substring(0, maxFileSizeBytes) - } - - var contentWithLineNumbers = addLineNumbers(content, startLine, totalLines) - if (isTruncated) { - contentWithLineNumbers += "\n\n... (file content truncated) ..." - } - - ToolResult( - toolName = tool.name, - success = true, - result = - FilePartContentData( - path = path, - content = contentWithLineNumbers.trimEnd(), - partIndex = 0, // 保留兼容性,但不再使用 - totalParts = 1, // 保留兼容性,但不再使用 - startLine = startLine - 1, // To 0-indexed for response - endLine = endLine, - totalLines = totalLines - ), - error = "" - ) - } catch (e: Exception) { - AppLogger.e(TAG, "Error reading file part", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error reading file part: ${e.message}" - ) - } - } - - /** - * 重写特殊文件读取逻辑 - * 对于受保护的路径(如 /Android/data),先通过Shell命令复制到缓存目录, - * 再调用父类的解析逻辑。 - */ - override suspend fun handleSpecialFileRead( - tool: AITool, - path: String, - fileExt: String - ): ToolResult? { - val file = File(path) - - if (isOperitInternalPath(path)) { - return super.handleSpecialFileRead(tool, path, fileExt) - } - - // 如果文件可读,直接使用父类逻辑(更高效) - if (file.exists() && file.canRead()) { - return super.handleSpecialFileRead(tool, path, fileExt) - } - - AppLogger.d(TAG, "File not directly readable (permission restricted), trying Shell copy for: $path") - - // 创建临时文件用于中转 - val tempFile = File(context.cacheDir, "shell_copy_${System.currentTimeMillis()}.$fileExt") - - return try { - // 使用cat命令复制文件内容 - // 注意:使用cat而不是cp,因为cp可能保留权限属性导致仍然无法读取 - val copyResult = AndroidShellExecutor.executeShellCommand("cat '$path' > '${tempFile.absolutePath}'") - - if (!copyResult.success) { - AppLogger.w(TAG, "Shell copy failed: ${copyResult.stderr}") - // 复制失败,回退到父类逻辑(虽然很可能也失败,但能返回一致的错误信息) - return super.handleSpecialFileRead(tool, path, fileExt) - } - - // 检查临时文件是否有效 - if (!tempFile.exists() || tempFile.length() == 0L) { - AppLogger.w(TAG, "Temp file is empty or does not exist after copy") - return super.handleSpecialFileRead(tool, path, fileExt) - } - - // 使用临时文件路径调用父类处理逻辑 - val tempToolResult = super.handleSpecialFileRead(tool, tempFile.absolutePath, fileExt) - - // 如果处理成功,修正返回结果中的 path 为原始路径 - if (tempToolResult != null && tempToolResult.success) { - val resultData = tempToolResult.result - if (resultData is FileContentData) { - return tempToolResult.copy( - result = resultData.copy(path = path) - ) - } - } - - tempToolResult - - } catch (e: Exception) { - AppLogger.e(TAG, "Error in shell copy strategy", e) - super.handleSpecialFileRead(tool, path, fileExt) - } finally { - // 清理临时文件 - try { - if (tempFile.exists()) { - tempFile.delete() - } - } catch (e: Exception) { - AppLogger.e(TAG, "Failed to clean up temp file", e) - } - } - } - - /** Write content to a file */ - override suspend fun writeFile(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.writeFile(tool) - } - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - if (isSafEnvironment(environment)) { - return super.writeFile(tool) - } - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - val content = tool.parameters.find { it.name == "content" }?.value ?: "" - val append = tool.parameters.find { it.name == "append" }?.value?.toBoolean() ?: false - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.writeFile(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "write", - path = "", - successful = false, - details = "Path parameter is required" - ), - error = "Path parameter is required" - ) - } - - return try { - // 确保目标目录存在 - val directory = File(path).parent - if (directory != null) { - val mkdirResult = AndroidShellExecutor.executeShellCommand("mkdir -p '$directory'") - if (!mkdirResult.success) { - AppLogger.w(TAG, "Warning: Failed to create parent directory: ${mkdirResult.stderr}") - } - } - - // 直接使用echo命令写入内容 - // 对内容进行base64编码,避免特殊字符问题 - val contentBase64 = - android.util.Base64.encodeToString( - content.toByteArray(), - android.util.Base64.NO_WRAP - ) - - // 使用 base64 写入;大内容分块,失败后不重新提交已写入的数据。 - val redirectOperator = if (append) ">>" else ">" - val maxInlineBase64 = 32768 - val base64ChunkSize = 16384 // 4的倍数,保证base64解码边界正确 - val writeResult = - if (contentBase64.length <= maxInlineBase64) { - AndroidShellExecutor.executeShellCommand( - "echo '$contentBase64' | base64 -d $redirectOperator '$path'" - ) - } else { - var chunkSuccess = true - var firstChunk = true - var index = 0 - while (index < contentBase64.length) { - val end = (index + base64ChunkSize).coerceAtMost(contentBase64.length) - val chunk = contentBase64.substring(index, end) - val chunkRedirect = if (firstChunk) redirectOperator else ">>" - val chunkResult = - AndroidShellExecutor.executeShellCommand( - "echo '$chunk' | base64 -d $chunkRedirect '$path'" - ) - if (!chunkResult.success) { - AppLogger.e( - TAG, - "Failed to write base64 chunk: ${chunkResult.stderr}" - ) - chunkSuccess = false - break - } - firstChunk = false - index = end - } - if (chunkSuccess) { - AndroidShellExecutor.CommandResult(true, "", "", 0) - } else { - AndroidShellExecutor.CommandResult(false, "", "Failed to write base64 chunks") - } - } - - if (!writeResult.success) { - AppLogger.e(TAG, "Failed to write with base64 method: ${writeResult.stderr}") - return ToolResult( - toolName = tool.name, - success = false, - result = FileOperationData( - operation = if (append) "append" else "write", - path = path, - successful = false, - details = "Failed to write to file: ${writeResult.stderr}" - ), - error = "Failed to write to file: ${writeResult.stderr}" - ) - } - - // 验证写入是否成功 - val verifyResult = - AndroidShellExecutor.executeShellCommand( - "test -f '$path' && echo 'exists' || echo 'not exists'" - ) - if (verifyResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = if (append) "append" else "write", - path = path, - successful = false, - details = - "Write command completed but file does not exist. Possible permission issue." - ), - error = - "Write command completed but file does not exist. Possible permission issue." - ) - } - - // 检查文件大小确认内容被写入 - val sizeResult = - AndroidShellExecutor.executeShellCommand( - "stat -c %s '$path' 2>/dev/null || echo '0'" - ) - val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 - if (size == 0L && content.isNotEmpty()) { - // 文件存在但是大小为0,可能写入失败 - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = if (append) "append" else "write", - path = path, - successful = false, - details = - "File was created but appears to be empty. Possible write failure." - ), - error = "File was created but appears to be empty. Possible write failure." - ) - } - - val operation = if (append) "append" else "write" - val details = if (append) "Content appended to $path" else "Content written to $path" - - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = operation, - path = path, - successful = true, - details = details - ), - error = "" - ) - } catch (e: Exception) { - AppLogger.e(TAG, "Error writing to file", e) - - // 提供更具体的错误信息 - val errorMessage = - when { - e is InterruptedException || - e.message?.contains("interrupted", ignoreCase = true) == true -> - "ADB connection interrupted, possibly due to network instability. Please check ADB connection and retry. Error details: ${e.message}" - e is java.net.SocketException || - e.message?.contains("socket", ignoreCase = true) == true -> - "ADB network connection exception, please check if device is still connected and retry. Error details: ${e.message}" - e is java.io.IOException -> "File IO error: ${e.message}. Please check if the file path has write permission." - e.message?.contains("permission", ignoreCase = true) == true -> - "Permission denied, cannot write to file: ${e.message}. Please check if the app has appropriate permissions." - else -> "Error writing to file: ${e.message}" - } - - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = if (append) "append" else "write", - path = path, - successful = false, - details = errorMessage - ), - error = errorMessage - ) - } - } - - /** Delete a file or directory */ - override suspend fun deleteFile(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.deleteFile(tool) - } - - if (isSafEnvironment(environment)) { - return super.deleteFile(tool) - } - - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.deleteFile(tool) - } - val recursive = tool.parameters.find { it.name == "recursive" }?.value?.toBoolean() ?: false - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "delete", - path = "", - successful = false, - details = "Path parameter is required" - ), - error = "Path parameter is required" - ) - } - - - return try { - val quotedPath = shQuote(path) - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -e $quotedPath && echo 'exists' || echo 'missing'" - ) - if (existsResult.stdout.trim() != "exists") { - ToolProgressBus.update(tool.name, 1f, "Delete failed") - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "delete", - path = path, - successful = false, - details = "File or directory does not exist: $path" - ), - error = "File or directory does not exist: $path" - ) - } - - val typeResult = - AndroidShellExecutor.executeShellCommand( - "if test -d $quotedPath; then echo 'directory'; elif test -f $quotedPath; then echo 'file'; else echo 'other'; fi" - ) - val isDirectory = typeResult.stdout.trim() == "directory" - - ToolProgressBus.update( - tool.name, - 0.1f, - if (isDirectory) "Deleting directory..." else "Deleting file..." - ) - - val deleteCommand = - if (recursive) "rm -rf $quotedPath" else if (isDirectory) "rmdir $quotedPath" else "rm -f $quotedPath" - val result = AndroidShellExecutor.executeShellCommand(deleteCommand) - - if (result.success && isDirectory && recursive) { - ToolProgressBus.update(tool.name, 0.85f, "Finalizing directory deletion...") - AndroidShellExecutor.executeShellCommand("rmdir $quotedPath") - } - - val verifyDeletedResult = - AndroidShellExecutor.executeShellCommand( - "test -e $quotedPath && echo 'exists' || echo 'missing'" - ) - val deleted = verifyDeletedResult.stdout.trim() != "exists" - - if (result.success && deleted) { - ToolProgressBus.update(tool.name, 1f, "Delete completed") - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "delete", - path = path, - successful = true, - details = "Successfully deleted $path" - ), - error = "" - ) - } else { - val errorMessage = - when { - !result.success && result.stderr.isNotBlank() -> - "Failed to delete: ${result.stderr}" - !deleted -> "Failed to delete: target still exists after delete command" - else -> "Failed to delete: unknown error" - } - ToolProgressBus.update(tool.name, 1f, "Delete failed") - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "delete", - path = path, - successful = false, - details = errorMessage - ), - error = errorMessage - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error deleting file/directory", e) - ToolProgressBus.update(tool.name, 1f, "Delete failed") - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "delete", - path = path, - successful = false, - details = "Error deleting file/directory: ${e.message}" - ), - error = "Error deleting file/directory: ${e.message}" - ) - } - } - - /** Check if a file or directory exists */ - override suspend fun fileExists(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.fileExists(tool) - } - - if (isSafEnvironment(environment)) { - return super.fileExists(tool) - } - - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.fileExists(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Path parameter is required" - ) - } - - return try { - // Check if the path exists - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -e '$path' && echo 'exists' || echo 'not exists'" - ) - val exists = existsResult.success && existsResult.stdout.trim() == "exists" - - if (!exists) { - // If it doesn't exist, return a simple FileExistsData with - // exists=false - return ToolResult( - toolName = tool.name, - success = true, - result = FileExistsData(path = path, exists = false), - error = "" - ) - } - - // If it exists, check if it's a directory - val isDirResult = - AndroidShellExecutor.executeShellCommand( - "test -d '$path' && echo 'true' || echo 'false'" - ) - val isDirectory = isDirResult.success && isDirResult.stdout.trim() == "true" - - // Get the size - val sizeResult = - AndroidShellExecutor.executeShellCommand( - "stat -c %s '$path' 2>/dev/null || echo '0'" - ) - val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 - - return ToolResult( - toolName = tool.name, - success = true, - result = - FileExistsData( - path = path, - exists = true, - isDirectory = isDirectory, - size = size - ), - error = "" - ) - } catch (e: Exception) { - AppLogger.e(TAG, "Error checking file existence", e) - return ToolResult( - toolName = tool.name, - success = false, - result = - FileExistsData( - path = path, - exists = false, - isDirectory = false, - size = 0 - ), - error = "Error checking file existence: ${e.message}" - ) - } - } - - /** Move or rename a file or directory */ - override suspend fun moveFile(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.moveFile(tool) - } - val sourcePath = tool.parameters.find { it.name == "source" }?.value ?: "" - val destPath = tool.parameters.find { it.name == "destination" }?.value ?: "" - if (isSafEnvironment(environment)) { - return super.moveFile(tool) - } - PathValidator.validateAndroidPath(sourcePath, tool.name)?.let { return it } - PathValidator.validateAndroidPath(destPath, tool.name)?.let { return it } - - // 如果源文件或目标文件在Operit内部存储,使用super的高权限方法 - if (isOperitInternalPath(sourcePath) || isOperitInternalPath(destPath)) { - return super.moveFile(tool) - } - PathValidator.validateAndroidPath(destPath, tool.name, "destination")?.let { return it } - - if (sourcePath.isBlank() || destPath.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "move", - path = sourcePath, - successful = false, - details = "Source and destination parameters are required" - ), - error = "Source and destination parameters are required" - ) - } - - - return try { - val result = AndroidShellExecutor.executeShellCommand("mv '$sourcePath' '$destPath'") - - if (result.success) { - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "move", - path = sourcePath, - successful = true, - details = "Successfully moved $sourcePath to $destPath" - ), - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "move", - path = sourcePath, - successful = false, - details = "Failed to move file: ${result.stderr}" - ), - error = "Failed to move file: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error moving file", e) - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "move", - path = sourcePath, - successful = false, - details = "Error moving file: ${e.message}" - ), - error = "Error moving file: ${e.message}" - ) - } - } - - /** Copy a file or directory */ - override suspend fun copyFile(tool: AITool): ToolResult { - // 检查是否是 Linux 环境或跨环境操作 - val environment = tool.parameters.find { it.name == "environment" }?.value - val sourceEnvironment = tool.parameters.find { it.name == "source_environment" }?.value - val destEnvironment = tool.parameters.find { it.name == "dest_environment" }?.value - - // 确定源和目标环境 - val srcEnv = sourceEnvironment ?: environment ?: "android" - val dstEnv = destEnvironment ?: environment ?: "android" - - // 如果是 Linux 环境或跨环境操作,委托给父类处理 - if (srcEnv.lowercase() == "linux" || dstEnv.lowercase() == "linux") { - return super.copyFile(tool) - } - - val sourcePath = tool.parameters.find { it.name == "source" }?.value ?: "" - val destPath = tool.parameters.find { it.name == "destination" }?.value ?: "" - val recursive = tool.parameters.find { it.name == "recursive" }?.value?.toBoolean() ?: true - if (sourcePath.startsWith("content://", ignoreCase = true) || destPath.startsWith("content://", ignoreCase = true)) { - return super.copyFile(tool) - } - PathValidator.validateAndroidPath(sourcePath, tool.name, "source")?.let { return it } - PathValidator.validateAndroidPath(destPath, tool.name, "destination")?.let { return it } - - // 如果源文件或目标文件在Operit内部存储,使用super的高权限方法 - if (isOperitInternalPath(sourcePath) || isOperitInternalPath(destPath)) { - return super.copyFile(tool) - } - - if (sourcePath.isBlank() || destPath.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "copy", - path = sourcePath, - successful = false, - details = "Source and destination parameters are required" - ), - error = "Source and destination parameters are required" - ) - } - - return try { - // 首先检查源路径是否存在 - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -e '$sourcePath' && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "copy", - path = sourcePath, - successful = false, - details = "Source path does not exist: $sourcePath" - ), - error = "Source path does not exist: $sourcePath" - ) - } - - // 检查是否为目录 - val isDirResult = - AndroidShellExecutor.executeShellCommand( - "test -d '$sourcePath' && echo 'true' || echo 'false'" - ) - val isDirectory = isDirResult.stdout.trim() == "true" - - // 确保目标父目录存在 - val destParentDir = destPath.substringBeforeLast('/') - if (destParentDir.isNotEmpty()) { - AndroidShellExecutor.executeShellCommand("mkdir -p '$destParentDir'") - } - - // 根据是否为目录选择不同的复制命令 - val copyCommand = - if (isDirectory && recursive) { - "cp -r '$sourcePath' '$destPath'" - } else if (!isDirectory) { - "cp '$sourcePath' '$destPath'" - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "copy", - path = sourcePath, - successful = false, - details = - "Cannot copy directory without recursive flag" - ), - error = "Cannot copy directory without recursive flag" - ) - } - - val result = AndroidShellExecutor.executeShellCommand(copyCommand) - - if (result.success) { - // 验证复制是否成功 - val verifyResult = - AndroidShellExecutor.executeShellCommand( - "test -e '$destPath' && echo 'exists' || echo 'not exists'" - ) - if (verifyResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "copy", - path = sourcePath, - successful = false, - details = - "Copy command completed but destination does not exist" - ), - error = "Copy command completed but destination does not exist" - ) - } - - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "copy", - path = sourcePath, - successful = true, - details = - "Successfully copied ${if (isDirectory) "directory" else "file"} $sourcePath to $destPath" - ), - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "copy", - path = sourcePath, - successful = false, - details = "Failed to copy: ${result.stderr}" - ), - error = "Failed to copy: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error copying file/directory", e) - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "copy", - path = sourcePath, - successful = false, - details = "Error copying file/directory: ${e.message}" - ), - error = "Error copying file/directory: ${e.message}" - ) - } - } - - /** Create a directory */ - override suspend fun makeDirectory(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.makeDirectory(tool) - } - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - if (isSafEnvironment(environment)) { - return super.makeDirectory(tool) - } - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.makeDirectory(tool) - } - val createParents = - tool.parameters.find { it.name == "create_parents" }?.value?.toBoolean() ?: false - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "mkdir", - path = "", - successful = false, - details = "Path parameter is required" - ), - error = "Path parameter is required" - ) - } - - return try { - // 首先检查目录是否已存在 - val checkDirResult = - AndroidShellExecutor.executeShellCommand( - "test -d '$path' && echo 'exists' || echo 'not exists'" - ) - - if (checkDirResult.success && checkDirResult.stdout.trim() == "exists") { - // 目录已存在,返回成功 - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "mkdir", - path = path, - successful = true, - details = "Directory already exists: $path" - ), - error = "" - ) - } - - val mkdirCommand = if (createParents) "mkdir -p '$path'" else "mkdir '$path'" - val result = AndroidShellExecutor.executeShellCommand(mkdirCommand) - - if (result.success) { - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "mkdir", - path = path, - successful = true, - details = "Successfully created directory $path" - ), - error = "" - ) - } else { - // 创建失败后再次检查是否已存在(可能在执行过程中被创建) - val recheckDirResult = - AndroidShellExecutor.executeShellCommand( - "test -d '$path' && echo 'exists' || echo 'not exists'" - ) - - if (recheckDirResult.success && recheckDirResult.stdout.trim() == "exists") { - // 目录已存在,返回成功 - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "mkdir", - path = path, - successful = true, - details = "Directory already exists: $path" - ), - error = "" - ) - } - - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "mkdir", - path = path, - successful = false, - details = "Failed to create directory: ${result.stderr}" - ), - error = "Failed to create directory: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error creating directory", e) - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "mkdir", - path = path, - successful = false, - details = "Error creating directory: ${e.message}" - ), - error = "Error creating directory: ${e.message}" - ) - } - } - - /** Search for files matching a pattern */ - override suspend fun findFiles(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.findFiles(tool) - } - - if (isSafEnvironment(environment)) { - return super.findFiles(tool) - } - - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - val pattern = tool.parameters.find { it.name == "pattern" }?.value ?: "" - - if (isOperitInternalPath(path)) { - return super.findFiles(tool) - } - - if (path.isBlank() || pattern.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FindFilesResultData( - path = path, - pattern = pattern, - files = emptyList() - ), - error = "Path and pattern parameters are required" - ) - } - - return try { - ToolProgressBus.update(tool.name, 0.02f, "Searching (device)...") - // Add options for different search modes - val usePathPattern = - tool.parameters.find { it.name == "use_path_pattern" }?.value?.toBoolean() - ?: false - val caseInsensitive = - tool.parameters.find { it.name == "case_insensitive" }?.value?.toBoolean() - ?: false - - val isFileResult = - AndroidShellExecutor.executeShellCommand( - "test -f ${shQuote(path)} && echo file || echo not_file" - ) - if (isFileResult.success && isFileResult.stdout.trim() == "file") { - val fileName = path.substringAfterLast('/') - val testString = if (usePathPattern) path else fileName - val regex = globToRegex(pattern, caseInsensitive) - val files = if (regex.matches(testString)) listOf(path) else emptyList() - - ToolProgressBus.update(tool.name, 1f, "Search completed, found ${files.size}") - - return ToolResult( - toolName = tool.name, - success = true, - result = FindFilesResultData(path = path, pattern = pattern, files = files), - error = "" - ) - } - - // Add depth control parameter (default to -1 for unlimited depth/fully - // recursive) - val maxDepth = - tool.parameters.find { it.name == "max_depth" }?.value?.toIntOrNull() ?: -1 - - // Determine which search option to use - val searchOption = - if (usePathPattern) { - if (caseInsensitive) "-ipath" else "-path" - } else { - if (caseInsensitive) "-iname" else "-name" - } - - // Properly escape the pattern if quotes are required - val escapedPattern = pattern.replace("'", "'\\''") - val patternForCommand = "'$escapedPattern'" - - // Build the command with depth control if specified - val depthOption = if (maxDepth >= 0) "-maxdepth $maxDepth" else "" - val command = - "find '${if(path.endsWith("/")) path else "$path/"}' $depthOption $searchOption $patternForCommand" - - val files = mutableListOf() - val foundCount = AtomicInteger(0) - val progressFloor = AtomicInteger(2) - val stderrBuilder = StringBuilder() - - val process = AndroidShellExecutor.startShellProcess(command) - try { - val exitCode = coroutineScope { - val stdoutJob = launch { - process.stdout.collect { line -> - val v = line.trim() - if (v.isNotEmpty()) { - files.add(v) - val found = foundCount.incrementAndGet() - val p = (smoothProgress(found, 250f) * 100).toInt().coerceIn(0, 99) - updateProgressFloor(progressFloor, p) - if (found % 20 == 0) { - ToolProgressBus.update( - tool.name, - progressFloor.get() / 100f, - "Searching... found $found" - ) - } - } - } - } - val stderrJob = launch { - process.stderr.collect { line -> - if (line.isNotBlank()) { - stderrBuilder.appendLine(line) - } - } - } - val tickerJob = launch { - while (isActive && process.isAlive) { - delay(500) - val current = progressFloor.get() - if (current < 95) { - progressFloor.compareAndSet(current, current + 1) - ToolProgressBus.update( - tool.name, - progressFloor.get() / 100f, - "Searching... found ${foundCount.get()}" - ) - } - } - } - - val code = process.waitFor() - stdoutJob.cancelAndJoin() - stderrJob.cancelAndJoin() - tickerJob.cancelAndJoin() - code - } - - if (exitCode != 0) { - val err = stderrBuilder.toString().trim() - return ToolResult( - toolName = tool.name, - success = false, - result = FindFilesResultData(path = path, pattern = pattern, files = emptyList()), - error = if (err.isNotBlank()) err else "find command failed with exitCode=$exitCode" - ) - } - } finally { - if (process.isAlive) { - process.destroy() - } - } - - ToolProgressBus.update(tool.name, 1f, "Search completed, found ${files.size}") - - return ToolResult( - toolName = tool.name, - success = true, - result = FindFilesResultData(path = path, pattern = pattern, files = files), - error = "" - ) - } catch (e: Exception) { - AppLogger.e(TAG, "Error searching for files", e) - ToolProgressBus.update(tool.name, 1f, "Search failed") - return ToolResult( - toolName = tool.name, - success = false, - result = - FindFilesResultData( - path = path, - pattern = pattern, - files = emptyList() - ), - error = "Error searching for files: ${e.message}" - ) - } - } - - /** Get file information */ - override suspend fun fileInfo(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.fileInfo(tool) - } - - if (isSafEnvironment(environment)) { - return super.fileInfo(tool) - } - - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - // 如果是Operit内部存储路径,使用super的高权限方法 - if (isOperitInternalPath(path)) { - return super.fileInfo(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileInfoData( - path = "", - exists = false, - fileType = "", - size = 0, - permissions = "", - owner = "", - group = "", - lastModified = "", - rawStatOutput = "" - ), - error = "Path parameter is required" - ) - } - - return try { - // Check if file exists - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -e '$path' && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileInfoData( - path = path, - exists = false, - fileType = "", - size = 0, - permissions = "", - owner = "", - group = "", - lastModified = "", - rawStatOutput = "" - ), - error = "File or directory does not exist: $path" - ) - } - - // Get file details using stat - val statResult = AndroidShellExecutor.executeShellCommand("stat '$path'") - - if (statResult.success) { - // Get file type - val fileTypeResult = - AndroidShellExecutor.executeShellCommand( - "test -d '$path' && echo 'directory' || (test -f '$path' && echo 'file' || echo 'other')" - ) - val fileType = fileTypeResult.stdout.trim() - - // Get file size - val sizeResult = - AndroidShellExecutor.executeShellCommand( - "stat -c %s '$path' 2>/dev/null || echo '0'" - ) - val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 - - // Get file permissions - val permissionsResult = - AndroidShellExecutor.executeShellCommand( - "stat -c %A '$path' 2>/dev/null || echo ''" - ) - val permissions = permissionsResult.stdout.trim() - - // Get owner and group - val ownerResult = - AndroidShellExecutor.executeShellCommand( - "stat -c %U '$path' 2>/dev/null || echo ''" - ) - val owner = ownerResult.stdout.trim() - - val groupResult = - AndroidShellExecutor.executeShellCommand( - "stat -c %G '$path' 2>/dev/null || echo ''" - ) - val group = groupResult.stdout.trim() - - // Get last modified time - val modifiedResult = - AndroidShellExecutor.executeShellCommand( - "stat -c %Y '$path' 2>/dev/null || echo ''" - ) - val lastModifiedEpochSec = modifiedResult.stdout.trim().toLongOrNull() - val lastModified = - if (lastModifiedEpochSec != null && lastModifiedEpochSec > 0) { - SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US) - .format(Date(lastModifiedEpochSec * 1000L)) - } else { - "" - } - - return ToolResult( - toolName = tool.name, - success = true, - result = - FileInfoData( - path = path, - exists = true, - fileType = fileType, - size = size, - permissions = permissions, - owner = owner, - group = group, - lastModified = lastModified, - rawStatOutput = statResult.stdout - ), - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileInfoData( - path = path, - exists = true, - fileType = "", - size = 0, - permissions = "", - owner = "", - group = "", - lastModified = "", - rawStatOutput = "" - ), - error = "Failed to get file information: ${statResult.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error getting file information", e) - return ToolResult( - toolName = tool.name, - success = false, - result = - FileInfoData( - path = path, - exists = false, - fileType = "", - size = 0, - permissions = "", - owner = "", - group = "", - lastModified = "", - rawStatOutput = "" - ), - error = "Error getting file information: ${e.message}" - ) - } - } - - /** Zip files or directories */ - override suspend fun zipFiles(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.zipFiles(tool) - } - val sourcePath = tool.parameters.find { it.name == "source" }?.value ?: "" - val zipPath = tool.parameters.find { it.name == "destination" }?.value ?: "" - val includeRootDirectoryParameter = tool.parameters.find { it.name == "include_root_directory" } - val includeRootDirectory = - if (includeRootDirectoryParameter == null) { - true - } else { - includeRootDirectoryParameter.value.toBooleanStrictOrNull() - ?: return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "include_root_directory must be true or false" - ) - } - PathValidator.validateAndroidPath(sourcePath, tool.name, "source")?.let { return it } - PathValidator.validateAndroidPath(zipPath, tool.name, "destination")?.let { return it } - - if (isOperitInternalPath(sourcePath) || isOperitInternalPath(zipPath)) { - return super.zipFiles(tool) - } - - if (sourcePath.isBlank() || zipPath.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Source and destination parameters are required" - ) - } - - return try { - val archiveSourcePath = - sourcePath.trimEnd('/').let { - if (it.isEmpty() && sourcePath.startsWith("/")) "/" else it - } - // First, check if the source path exists - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -e ${shQuote(archiveSourcePath)} && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Source file or directory does not exist: $sourcePath" - ) - } - - // Check if source is a directory - val isDirResult = - AndroidShellExecutor.executeShellCommand( - "test -d ${shQuote(archiveSourcePath)} && echo 'true' || echo 'false'" - ) - val isDirectory = isDirResult.stdout.trim() == "true" - - // Create parent directory for zip file if needed - val zipDir = File(zipPath).parent - if (zipDir != null) { - AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(zipDir)}") - } - - // Use Java's ZipOutputStream to create the zip file - // We'll use ADB to copy files to/from the device and process locally - val sourceFile = File(archiveSourcePath) - - // Initialize buffer for file copy - val buffer = ByteArray(1024) - - // Create temporary file for processing - using external files directory for - // better - // permissions - val tempDir = context.getExternalFilesDir(null) ?: context.cacheDir - val tempSourceFile = File(tempDir, "temp_source_${System.currentTimeMillis()}") - val tempZipFile = File(tempDir, "temp_zip_${System.currentTimeMillis()}.zip") - - try { - // Make sure the temp directory exists - tempDir.mkdirs() - - if (isDirectory) { - // For directories, we need to list all files and add them - // to the zip - val listResult = - AndroidShellExecutor.executeShellCommand("find ${shQuote(archiveSourcePath)} -type f") - val fileList = listResult.stdout.trim().split("\n").filter { it.isNotEmpty() } - - // Create ZIP output stream - val fos = FileOutputStream(tempZipFile) - val zos = ZipOutputStream(BufferedOutputStream(fos)) - - try { - for (filePath in fileList) { - // Get the file path relative to the source - // directory - val pathInsideSource = - if (archiveSourcePath == "/") { - filePath.removePrefix("/") - } else { - filePath.removePrefix("$archiveSourcePath/") - } - val relativePath = - if (includeRootDirectory && sourceFile.name.isNotEmpty()) { - "${sourceFile.name}/$pathInsideSource" - } else { - pathInsideSource - } - - // Copy the file from device to temp file - val pullResult = - AndroidShellExecutor.executeShellCommand( - "cat ${shQuote(filePath)} > ${shQuote(tempSourceFile.absolutePath)}" - ) - if (!pullResult.success) { - continue // Skip this file if we - // can't pull it - } - - // Add the file to the ZIP - val fis = FileInputStream(tempSourceFile) - val bis = BufferedInputStream(fis) - - try { - // Add ZIP entry - val entry = ZipEntry(relativePath) - zos.putNextEntry(entry) - - // Write file content to ZIP - var len: Int - while (bis.read(buffer).also { len = it } > 0) { - zos.write(buffer, 0, len) - } - - zos.closeEntry() - } finally { - bis.close() - fis.close() - tempSourceFile.delete() - } - } - } finally { - zos.close() - fos.close() - } - } else { - // For a single file, simpler process - // Copy the file from device to temp file - val pullResult = - AndroidShellExecutor.executeShellCommand( - "cat ${shQuote(archiveSourcePath)} > ${shQuote(tempSourceFile.absolutePath)}" - ) - if (!pullResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to read source file: ${pullResult.stderr}" - ) - } - - // Create zip file with single entry - val fos = FileOutputStream(tempZipFile) - val zos = ZipOutputStream(BufferedOutputStream(fos)) - - try { - val fis = FileInputStream(tempSourceFile) - val bis = BufferedInputStream(fis) - - try { - // Add ZIP entry - val entry = ZipEntry(sourceFile.name) - zos.putNextEntry(entry) - - // Write file content to ZIP - var len: Int - while (bis.read(buffer).also { len = it } > 0) { - zos.write(buffer, 0, len) - } - - zos.closeEntry() - } finally { - bis.close() - fis.close() - } - } finally { - zos.close() - fos.close() - } - } - - // Log information about the temp ZIP file - AppLogger.d( - TAG, - "Temp ZIP file created at: ${tempZipFile.absolutePath}, size: ${tempZipFile.length()} bytes" - ) - - // Push the ZIP file to the destination - val pushResult = - AndroidShellExecutor.executeShellCommand( - "cat ${shQuote(tempZipFile.absolutePath)} > ${shQuote(zipPath)}" - ) - if (!pushResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to write ZIP file: ${pushResult.stderr}" - ) - } - - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "zip", - path = sourcePath, - successful = true, - details = "Successfully compressed $sourcePath to $zipPath" - ), - error = "" - ) - } finally { - // Clean up temporary files - tempSourceFile.delete() - tempZipFile.delete() - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error compressing files", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error compressing files: ${e.message}" - ) - } - } - - /** Unzip a zip file */ - override suspend fun unzipFiles(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.unzipFiles(tool) - } - val zipPath = tool.parameters.find { it.name == "source" }?.value ?: "" - val destPath = tool.parameters.find { it.name == "destination" }?.value ?: "" - PathValidator.validateAndroidPath(zipPath, tool.name, "source")?.let { return it } - PathValidator.validateAndroidPath(destPath, tool.name, "destination")?.let { return it } - - if (isOperitInternalPath(zipPath) || isOperitInternalPath(destPath)) { - return super.unzipFiles(tool) - } - - val actualZipPath = zipPath - val actualDestPath = destPath - - if (zipPath.isBlank() || destPath.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Source and destination parameters are required" - ) - } - - return try { - ToolProgressBus.update(tool.name, -1f, "Unzipping...") - // Check if the zip file exists - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -f ${shQuote(zipPath)} && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Zip file does not exist: $zipPath" - ) - } - - // Create destination directory if it doesn't exist - AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(destPath)};") - - val deviceUnzipCommands = - listOf( - "unzip -o ${shQuote(zipPath)} -d ${shQuote(destPath)}", - "toybox unzip -o ${shQuote(zipPath)} -d ${shQuote(destPath)}", - "busybox unzip -o ${shQuote(zipPath)} -d ${shQuote(destPath)}" - ) - - for (cmd in deviceUnzipCommands) { - try { - ToolProgressBus.update(tool.name, 0.02f, "Unzipping (device)...") - val extractedCount = AtomicInteger(0) - val progressFloor = AtomicInteger(2) - val stderrBuilder = StringBuilder() - - val process = AndroidShellExecutor.startShellProcess("$cmd;") - try { - val exitCode = coroutineScope { - val stdoutJob = launch { - process.stdout.collect { line -> - val t = line.trimStart() - val isProgressLine = - t.startsWith("inflating:") || - t.startsWith("extracting:") || - t.startsWith("creating:") || - t.startsWith(" inflating:") || - t.startsWith(" extracting:") - - if (isProgressLine) { - val extracted = extractedCount.incrementAndGet() - val p = (smoothProgress(extracted, 120f) * 100).toInt().coerceIn(0, 99) - updateProgressFloor(progressFloor, p) - if (extracted % 10 == 0) { - ToolProgressBus.update( - tool.name, - progressFloor.get() / 100f, - "Unzipping... extracted $extracted" - ) - } - } - } - } - val stderrJob = launch { - process.stderr.collect { line -> - if (line.isNotBlank()) { - stderrBuilder.appendLine(line) - } - - val t = line.trimStart() - val isProgressLine = - t.startsWith("inflating:") || - t.startsWith("extracting:") || - t.startsWith("creating:") || - t.startsWith(" inflating:") || - t.startsWith(" extracting:") - - if (isProgressLine) { - val extracted = extractedCount.incrementAndGet() - val p = (smoothProgress(extracted, 120f) * 100).toInt().coerceIn(0, 99) - updateProgressFloor(progressFloor, p) - if (extracted % 10 == 0) { - ToolProgressBus.update( - tool.name, - progressFloor.get() / 100f, - "Unzipping... extracted $extracted" - ) - } - } - } - } - val tickerJob = launch { - while (isActive && process.isAlive) { - delay(500) - val current = progressFloor.get() - if (current < 95) { - progressFloor.compareAndSet(current, current + 1) - ToolProgressBus.update( - tool.name, - progressFloor.get() / 100f, - "Unzipping..." - ) - } - } - } - - val code = process.waitFor() - stdoutJob.cancelAndJoin() - stderrJob.cancelAndJoin() - tickerJob.cancelAndJoin() - code - } - - if (exitCode == 0) { - ToolProgressBus.update(tool.name, 1f, "Unzip completed") - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "unzip", - path = zipPath, - successful = true, - details = "Successfully extracted $zipPath to $destPath" - ), - error = "" - ) - } - } finally { - if (process.isAlive) { - process.destroy() - } - } - } catch (e: Exception) { - AppLogger.w(TAG, "Device-side unzip failed for cmd: $cmd", e) - } - } - - // Create temporary files for processing - using external files directory - // for better - // permissions - val tempDir = context.getExternalFilesDir(null) ?: context.cacheDir - val tempZipFile = File(tempDir, "temp_zip_${System.currentTimeMillis()}.zip") - - try { - // Make sure the temp directory exists - tempDir.mkdirs() - - // Copy the zip file from device to temp file - val pullResult = - AndroidShellExecutor.executeShellCommand( - "cat ${shQuote(zipPath)} > ${shQuote(tempZipFile.absolutePath)}" - ) - if (!pullResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to read zip file: ${pullResult.stderr}" - ) - } - - // Log information about the temp ZIP file - AppLogger.d( - TAG, - "Temp ZIP file loaded at: ${tempZipFile.absolutePath}, size: ${tempZipFile.length()} bytes" - ) - - val totalEntries = try { - ZipFile(tempZipFile).use { it.size() } - } catch (_: Exception) { - null - } - var processedEntries = 0 - - // Extract files using ZipInputStream - val buffer = ByteArray(64 * 1024) - val zipInputStream = - ZipInputStream(BufferedInputStream(FileInputStream(tempZipFile))) - - try { - var zipEntry: ZipEntry? = zipInputStream.nextEntry - while (zipEntry != null) { - val fileName = zipEntry.name - if (fileName.startsWith("/") || fileName.contains("..") || fileName.contains("\\")) { - zipInputStream.closeEntry() - zipEntry = zipInputStream.nextEntry - continue - } - - val newFile = File(tempDir, fileName) - - val newFileCanonical = newFile.canonicalPath - val tempDirCanonical = tempDir.canonicalPath + File.separator - if (!newFileCanonical.startsWith(tempDirCanonical)) { - zipInputStream.closeEntry() - zipEntry = zipInputStream.nextEntry - continue - } - - // Skip directories, but make sure they exist - if (zipEntry.isDirectory) { - newFile.mkdirs() - val dirPath = "$destPath/$fileName" - AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(dirPath)};") - zipInputStream.closeEntry() - zipEntry = zipInputStream.nextEntry - continue - } - - // Create parent directories if needed - val filePath = "$destPath/$fileName" - val parentDirPath = File(filePath).parent - if (parentDirPath != null) { - AndroidShellExecutor.executeShellCommand("mkdir -p ${shQuote(parentDirPath)};") - } - - newFile.parentFile?.mkdirs() - - // Extract file - val fileOutputStream = FileOutputStream(newFile) - - try { - var len: Int - while (zipInputStream.read(buffer).also { len = it } > 0) { - fileOutputStream.write(buffer, 0, len) - } - } finally { - fileOutputStream.close() - } - - // Copy the extracted file to device - val pushResult = - AndroidShellExecutor.executeShellCommand( - "cat ${shQuote(newFile.absolutePath)} > ${shQuote(filePath)}" - ) - if (!pushResult.success) { - AppLogger.w(TAG, "Failed to copy extracted file: $fileName to $filePath") - // Continue with next file - } - - // Clean up temp file - newFile.delete() - - zipInputStream.closeEntry() - processedEntries++ - val progress = - if (totalEntries != null && totalEntries > 0) { - (processedEntries.toFloat() / totalEntries.toFloat()).coerceIn(0f, 1f) - } else { - -1f - } - val msg = - if (totalEntries != null && totalEntries > 0) { - "Unzipping... ($processedEntries/$totalEntries)" - } else { - "Unzipping..." - } - ToolProgressBus.update(tool.name, progress, msg) - zipEntry = zipInputStream.nextEntry - } - } finally { - zipInputStream.close() - } - - ToolProgressBus.update(tool.name, 1f, "Unzip completed") - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "unzip", - path = zipPath, - successful = true, - details = "Successfully extracted $zipPath to $destPath" - ), - error = "" - ) - } finally { - tempZipFile.delete() - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error extracting zip file", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error extracting zip file: ${e.message}" - ) - } finally { - ToolProgressBus.clear() - } - } - - /** 打开文件 使用系统默认应用打开文件 */ - override suspend fun openFile(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.openFile(tool) - } - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - - if (isOperitInternalPath(path)) { - return super.openFile(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "open", - path = "", - successful = false, - details = "Must provide path parameter" - ), - error = "Must provide path parameter" - ) - } - - return try { - // 首先检查文件是否存在 - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -f '$path' && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "open", - path = path, - successful = false, - details = "File does not exist: $path" - ), - error = "File does not exist: $path" - ) - } - - // 获取文件MIME类型 - val mimeTypeResult = - AndroidShellExecutor.executeShellCommand("file --mime-type -b '$path'") - val mimeType = - if (mimeTypeResult.success) mimeTypeResult.stdout.trim() - else "application/octet-stream" - - // 使用Android intent打开文件 - val command = "am start -a android.intent.action.VIEW -d 'file://$path' -t '$mimeType'" - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success) { - return ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "open", - path = path, - successful = true, - details = "Opened file with system app: $path" - ), - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "open", - path = path, - successful = false, - details = "Failed to open file: ${result.stderr}" - ), - error = "Failed to open file: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error opening file", e) - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "open", - path = path, - successful = false, - details = "Error opening file: ${e.message}" - ), - error = "Error opening file: ${e.message}" - ) - } - } - - /** 分享文件 调用系统分享功能 */ - override suspend fun shareFile(tool: AITool): ToolResult { - val environment = tool.parameters.find { it.name == "environment" }?.value - if (environment == "linux") { - return super.shareFile(tool) - } - val path = tool.parameters.find { it.name == "path" }?.value ?: "" - PathValidator.validateAndroidPath(path, tool.name)?.let { return it } - val title = tool.parameters.find { it.name == "title" }?.value ?: "Share File" - - if (isOperitInternalPath(path)) { - return super.shareFile(tool) - } - - if (path.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "share", - path = "", - successful = false, - details = "Must provide path parameter" - ), - error = "Must provide path parameter" - ) - } - - return try { - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -f ${shQuote(path)} && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "share", - path = path, - successful = false, - details = "File does not exist: $path" - ), - error = "File does not exist: $path" - ) - } - - val stagingRoot = (context.getExternalFilesDir(null) ?: context.cacheDir) - val stagingDir = File(stagingRoot, "share_tmp") - if (!stagingDir.exists()) { - stagingDir.mkdirs() - } - - val sourceName = File(path).name.ifBlank { "shared_file" } - val stagedFile = File(stagingDir, "${System.currentTimeMillis()}_$sourceName") - val copyResult = - AndroidShellExecutor.executeShellCommand( - "cat ${shQuote(path)} > ${shQuote(stagedFile.absolutePath)}" - ) - - if (!copyResult.success || !stagedFile.exists()) { - return ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "share", - path = path, - successful = false, - details = "Failed to prepare file for sharing: ${copyResult.stderr}" - ), - error = "Failed to prepare file for sharing: ${copyResult.stderr}" - ) - } - - val extension = stagedFile.extension.lowercase(Locale.US) - val mimeType = - if (extension.isNotEmpty()) { - MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) - ?: "application/octet-stream" - } else { - "application/octet-stream" - } - - val authority = "${context.packageName}.fileprovider" - val contentUri = FileProvider.getUriForFile(context, authority, stagedFile) - val shareIntent = - Intent(Intent.ACTION_SEND).apply { - type = mimeType - putExtra(Intent.EXTRA_STREAM, contentUri) - putExtra(Intent.EXTRA_SUBJECT, title) - clipData = - ClipData.newUri( - context.contentResolver, - stagedFile.name, - contentUri - ) - addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - } - val chooserIntent = - Intent.createChooser(shareIntent, title).apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - } - context.startActivity(chooserIntent) - - ToolResult( - toolName = tool.name, - success = true, - result = - FileOperationData( - operation = "share", - path = path, - successful = true, - details = "Opened share interface, sharing file: $path" - ), - error = "" - ) - } catch (e: ActivityNotFoundException) { - AppLogger.e(TAG, "No activity found to handle sharing file: $path", e) - ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "share", - path = path, - successful = false, - details = "No application found to share this file type." - ), - error = "No application found to share this file type." - ) - } catch (e: Exception) { - AppLogger.e(TAG, "Error sharing file", e) - ToolResult( - toolName = tool.name, - success = false, - result = - FileOperationData( - operation = "share", - path = path, - successful = false, - details = "Error sharing file: ${e.message}" - ), - error = "Error sharing file: ${e.message}" - ) - } - } - - /** 下载文件 从网络URL下载文件到指定路径 */ - override suspend fun downloadFile(tool: AITool): ToolResult { - return super.downloadFile(tool) - } - - /** Write base64 encoded content to a binary file */ - -// if (path.isBlank()) { -// return ToolResult( -// toolName = tool.name, -// success = false, -// result = -// FileOperationData( -// operation = "write_binary", -// path = "", -// successful = false, -// details = "Path parameter is required" -// ), -// error = "Path parameter is required" -// ) -// } - -// return try { -// // Ensure parent directory exists -// val directory = File(path).parent -// if (directory != null) { -// AndroidShellExecutor.executeShellCommand("mkdir -p '$directory'") -// } - -// // Write content using echo and base64 decode -// val writeResult = -// AndroidShellExecutor.executeShellCommand( -// "echo '$base64Content' | base64 -d > '$path'" -// ) - -// if (!writeResult.success) { -// return ToolResult( -// toolName = tool.name, -// success = false, -// result = -// FileOperationData( -// operation = "write_binary", -// path = path, -// successful = false, -// details = "Failed to write binary file: ${writeResult.stderr}" -// ), -// error = "Failed to write binary file: ${writeResult.stderr}" -// ) -// } - -// // Verify write was successful -// val sizeResult = -// AndroidShellExecutor.executeShellCommand("stat -c %s '$path' 2>/dev/null || echo '0'") -// val size = sizeResult.stdout.trim().toLongOrNull() ?: 0 -// val originalSize = -// android.util.Base64.decode(base64Content, android.util.Base64.NO_WRAP).size - -// if (size.toLong() != originalSize.toLong()) { -// return ToolResult( -// toolName = tool.name, -// success = false, -// result = -// FileOperationData( -// operation = "write_binary", -// path = path, -// successful = false, -// details = "Write completed but file size mismatch. Expected: $originalSize, Got: $size. Possible write failure." -// ), -// error = "Write completed but file size mismatch. Expected: $originalSize, Got: $size. Possible write failure." -// ) -// } - -// return ToolResult( -// toolName = tool.name, -// success = true, -// result = -// FileOperationData( -// operation = "write_binary", -// path = path, -// successful = true, -// details = "Binary content written to $path" -// ), -// error = "" -// ) -// } catch (e: Exception) { -// AppLogger.e(TAG, "Error writing binary file", e) -// return ToolResult( -// toolName = tool.name, -// success = false, -// result = -// FileOperationData( -// operation = "write_binary", -// path = path, -// successful = false, -// details = "Error writing binary file: ${e.message}" -// ), -// error = "Error writing binary file: ${e.message}" -// ) -// } -// } -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerSystemOperationTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerSystemOperationTools.kt deleted file mode 100644 index 5450332bec..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerSystemOperationTools.kt +++ /dev/null @@ -1,527 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.debugger - -import android.content.Context -import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.AppOperationData -import com.ai.assistance.operit.core.tools.NotificationData -import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.SystemSettingData -import com.ai.assistance.operit.core.tools.defaultTool.accessbility.AccessibilitySystemOperationTools -import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor -import com.ai.assistance.operit.data.model.AITool -import com.ai.assistance.operit.data.model.ToolResult - -/** 调试级别的系统操作工具,继承无障碍版本, 并使用shell命令覆盖部分实现 */ -open class DebuggerSystemOperationTools(private val context: Context) : - AccessibilitySystemOperationTools(context) { - - private val TAG = "DebuggerSystemTools" - - override suspend fun modifySystemSetting(tool: AITool): ToolResult { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return super.modifySystemSetting(tool) - } - - val setting = tool.parameters.find { it.name == "setting" }?.value ?: "" - val value = tool.parameters.find { it.name == "value" }?.value ?: "" - val namespace = tool.parameters.find { it.name == "namespace" }?.value ?: "system" - - if (setting.isBlank() || value.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Must provide setting and value parameters" - ) - } - - val validNamespaces = listOf("system", "secure", "global") - if (!validNamespaces.contains(namespace)) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Namespace must be one of: ${validNamespaces.joinToString(", ")}" - ) - } - - return try { - val command = "settings put $namespace $setting $value" - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success) { - val resultData = - SystemSettingData(namespace = namespace, setting = setting, value = value) - - return ToolResult( - toolName = tool.name, - success = true, - result = resultData, - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to set setting: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error modifying system setting", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error modifying system setting: ${e.message}" - ) - } - } - - override suspend fun getSystemSetting(tool: AITool): ToolResult { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return super.getSystemSetting(tool) - } - - val setting = tool.parameters.find { it.name == "setting" }?.value ?: "" - val namespace = tool.parameters.find { it.name == "namespace" }?.value ?: "system" - - if (setting.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Must provide setting parameter" - ) - } - - val validNamespaces = listOf("system", "secure", "global") - if (!validNamespaces.contains(namespace)) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Namespace must be one of: ${validNamespaces.joinToString(", ")}" - ) - } - - return try { - val command = "settings get $namespace $setting" - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success) { - val resultData = - SystemSettingData( - namespace = namespace, - setting = setting, - value = result.stdout.trim() - ) - - return ToolResult( - toolName = tool.name, - success = true, - result = resultData, - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to get setting: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error getting system setting", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error getting system setting: ${e.message}" - ) - } - } - - override suspend fun installApp(tool: AITool): ToolResult { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return super.installApp(tool) - } - - val apkPath = tool.parameters.find { it.name == "path" }?.value ?: "" - - if (apkPath.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Must provide apk_path parameter" - ) - } - - if (DebuggerFileSystemTools.isOperitInternalPath(apkPath)) { - AppLogger.d( - TAG, - "installApp detected Operit internal path, delegating to AccessibilitySystemOperationTools" - ) - return super.installApp(tool) - } - - val existsResult = - AndroidShellExecutor.executeShellCommand( - "test -f $apkPath && echo 'exists' || echo 'not exists'" - ) - if (existsResult.stdout.trim() != "exists") { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "APK file does not exist: $apkPath" - ) - } - - return try { - val command = "pm install -r $apkPath" - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success && result.stdout.contains("Success")) { - val resultData = - AppOperationData( - operationType = "install", - packageName = apkPath, - success = true - ) - - return ToolResult( - toolName = tool.name, - success = true, - result = resultData, - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Installation failed: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error installing app", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error installing app: ${e.message}" - ) - } - } - - override suspend fun uninstallApp(tool: AITool): ToolResult { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return super.uninstallApp(tool) - } - - val packageName = tool.parameters.find { it.name == "package_name" }?.value ?: "" - val keepData = tool.parameters.find { it.name == "keep_data" }?.value?.toBoolean() ?: false - - if (packageName.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Must provide package_name parameter" - ) - } - - val checkCommand = "pm list packages | grep -c \"$packageName\"" - val checkResult = AndroidShellExecutor.executeShellCommand(checkCommand) - - if (checkResult.stdout.trim() == "0") { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "App not installed: $packageName" - ) - } - - return try { - val command = - if (keepData) { - "pm uninstall -k $packageName" - } else { - "pm uninstall $packageName" - } - - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success && result.stdout.contains("Success")) { - val details = if (keepData) "(keep data)" else "" - val resultData = - AppOperationData( - operationType = "uninstall", - packageName = packageName, - success = true, - details = details - ) - - return ToolResult( - toolName = tool.name, - success = true, - result = resultData, - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Uninstallation failed: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error uninstalling app", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error uninstalling app: ${e.message}" - ) - } - } - - override suspend fun startApp(tool: AITool): ToolResult { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return super.startApp(tool) - } - - val packageName = tool.parameters.find { it.name == "package_name" }?.value ?: "" - val activity = tool.parameters.find { it.name == "activity" }?.value ?: "" - - if (packageName.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Must provide package_name parameter" - ) - } - - return try { - val command: String - if (activity.isBlank()) { - // 使用 am start 命令而不是 monkey,避免修改系统设置(如屏幕旋转) - // 先获取应用的主 Activity,然后使用 -n 参数启动 - val resolveCmd = "cmd package resolve-activity --brief $packageName 2>/dev/null | tail -n 1" - val resolveResult = AndroidShellExecutor.executeShellCommand(resolveCmd) - - if (resolveResult.success && resolveResult.stdout.isNotBlank()) { - val output = resolveResult.stdout.trim() - // resolve-activity 返回格式可能是:package/activity 或只有 activity - // 也可能返回多行,最后一行是组件名 - val lines = output.lines().filter { it.isNotBlank() && !it.startsWith("name=") } - val mainActivity = lines.lastOrNull()?.trim() ?: output.trim() - - // 如果返回的是完整组件名(package/activity),直接使用 - command = if (mainActivity.contains('/')) { - "am start -n $mainActivity" - } else { - // 如果只返回了 Activity 名,拼接包名 - "am start -n $packageName/$mainActivity" - } - AppLogger.d(TAG, "Resolved main Activity: $mainActivity, using command: $command") - } else { - // 如果无法解析 Activity,返回错误 - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Cannot resolve app main Activity. Please provide activity parameter or ensure app is properly installed. Package: $packageName" - ) - } - } else { - command = "am start -n $packageName/$activity" - } - - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success) { - val details = if (activity.isNotBlank()) "Activity: $activity" else "" - val resultData = - AppOperationData( - operationType = "start", - packageName = packageName, - success = true, - details = details - ) - - return ToolResult( - toolName = tool.name, - success = true, - result = resultData, - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to start app: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error starting app", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error starting app: ${e.message}" - ) - } - } - - override suspend fun stopApp(tool: AITool): ToolResult { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return super.stopApp(tool) - } - - val packageName = tool.parameters.find { it.name == "package_name" }?.value ?: "" - - if (packageName.isBlank()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Must provide package_name parameter" - ) - } - - return try { - val command = "am force-stop $packageName" - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success) { - val resultData = - AppOperationData( - operationType = "stop", - packageName = packageName, - success = true - ) - - return ToolResult( - toolName = tool.name, - success = true, - result = resultData, - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to stop app: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error stopping app", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error stopping app: ${e.message}" - ) - } - } - - override suspend fun getNotifications(tool: AITool): ToolResult { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return super.getNotifications(tool) - } - - val limit = tool.parameters.find { it.name == "limit" }?.value?.toIntOrNull() ?: 10 - val includeOngoing = - tool.parameters.find { it.name == "include_ongoing" }?.value?.toBoolean() ?: false - - return try { - val command = - if (includeOngoing) { - "dumpsys notification --noredact | grep -E 'pkg=|text=' | head -${limit * 2}" - } else { - "dumpsys notification --noredact | grep -v 'ongoing' | grep -E 'pkg=|text=' | head -${limit * 2}" - } - - val result = AndroidShellExecutor.executeShellCommand(command) - - if (result.success) { - val lines = result.stdout.split("\n") - val notifications = mutableListOf() - - var currentPackage = "" - var currentText = "" - - for (line in lines) { - when { - line.contains("pkg=") -> { - if (currentPackage.isNotEmpty() && currentText.isNotEmpty()) { - notifications.add( - NotificationData.Notification( - packageName = currentPackage, - text = currentText, - timestamp = System.currentTimeMillis() - ) - ) - currentText = "" - } - - val pkgMatch = Regex("pkg=(\\S+)").find(line) - currentPackage = pkgMatch?.groupValues?.getOrNull(1) ?: "" - } - line.contains("text=") -> { - val textMatch = Regex("text=(.+)").find(line) - currentText = textMatch?.groupValues?.getOrNull(1) ?: "" - } - } - } - - if (currentPackage.isNotEmpty() && currentText.isNotEmpty()) { - notifications.add( - NotificationData.Notification( - packageName = currentPackage, - text = currentText, - timestamp = System.currentTimeMillis() - ) - ) - } - - val resultData = - NotificationData( - notifications = notifications, - timestamp = System.currentTimeMillis() - ) - - return ToolResult( - toolName = tool.name, - success = true, - result = resultData, - error = "" - ) - } else { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to get notifications: ${result.stderr}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error getting notifications", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error getting notifications: ${e.message}" - ) - } - } -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerUITools.kt deleted file mode 100644 index 46da0c842f..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/DebuggerUITools.kt +++ /dev/null @@ -1,1359 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.debugger - -import android.annotation.SuppressLint -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import java.io.File -import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.SimplifiedUINode -import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.UIActionResultData -import com.ai.assistance.operit.core.tools.UIPageResultData -import com.ai.assistance.operit.core.tools.defaultTool.accessbility.AccessibilityUITools -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardUITools -import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor -import com.ai.assistance.operit.core.tools.system.ShellIdentity -import com.ai.assistance.operit.data.model.AITool -import com.ai.assistance.operit.data.model.ToolResult -import java.io.StringReader -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.json.JSONObject -import org.xmlpull.v1.XmlPullParser -import org.xmlpull.v1.XmlPullParserFactory -import com.ai.assistance.operit.util.files.OperitPaths -import com.ai.assistance.operit.core.tools.system.uiautomator.UiAutomatorDumpGuard - -/** 调试级别的UI工具,通过Shell命令实现UI操作,继承无障碍版本 */ -open class DebuggerUITools(context: Context) : AccessibilityUITools(context) { - - companion object { - private const val TAG = "DebuggerUITools" - } - - protected open val uiShellIdentity: ShellIdentity? = null - - protected suspend fun executeUiShellCommand(command: String): AndroidShellExecutor.CommandResult { - // 读取页面和按元素点击共用入口;Root 子类也必须保存并恢复调用前的旋转设置。 - if (command.startsWith("uiautomator dump ")) { - return UiAutomatorDumpGuard.execute(command) { protectedCommand -> - AndroidShellExecutor.executeShellCommand(protectedCommand, uiShellIdentity) - } - } - return AndroidShellExecutor.executeShellCommand(command, uiShellIdentity) - } - - protected suspend fun shouldUseAccessibility(tool: AITool): Boolean = - !hasDisplayParam(tool) && PermissionCapabilityResolver.uiSnapshot(context).canUseAccessibility - - /** 是否包含 display 相关参数(有的话强制走 Shell,不走无障碍) */ - private fun hasDisplayParam(tool: AITool): Boolean { - return tool.parameters.any { param -> - param.name.equals("display", ignoreCase = true) - } - } - - private fun getDisplayArg(tool: AITool): String { - val display = tool.parameters.find { it.name.equals("display", ignoreCase = true) }?.value?.trim() - return if (!display.isNullOrEmpty()) "-d $display " else "" - } - - /** 使用Shell命令实现点击操作 */ - override suspend fun tap(tool: AITool): ToolResult { - if (shouldUseAccessibility(tool)) { - AppLogger.d(TAG, "无障碍服务已启用,使用无障碍点击") - return super.tap(tool) - } - - val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() - val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() - - if (x == null || y == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = - "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." - ) - } - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - - // 使用Shell命令执行点击 - try { - AppLogger.d(TAG, "Attempting to tap at coordinates: ($x, $y) via shell command") - val command = "input ${getDisplayArg(tool)}tap $x $y" - val result = executeUiShellCommand(command) - - if (result.success) { - AppLogger.d(TAG, "Tap successful at coordinates: ($x, $y)") - withContext(Dispatchers.Main) { - operationOverlay.showTap(x, y) - operationOverlay.hide() - } - return ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "tap", - actionDescription = - "Successfully tapped at coordinates ($x, $y) via shell command", - coordinates = Pair(x, y) - ), - error = "" - ) - } else { - AppLogger.e(TAG, "Tap failed at coordinates: ($x, $y), error: ${result.stderr}") - withContext(Dispatchers.Main) { - operationOverlay.hide() // 隐藏反馈(在主线程上执行) - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = - "Failed to tap at coordinates ($x, $y): ${result.stderr ?: "Unknown error"}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error tapping at coordinates ($x, $y)", e) - withContext(Dispatchers.Main) { - operationOverlay.hide() // 隐藏反馈(在主线程上执行) - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error tapping at coordinates: ${e.message ?: "Unknown exception"}" - ) - } - } - - override suspend fun longPress(tool: AITool): ToolResult { - if (shouldUseAccessibility(tool)) { - AppLogger.d(TAG, "无障碍服务已启用,使用无障碍长按") - return super.longPress(tool) - } - - val x = tool.parameters.find { it.name == "x" }?.value?.toIntOrNull() - val y = tool.parameters.find { it.name == "y" }?.value?.toIntOrNull() - - if (x == null || y == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Missing or invalid coordinates. Both 'x' and 'y' must be valid integers." - ) - } - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - - try { - AppLogger.d(TAG, "Attempting to long press at coordinates: ($x, $y) via shell command") - // Use swipe to simulate long press - val command = "input ${getDisplayArg(tool)}swipe $x $y $x $y 800" - val result = executeUiShellCommand(command) - - if (result.success) { - AppLogger.d(TAG, "Long press successful at coordinates: ($x, $y)") - withContext(Dispatchers.Main) { - operationOverlay.showTap(x, y) - operationOverlay.hide() - } - return ToolResult( - toolName = tool.name, - success = true, - result = UIActionResultData( - actionType = "long_press", - actionDescription = "Successfully long pressed at ($x, $y) via shell command", - coordinates = Pair(x, y) - ), - error = "" - ) - } else { - AppLogger.e(TAG, "Long press failed at coordinates: ($x, $y), error: ${result.stderr}") - withContext(Dispatchers.Main) { operationOverlay.hide() } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to long press at coordinates ($x, $y): ${result.stderr ?: "Unknown error"}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error long pressing at coordinates ($x, $y)", e) - withContext(Dispatchers.Main) { operationOverlay.hide() } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error long pressing at coordinates: ${e.message ?: "Unknown exception"}" - ) - } - } - - /** 使用Shell命令实现滑动操作 */ - override suspend fun swipe(tool: AITool): ToolResult { - if (shouldUseAccessibility(tool)) { - AppLogger.d(TAG, "无障碍服务已启用,使用无障碍滑动") - return super.swipe(tool) - } - - val startX = tool.parameters.find { it.name == "start_x" }?.value?.toIntOrNull() - val startY = tool.parameters.find { it.name == "start_y" }?.value?.toIntOrNull() - val endX = tool.parameters.find { it.name == "end_x" }?.value?.toIntOrNull() - val endY = tool.parameters.find { it.name == "end_y" }?.value?.toIntOrNull() - val duration = tool.parameters.find { it.name == "duration" }?.value?.toIntOrNull() ?: 300 - - if (startX == null || startY == null || endX == null || endY == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = - "Missing or invalid coordinates. 'start_x', 'start_y', 'end_x', and 'end_y' must be valid integers." - ) - } - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - - try { - AppLogger.d( - TAG, - "Attempting to swipe from ($startX, $startY) to ($endX, $endY) with duration $duration ms via shell command" - ) - val command = "input ${getDisplayArg(tool)}swipe $startX $startY $endX $endY $duration" - val result = executeUiShellCommand(command) - - if (result.success) { - AppLogger.d(TAG, "Swipe successful from ($startX, $startY) to ($endX, $endY)") - withContext(Dispatchers.Main) { - operationOverlay.showSwipe(startX, startY, endX, endY) - operationOverlay.hide() - } - return ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "swipe", - actionDescription = - "Successfully performed swipe from ($startX, $startY) to ($endX, $endY) via shell command" - ), - error = "" - ) - } else { - AppLogger.e(TAG, "Swipe failed: ${result.stderr}") - withContext(Dispatchers.Main) { - operationOverlay.hide() // 隐藏反馈(在主线程上执行) - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to perform swipe: ${result.stderr ?: "Unknown error"}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error performing swipe", e) - withContext(Dispatchers.Main) { - operationOverlay.hide() // 隐藏反馈(在主线程上执行) - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error performing swipe: ${e.message ?: "Unknown exception"}" - ) - } - } - - /** 使用Shell命令点击元素 */ - override suspend fun clickElement(tool: AITool): ToolResult { - if (shouldUseAccessibility(tool)) { - AppLogger.d(TAG, "无障碍服务已启用,使用无障碍点击元素") - return super.clickElement(tool) - } - - val resourceId = tool.parameters.find { it.name == "resourceId" }?.value - val className = tool.parameters.find { it.name == "className" }?.value - val contentDesc = tool.parameters.find { it.name == "contentDesc" }?.value - // index kept for future use - tool.parameters.find { it.name == "index" }?.value?.toIntOrNull() ?: 0 - val bounds = tool.parameters.find { it.name == "bounds" }?.value - - if (resourceId == null && className == null && bounds == null && contentDesc == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = - "Missing element identifier. Provide at least one of: 'resourceId', 'className', 'contentDesc', or 'bounds'." - ) - } - - // 如果提供了边界坐标,直接点击 - if (bounds != null) { - try { - // 解析边界坐标格式 [left,top][right,bottom] - val boundsPattern = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]".toRegex() - val matchResult = boundsPattern.find(bounds) - - if (matchResult == null || matchResult.groupValues.size < 5) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Invalid bounds format. Should be: [left,top][right,bottom]" - ) - } - - // 提取坐标 - val x1 = matchResult.groupValues[1].toInt() - val y1 = matchResult.groupValues[2].toInt() - val x2 = matchResult.groupValues[3].toInt() - val y2 = matchResult.groupValues[4].toInt() - - // 计算中心点 - val centerX = (x1 + x2) / 2 - val centerY = (y1 + y2) / 2 - - // 利用tap方法点击中心点 - val tapTool = - AITool( - name = "tap", - parameters = - listOf( - com.ai.assistance.operit.data.model.ToolParameter( - "x", - centerX.toString() - ), - com.ai.assistance.operit.data.model.ToolParameter( - "y", - centerY.toString() - ) - ) - ) - - return tap(tapTool) - } catch (e: Exception) { - AppLogger.e(TAG, "Error processing bounds", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error processing bounds: ${e.message}" - ) - } - } - - // 使用uiautomator获取和点击元素 - return clickElementWithUiautomator(tool) - } - - /** 使用Shell命令设置输入文本 */ - override suspend fun setInputText(tool: AITool): ToolResult { - if (shouldUseAccessibility(tool)) { - AppLogger.d(TAG, "无障碍服务已启用,使用无障碍设置文本") - return super.setInputText(tool) - } - - val text = tool.parameters.find { it.name == "text" }?.value ?: "" - - try { - // 获取屏幕中心作为文本输入的位置 - val displayMetrics = context.resources.displayMetrics - val centerX = displayMetrics.widthPixels / 2 - val centerY = displayMetrics.heightPixels / 2 - - // 显示文本输入反馈(在主线程上执行) - withContext(Dispatchers.Main) { operationOverlay.showTextInput(centerX, centerY, text) } - - // 使用KEYCODE_CLEAR清除字段,这比模拟CTRL+A和DEL更直接 - AppLogger.d(TAG, "Clearing text field with KEYCODE_CLEAR") - val clearCommand = "input ${getDisplayArg(tool)}keyevent KEYCODE_CLEAR" - executeUiShellCommand(clearCommand) - - // 短暂延迟 - kotlinx.coroutines.delay(300) - - // 如果文本为空,只需清除字段 - if (text.isEmpty()) { - // 成功后主动隐藏overlay - withContext(Dispatchers.Main) { operationOverlay.hide() } - return ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "textInput", - actionDescription = - "Successfully cleared input field via shell command" - ), - error = "" - ) - } - - // 使用原生复制和ADB粘贴来输入文本,这比'input text'更可靠 - AppLogger.d(TAG, "Setting text to clipboard and pasting via ADB: $text") - withContext(Dispatchers.Main) { - val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - val clip = ClipData.newPlainText("operit_input", text) - clipboard.setPrimaryClip(clip) - } - - // 短暂延迟以确保剪贴板操作完成 - kotlinx.coroutines.delay(100) - - // 执行粘贴命令 - val pasteCommand = "input ${getDisplayArg(tool)}keyevent KEYCODE_PASTE" - val pasteResult = executeUiShellCommand(pasteCommand) - - if (pasteResult.success) { - // 成功后主动隐藏overlay - withContext(Dispatchers.Main) { operationOverlay.hide() } - return ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "textInput", - actionDescription = - "Successfully set input text to: $text via clipboard paste" - ), - error = "" - ) - } else { - withContext(Dispatchers.Main) { - operationOverlay.hide() // 隐藏反馈(在主线程上执行) - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to paste text from clipboard: ${pasteResult.stderr ?: "Unknown error"}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error setting input text", e) - withContext(Dispatchers.Main) { - operationOverlay.hide() // 隐藏反馈(在主线程上执行) - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error setting input text: ${e.message ?: "Unknown exception"}" - ) - } - } - - /** 使用Shell命令实现按键操作 */ - override suspend fun pressKey(tool: AITool): ToolResult { - val keyCode = tool.parameters.find { it.name == "key_code" }?.value - - if (keyCode == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Missing 'key_code' parameter." - ) - } - - if (shouldUseAccessibility(tool) && - (accessibilityKeyAction(keyCode) != null || - !PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) - ) { - return super.pressKey(tool) - } - - val command = "input ${getDisplayArg(tool)}keyevent $keyCode" - - return try { - val result = executeUiShellCommand(command) - - if (result.success) { - ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "keyPress", - actionDescription = - "Successfully pressed key: $keyCode via shell command" - ), - error = "" - ) - } else { - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to press key: ${result.stderr ?: "Unknown error"}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error pressing key", e) - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error pressing key: ${e.message ?: "Unknown exception"}" - ) - } - } - - override suspend fun captureScreenshotToFile(tool: AITool): Pair?> { - if (!PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) { - return if (hasDisplayParam(tool)) Pair(null, null) else super.captureScreenshotToFile(tool) - } - return try { - val screenshotDir = OperitPaths.cleanOnExitDir() - - val shortName = System.currentTimeMillis().toString().takeLast(4) - val file = File(screenshotDir, "$shortName.png") - - // 1) Debugger 模式下优先尝试 Shell 模式 (ADB) 截图 - AppLogger.d(TAG, "captureScreenshotToFile: Attempting shell screencap") - val command = "screencap -p ${file.absolutePath}" - val result = executeUiShellCommand(command) - - if (result.success && file.exists()) { - val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } - BitmapFactory.decodeFile(file.absolutePath, options) - val dimensions = if (options.outWidth > 0 && options.outHeight > 0) { - Pair(options.outWidth, options.outHeight) - } else { - null - } - AppLogger.d(TAG, "captureScreenshotToFile: Shell screencap success") - return Pair(file.absolutePath, dimensions) - } - - // 2) 如果 Shell 失败,作为回退尝试无障碍截图 (调用父类) - AppLogger.w(TAG, "captureScreenshotToFile: Shell screencap failed, falling back to accessibility") - if (hasDisplayParam(tool)) Pair(null, null) else super.captureScreenshotToFile(tool) - } catch (e: Exception) { - AppLogger.e(TAG, "captureScreenshotToFile failed in Debugger", e) - Pair(null, null) - } - } - - override suspend fun captureScreenshot(tool: AITool): Pair?> { - return captureScreenshotToFile(tool) - } - - override suspend fun captureScreenshotBitmap(tool: AITool): Pair?> { - val (filePath, dimensions) = captureScreenshot(tool) - if (filePath == null) { - return Pair(null, dimensions) - } - - val bitmap = BitmapFactory.decodeFile(filePath) ?: return Pair(null, dimensions) - val resolvedDimensions = dimensions ?: Pair(bitmap.width, bitmap.height) - return Pair(bitmap, resolvedDimensions) - } - - /** 使用Shell命令获取页面信息 */ - override suspend fun getPageInfo(tool: AITool): ToolResult { - if (shouldUseAccessibility(tool)) { - AppLogger.d(TAG, "无障碍服务已启用,使用无障碍获取页面信息") - val result = super.getPageInfo(tool) - if (result.success || !PermissionCapabilityResolver.shellSnapshot(context).hasPrivilegedShell) return result - } - - val format = tool.parameters.find { it.name == "format" }?.value ?: "xml" - // detail kept for future use - tool.parameters.find { it.name == "detail" }?.value ?: "summary" - - if (format !in listOf("xml", "json")) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Invalid format specified. Must be 'xml' or 'json'." - ) - } - - return try { - // 获取UI数据 - val uiData = getUIDataFromShell(tool) - if (uiData == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to retrieve UI data." - ) - } - - // 解析当前窗口信息 - val focusInfo = extractFocusInfoFromShell(uiData.windowInfo) - - // 简化布局信息 - val simplifiedLayout = simplifyLayoutFromXml(uiData.uiXml) - - // 创建结构化数据 - val resultData = - UIPageResultData( - packageName = focusInfo.packageName ?: "Unknown", - activityName = focusInfo.activityName ?: "Unknown", - uiElements = simplifiedLayout - ) - - ToolResult(toolName = tool.name, success = true, result = resultData, error = "") - } catch (e: Exception) { - AppLogger.e(TAG, "Error getting page info", e) - ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error getting page info: ${e.message}" - ) - } - } - - /** UI数据类,保存XML和窗口信息 */ - private data class UIData(val uiXml: String, val windowInfo: String) - - /** 获取UI数据,使用Shell命令,严格遵守工具参数中的 display(如有) */ - private suspend fun getUIDataFromShell(tool: AITool): UIData? { - return try { - // 使用ADB命令获取UI dump - AppLogger.d(TAG, "使用ADB命令获取UI数据") - - val displayId = tool.parameters - .find { it.name.equals("display", ignoreCase = true) } - ?.value - ?.trim() - ?.takeIf { it.isNotEmpty() } - - // 执行UI dump命令,只有在显式提供 display 参数时才使用 --display-id - val dumpResult = if (displayId != null) { - val cmd = "uiautomator dump --display-id $displayId /sdcard/window_dump.xml" - AppLogger.d(TAG, "UI dump using explicit display-id=$displayId") - executeUiShellCommand(cmd) - } else { - executeUiShellCommand("uiautomator dump /sdcard/window_dump.xml") - } - - if (!dumpResult.success) { - AppLogger.e(TAG, "uiautomator dump失败: ${dumpResult.stderr}") - return null - } - AppLogger.d(TAG, "uiautomator dump成功: ${dumpResult.stdout}") - - // 读取dump文件内容 - val readResult = executeUiShellCommand("cat /sdcard/window_dump.xml") - if (!readResult.success) { - AppLogger.e(TAG, "读取UI dump文件失败: ${readResult.stderr}") - return null - } - - // 获取窗口信息 - var windowInfo = getWindowInfoFromShell() - - // 如果窗口信息为空,尝试延迟后重试一次 - if (windowInfo.isEmpty()) { - AppLogger.w(TAG, "首次获取窗口信息失败,延迟500ms后重试") - kotlinx.coroutines.delay(500) - windowInfo = getWindowInfoFromShell() - } - - UIData(readResult.stdout, windowInfo) - } catch (e: Exception) { - AppLogger.e(TAG, "获取UI数据时出错", e) - null - } - } - - /** 获取窗口信息,使用多种命令尝试 */ - private suspend fun getWindowInfoFromShell(): String { - // 尝试多种命令来获取窗口信息 - val commands = - listOf( - // 标准命令,获取当前焦点和焦点应用 - "dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp'", - // 备用命令,只获取当前焦点 - "dumpsys window | grep -E 'mCurrentFocus'", - // 备用命令,只获取焦点应用 - "dumpsys window | grep -E 'mFocusedApp'", - // 最后的备用命令,尝试获取任何窗口信息 - "dumpsys window | grep -E 'Window #|Focus'", - // 极端情况下,尝试获取前台应用包名 - "dumpsys activity recents | grep 'Recent #0' -A2" - ) - - // 依次尝试每个命令,直到有一个成功 - for (command in commands) { - try { - val result = executeUiShellCommand(command) - if (result.success && result.stdout.isNotEmpty()) { - AppLogger.d(TAG, "成功获取窗口信息: ${result.stdout.take(100)}") - return result.stdout - } - // 如果命令执行失败或返回空结果,尝试下一个命令 - AppLogger.w(TAG, "窗口信息命令 '$command' 失败或返回空结果") - } catch (e: Exception) { - AppLogger.e(TAG, "执行窗口信息命令 '$command' 出错", e) - // 继续尝试下一个命令 - } - } - - // 所有命令都失败时,尝试获取topActivity作为最后的手段 - try { - val topActivityCommand = - "dumpsys activity activities | grep -E 'topResumedActivity|topActivity'" - val result = executeUiShellCommand(topActivityCommand) - if (result.success && result.stdout.isNotEmpty()) { - AppLogger.d(TAG, "使用topActivity作为窗口信息替代: ${result.stdout.take(100)}") - return result.stdout - } - } catch (e: Exception) { - AppLogger.e(TAG, "获取topActivity失败", e) - } - - AppLogger.e(TAG, "所有获取窗口信息的尝试均失败") - return "" - } - - /** UI节点数据类,仅在Shell实现中使用 */ - private data class UINodeShell( - val className: String?, - val text: String?, - val contentDesc: String?, - val resourceId: String?, - val bounds: String?, - val isClickable: Boolean, - val children: MutableList = mutableListOf() - ) - - /** 简化布局,从XML中提取UI元素,Shell版本 */ - private fun simplifyLayoutFromXml(xml: String): SimplifiedUINode { - val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } - val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } - - val nodeStack = mutableListOf() - var rootNode: UINodeShell? = null - - while (parser.eventType != XmlPullParser.END_DOCUMENT) { - when (parser.eventType) { - XmlPullParser.START_TAG -> { - if (parser.name == "node") { - val newNode = createNodeShell(parser) - if (rootNode == null) { - rootNode = newNode - nodeStack.add(newNode) - } else { - nodeStack.lastOrNull()?.children?.add(newNode) - nodeStack.add(newNode) - } - } - } - XmlPullParser.END_TAG -> { - if (parser.name == "node") { - nodeStack.removeLastOrNull() - } - } - } - parser.next() - } - - // 创建默认根节点,如果解析失败 - return rootNode?.toUINodeSimplified() - ?: SimplifiedUINode( - className = null, - text = null, - contentDesc = null, - resourceId = null, - bounds = null, - isClickable = false, - children = emptyList() - ) - } - - // 转换内部UINodeShell为SimplifiedUINode - private fun UINodeShell.toUINodeSimplified(): SimplifiedUINode { - return SimplifiedUINode( - className = className, - text = text, - contentDesc = contentDesc, - resourceId = resourceId, - bounds = bounds, - isClickable = isClickable, - children = children.map { it.toUINodeSimplified() } - ) - } - - private fun createNodeShell(parser: XmlPullParser): UINodeShell { - // 解析关键属性 - val className = parser.getAttributeValue(null, "class")?.substringAfterLast('.') - val text = parser.getAttributeValue(null, "text")?.replace(" ", "\n") - val contentDesc = parser.getAttributeValue(null, "content-desc") - val resourceId = parser.getAttributeValue(null, "resource-id") - val bounds = parser.getAttributeValue(null, "bounds") - val isClickable = parser.getAttributeValue(null, "clickable") == "true" - - return UINodeShell( - className = className, - text = text, - contentDesc = contentDesc, - resourceId = resourceId, - bounds = bounds, - isClickable = isClickable - ) - } - - /** 窗口焦点信息数据类 */ - private data class FocusInfoShell( - var packageName: String? = null, - var activityName: String? = null - ) - - /** 从窗口焦点数据中提取包名和活动名 */ - private fun extractFocusInfoFromShell(windowInfo: String): FocusInfoShell { - val result = FocusInfoShell() - - try { - if (windowInfo.isBlank()) { - AppLogger.w(TAG, "Window info is empty, cannot extract focus information") - // 即使窗口信息为空,也设置默认值,确保不会返回Unknown - result.packageName = "android" - result.activityName = "ForegroundActivity" - return result - } - - AppLogger.d(TAG, "Window info for extraction: ${windowInfo.take(200)}") - - // 尝试不同的提取方法,按照特异性顺序 - if (!extractFromCurrentFocusShell(windowInfo, result) && - !extractFromFocusedAppShell(windowInfo, result) && - !extractFromLauncherInfoShell(windowInfo, result) && - !extractFromTopActivityShell(windowInfo, result) && - !extractUsingGenericPatternsShell(windowInfo, result) - ) { - - AppLogger.w(TAG, "Could not extract focus information using any method") - } - - // 最后的回退:如果我们仍然无法确定任何信息,使用默认值 - if (result.packageName == null) { - if (windowInfo.contains("statusbar") || windowInfo.contains("SystemUI")) { - result.packageName = "com.android.systemui" - result.activityName = "SystemUI" - AppLogger.d(TAG, "Using SystemUI fallback") - } else if (windowInfo.contains("recents")) { - result.packageName = "com.android.systemui" - result.activityName = "Recents" - AppLogger.d(TAG, "Using Recents fallback") - } else { - result.packageName = "android" - result.activityName = "ForegroundActivity" - AppLogger.d(TAG, "Using last-resort fallback values") - } - } - - // 记录提取结果 - AppLogger.d( - TAG, - "Final extraction result - package: ${result.packageName}, activity: ${result.activityName}" - ) - } catch (e: Exception) { - AppLogger.e(TAG, "Error parsing window info", e) - // 确保即使出现异常,我们也有至少一些默认值 - if (result.packageName == null) result.packageName = "android" - if (result.activityName == null) result.activityName = "ForegroundActivity" - } - - return result - } - - /** - * 从mCurrentFocus格式提取 例如:mCurrentFocus=Window{1234567 u0 - * com.example.app/com.example.app.MainActivity} - */ - private fun extractFromCurrentFocusShell(windowInfo: String, result: FocusInfoShell): Boolean { - // 尝试多种mCurrentFocus格式模式 - val currentFocusPatterns = - listOf( - // 标准格式,具有包/活动(同时也支持 mFocusedWindow) - "(?:mCurrentFocus|mFocusedWindow)=.*?\\{.*?\\s+([a-zA-Z0-9_.]+)/([^\\s}]+)".toRegex(), - // 有时会看到的替代格式 - "(?:mCurrentFocus|mFocusedWindow)=.*?\\s+([a-zA-Z0-9_.]+)/([^\\s}]+)\\}".toRegex(), - // 只有包名的格式(活动将单独处理) - "(?:mCurrentFocus|mFocusedWindow)=.*?\\{.*?\\s+([a-zA-Z0-9_.]+)(?:/|\\s)".toRegex() - ) - - for (pattern in currentFocusPatterns) { - val match = pattern.find(windowInfo) - if (match != null) { - if (match.groupValues.size >= 3) { - // 包含包和活动的模式 - result.packageName = match.groupValues[1] - result.activityName = match.groupValues[2] - AppLogger.d(TAG, "Extracted from mCurrentFocus pattern (full): ${pattern.pattern}") - return true - } else if (match.groupValues.size >= 2) { - // 只有包名的模式 - result.packageName = match.groupValues[1] - AppLogger.d(TAG, "Extracted package from mCurrentFocus pattern: ${pattern.pattern}") - // 返回false以允许其他方法提取活动名称 - return false - } - } - } - return false - } - - /** - * 从mFocusedApp格式提取 例如:mFocusedApp=AppWindowToken{token=Token{12345 ActivityRecord{67890 u0 - * com.example.app/.MainActivity t123}}} - */ - private fun extractFromFocusedAppShell(windowInfo: String, result: FocusInfoShell): Boolean { - // mFocusedApp格式的多种模式 - val focusedAppPatterns = - listOf( - // 带有ActivityRecord的标准格式 - "mFocusedApp=.*?ActivityRecord\\{.*?\\s+([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex(), - // 处理类似于 mFocusedApp=null 后的真实输出行 - "ActivityRecord\\{.*?\\s+([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex(), - // 有时会看到的替代格式 - "mFocusedApp=.*?\\s+([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)\\s".toRegex(), - // 只有包名的格式 - "mFocusedApp=.*?\\s+([a-zA-Z0-9_.]+)(?:/|\\s)".toRegex() - ) - - for (pattern in focusedAppPatterns) { - val match = pattern.find(windowInfo) - if (match != null) { - if (match.groupValues.size >= 3) { - // 包含包和活动的完全匹配 - result.packageName = match.groupValues[1] - result.activityName = match.groupValues[2] - AppLogger.d(TAG, "Extracted from mFocusedApp pattern (full): ${pattern.pattern}") - return true - } else if (match.groupValues.size >= 2) { - // 只有包的部分匹配 - result.packageName = match.groupValues[1] - AppLogger.d(TAG, "Extracted package from mFocusedApp pattern: ${pattern.pattern}") - // 返回false以允许通过其他方法提取活动名称 - return false - } - } - } - return false - } - - /** 为启动器窗口提取信息 例如:mCurrentFocus=Window{1a23bc4 u0 Launcher} */ - private fun extractFromLauncherInfoShell(windowInfo: String, result: FocusInfoShell): Boolean { - // 查找启动器特定模式 - if (windowInfo.contains("mCurrentFocus") && windowInfo.contains("Launcher")) { - val launcherPatterns = - listOf( - "\\{.*?\\s+([a-zA-Z0-9_.]+\\.launcher)/".toRegex(), - "\\{.*?\\s+([a-zA-Z0-9_.]+\\.home)/".toRegex(), - "\\{.*?\\s+Launcher\\}".toRegex() - ) - - for (pattern in launcherPatterns) { - val match = pattern.find(windowInfo) - if (match != null && match.groupValues.size >= 2) { - result.packageName = match.groupValues[1] - result.activityName = "Launcher" - AppLogger.d(TAG, "Extracted launcher info") - return true - } - } - - // 如果我们检测到Launcher但无法提取特定的包, - // 使用默认的启动器包和名称 - result.packageName = "com.android.launcher3" - result.activityName = "Launcher" - AppLogger.d(TAG, "Using default launcher info") - return true - } - return false - } - - /** - * 从topActivity/topResumedActivity输出格式提取 - * 例如:topActivity=ComponentInfo{com.example.app/.MainActivity} - */ - private fun extractFromTopActivityShell(windowInfo: String, result: FocusInfoShell): Boolean { - // topActivity格式的模式 - val topActivityPatterns = - listOf( - "topActivity=ComponentInfo\\{([a-zA-Z0-9_.]+)/\\.?([^}]+)\\}".toRegex(), - "topResumedActivity=ComponentInfo\\{([a-zA-Z0-9_.]+)/\\.?([^}]+)\\}".toRegex(), - "ResumedActivity:\\s+\\{([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex() - ) - - for (pattern in topActivityPatterns) { - val match = pattern.find(windowInfo) - if (match != null && match.groupValues.size >= 3) { - result.packageName = match.groupValues[1] - result.activityName = match.groupValues[2] - AppLogger.d(TAG, "Extracted from topActivity pattern: ${pattern.pattern}") - return true - } - } - - // 还要查找Recent tasks格式 - val recentPattern = "Recent #0.*?\\{([a-zA-Z0-9_.]+)/\\.?([^\\s}]+)".toRegex() - val recentMatch = recentPattern.find(windowInfo) - if (recentMatch != null && recentMatch.groupValues.size >= 3) { - result.packageName = recentMatch.groupValues[1] - result.activityName = recentMatch.groupValues[2] - AppLogger.d(TAG, "Extracted from Recent tasks pattern") - return true - } - - return false - } - - /** 作为后备使用更通用的模式提取 */ - private fun extractUsingGenericPatternsShell( - windowInfo: String, - result: FocusInfoShell - ): Boolean { - var foundAny = false - - // 尝试用各种模式提取包名 - if (result.packageName == null) { - // 查找常见的包模式,如com.android.something - val packagePatterns = - listOf( - "\\s([a-zA-Z][a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+){2,})/".toRegex(), // com.example.app/ - "\\s([a-zA-Z][a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+){2,})\\s".toRegex(), // com.example.app (空格后) - "([a-zA-Z][a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+){2,})".toRegex() // 只查找任何包名类似的名称 - ) - - for (pattern in packagePatterns) { - val match = pattern.find(windowInfo) - if (match != null && match.groupValues.size >= 2) { - val potentialPackage = match.groupValues[1] - // 验证这看起来像一个真实的包(避免匹配随机字符串) - if (potentialPackage.split(".").size >= 3 && - !potentialPackage.contains("@") && - !potentialPackage.startsWith("1") && - !potentialPackage.startsWith("0") - ) { - - result.packageName = potentialPackage - foundAny = true - AppLogger.d(TAG, "Found package name using fallback pattern: ${pattern.pattern}") - break - } - } - } - } - - // 如果我们还没有活动名称,尝试提取它 - if (result.activityName == null) { - // 查找活动名称模式 - val activityPatterns = - listOf( - "/\\.?([A-Z][a-zA-Z0-9_]+Activity)".toRegex(), // /.MainActivity or - // /MainActivity - "/([^\\s/}]+)".toRegex(), // 斜杠后的任何段 - "\\.([A-Z][a-zA-Z0-9_]+)".toRegex() // .MainActivity - ) - - for (pattern in activityPatterns) { - val match = pattern.find(windowInfo) - if (match != null && match.groupValues.size >= 2) { - val activityName = match.groupValues[1] - // 验证它看起来像一个活动名称(以大写字母开头) - if (activityName.isNotEmpty() && - activityName[0].isUpperCase() && - !activityName.contains("@") - ) { - - result.activityName = activityName - foundAny = true - AppLogger.d(TAG, "Found activity name using fallback pattern: ${pattern.pattern}") - break - } - } - } - } - - // 特殊情况处理:如果我们有包名但没有活动名称 - if (result.packageName != null && result.activityName == null) { - // 尝试根据包猜测主活动名称 - val packageParts = result.packageName!!.split(".") - if (packageParts.isNotEmpty()) { - val lastPart = packageParts.last().replaceFirstChar { if (it.isLowerCase()) it.titlecase(java.util.Locale.getDefault()) else it.toString() } - result.activityName = "${lastPart}Activity" - AppLogger.d(TAG, "Guessed activity name from package: ${result.activityName}") - foundAny = true - } - } - - // 如果我们找到了包或活动,将其视为部分成功 - return foundAny - } - - - - /** 使用uiautomator点击元素 */ - private suspend fun clickElementWithUiautomator(tool: AITool): ToolResult { - AppLogger.d(TAG, "Using uiautomator to click element") - - val resourceId = tool.parameters.find { it.name == "resourceId" }?.value - val className = tool.parameters.find { it.name == "className" }?.value - val contentDesc = tool.parameters.find { it.name == "contentDesc" }?.value - val index = tool.parameters.find { it.name == "index" }?.value?.toIntOrNull() ?: 0 - val partialMatch = - tool.parameters.find { it.name == "partialMatch" }?.value?.toBoolean() ?: false - - try { - // 先尝试获取UI dump - AppLogger.d(TAG, "Dumping UI hierarchy to find element") - val dumpCommand = "uiautomator dump /sdcard/window_dump.xml" - val result = executeUiShellCommand(dumpCommand) - - if (!result.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to dump UI hierarchy: ${result.stderr ?: "Unknown error"}" - ) - } - - // 读取dump文件 - val readCommand = "cat /sdcard/window_dump.xml" - val readResult = executeUiShellCommand(readCommand) - - if (!readResult.success) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to read UI dump: ${readResult.stderr ?: "Unknown error"}" - ) - } - - val xml = readResult.stdout - - // 使用XML Parser查找匹配的元素(取代有问题的正则方式) - val hasSelectors = resourceId != null || className != null || contentDesc != null - if (!hasSelectors) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "No element selector provided." - ) - } - - // 用XmlPullParser逐节点匹配,避免正则跨节点匹配的问题 - data class MatchedNode(val bounds: String?) - val matchingNodes = mutableListOf() - - try { - val factory = XmlPullParserFactory.newInstance().apply { isNamespaceAware = false } - val parser = factory.newPullParser().apply { setInput(StringReader(xml)) } - - while (parser.eventType != XmlPullParser.END_DOCUMENT) { - if (parser.eventType == XmlPullParser.START_TAG && parser.name == "node") { - val actualId = parser.getAttributeValue(null, "resource-id") - val actualClass = parser.getAttributeValue(null, "class") - val actualDesc = parser.getAttributeValue(null, "content-desc") - val actualBounds = parser.getAttributeValue(null, "bounds") - - var matches = true - - if (resourceId != null) { - if (actualId == null) { - matches = false - } else if (partialMatch) { - matches = actualId.contains(resourceId) - } else { - // 支持短ID (expand_search) 和完整ID (tv.danmaku.bili:id/expand_search) - matches = actualId == resourceId || actualId.endsWith(":id/$resourceId") - } - } - - if (matches && className != null) { - if (actualClass == null) { - matches = false - } else if (partialMatch) { - matches = actualClass.contains(className) - } else { - // 支持短类名 (ImageView) 和完整类名 (android.widget.ImageView) - matches = actualClass == className || actualClass.endsWith(".$className") - } - } - - if (matches && contentDesc != null) { - if (actualDesc == null) { - matches = false - } else if (partialMatch) { - matches = actualDesc.contains(contentDesc, ignoreCase = true) - } else { - matches = actualDesc.equals(contentDesc, ignoreCase = true) - } - } - - if (matches) { - matchingNodes.add(MatchedNode(bounds = actualBounds)) - } - } - parser.next() - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error parsing UI XML", e) - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to parse UI hierarchy XML: ${e.message}" - ) - } - - if (matchingNodes.isEmpty()) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "No matching element found." - ) - } - - if (index < 0 || index >= matchingNodes.size) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = - "Index out of range. Found ${matchingNodes.size} elements, but requested index $index." - ) - } - - // 获取指定索引的节点bounds - val nodeBounds = matchingNodes[index].bounds - if (nodeBounds == null) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Target element has no bounds." - ) - } - - // 提取边界坐标 - val boundsPattern = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]".toRegex() - val boundsMatch = boundsPattern.find(nodeBounds) - if (boundsMatch == null || boundsMatch.groupValues.size < 5) { - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to extract bounds from the element: $nodeBounds" - ) - } - - // 提取坐标 - val x1 = boundsMatch.groupValues[1].toInt() - val y1 = boundsMatch.groupValues[2].toInt() - val x2 = boundsMatch.groupValues[3].toInt() - val y2 = boundsMatch.groupValues[4].toInt() - - // 计算中心点 - val centerX = (x1 + x2) / 2 - val centerY = (y1 + y2) / 2 - - withContext(Dispatchers.Main) { operationOverlay.hideImmediately() } - - val tapCommand = "input tap $centerX $centerY" - val tapResult = executeUiShellCommand(tapCommand) - - if (tapResult.success) { - val identifierDescription = - when { - resourceId != null -> " with resource ID: $resourceId" - contentDesc != null -> " with content description: $contentDesc" - else -> " with class name: $className" - } - - val matchCount = - if (matchingNodes.size > 1) { - " (index $index of ${matchingNodes.size} matches)" - } else "" - - withContext(Dispatchers.Main) { - operationOverlay.showTap(centerX, centerY) - operationOverlay.hide() - } - return ToolResult( - toolName = tool.name, - success = true, - result = - UIActionResultData( - actionType = "click", - actionDescription = - "Successfully clicked element$identifierDescription$matchCount at coordinates ($centerX, $centerY) via shell command", - coordinates = Pair(centerX, centerY), - elementId = resourceId ?: className ?: contentDesc - ), - error = "" - ) - } else { - withContext(Dispatchers.Main) { - operationOverlay.hide() - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Failed to click element: ${tapResult.stderr ?: "Unknown error"}" - ) - } - } catch (e: Exception) { - AppLogger.e(TAG, "Error clicking element with uiautomator", e) - withContext(Dispatchers.Main) { - operationOverlay.hide() - } - return ToolResult( - toolName = tool.name, - success = false, - result = StringResultData(""), - error = "Error clicking element: ${e.message ?: "Unknown exception"}" - ) - } finally { - // 清理临时文件 - try { - Runtime.getRuntime().exec("rm /sdcard/window_dump.xml") - } catch (cleanupEx: Exception) { - AppLogger.e(TAG, "Error cleaning up temp file", cleanupEx) - } - } - } - - /** 从边界字符串提取中心坐标 返回中心点坐标,或null如果格式无效 */ - protected fun extractCenterCoordinates(bounds: String): Pair? { - val boundsPattern = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]".toRegex() - val matchResult = boundsPattern.find(bounds) ?: return null - - if (matchResult.groupValues.size < 5) return null - - // 提取坐标 - val x1 = matchResult.groupValues[1].toInt() - val y1 = matchResult.groupValues[2].toInt() - val x2 = matchResult.groupValues[3].toInt() - val y2 = matchResult.groupValues[4].toInt() - - // 计算并返回中心点 - val centerX = (x1 + x2) / 2 - val centerY = (y1 + y2) / 2 - - return Pair(centerX, centerY) - } -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootDeviceInfoToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootDeviceInfoToolExecutor.kt deleted file mode 100644 index 7777815844..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootDeviceInfoToolExecutor.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.root - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.admin.AdminDeviceInfoToolExecutor - -/** Root级别的设备信息工具,继承管理员版本 */ -open class RootDeviceInfoToolExecutor(context: Context) : AdminDeviceInfoToolExecutor(context) { - // 当前阶段不添加新功能,仅继承管理员实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootFileSystemTools.kt deleted file mode 100644 index 197ead4a34..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootFileSystemTools.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.root - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.admin.AdminFileSystemTools - -/** Root级别的文件系统工具,继承管理员级别 */ -open class RootFileSystemTools(context: Context) : AdminFileSystemTools(context) { - // 当前阶段不添加新功能,仅继承管理员级别实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootSystemOperationTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootSystemOperationTools.kt deleted file mode 100644 index 7cfb3e35eb..0000000000 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootSystemOperationTools.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.ai.assistance.operit.core.tools.defaultTool.root - -import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.admin.AdminSystemOperationTools - -/** Root级别的系统操作工具,继承管理员版本 */ -open class RootSystemOperationTools(context: Context) : AdminSystemOperationTools(context) { - // 当前阶段不添加新功能,仅继承管理员实现 -} diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt index eeaf1a9c1b..f0b52dbd44 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt @@ -21,10 +21,7 @@ import kotlinx.coroutines.withContext import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParserFactory -/** - * Root-level UI tools that use shell commands (uiautomator, input) for robust UI automation. - * This implementation is modeled after DebuggerUITools but operates without accessibility fallbacks. - */ +/** Root UI 工具复用管理员公共实现,并按 Root 能力执行界面操作。 */ open class RootUITools(context: Context) : AdminUITools(context) { companion object { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt index 0b48cc51be..8df2c40517 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt @@ -56,7 +56,7 @@ open class StandardUITools(protected val context: Context) : ToolImplementations private const val TAG = "UITools" private const val COMMAND_TIMEOUT_SECONDS = 10L private const val OPERATION_NOT_SUPPORTED = - "This operation is not supported in the standard version. Please use the accessibility or debugger version." + "This operation is not supported in the standard version. Please select administrator or root mode and grant the required authorization." internal val APP_PACKAGES: MutableMap = mutableMapOf( diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt index a3a6c1386c..f7038ac82b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt @@ -17,7 +17,6 @@ enum class AndroidPermissionLevel { fun fromString(value: String?): AndroidPermissionLevel { return when(value?.uppercase(Locale.ROOT)) { "STANDARD" -> STANDARD - "ACCESSIBILITY", "DEBUGGER" -> ADMIN "ADMIN" -> ADMIN "ROOT" -> ROOT else -> STANDARD // 默认为最低权限 diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt index eef7ffa1e5..992aa1a263 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt @@ -18,7 +18,7 @@ class ActionListenerFactory { val listener = when (backend) { PermissionBackend.STANDARD -> StandardActionListener(appContext) PermissionBackend.ACCESSIBILITY -> AccessibilityActionListener(appContext) - PermissionBackend.SHIZUKU -> DebuggerActionListener(appContext) + PermissionBackend.SHIZUKU -> ShizukuActionListener(appContext) PermissionBackend.ROOT -> RootActionListener(appContext) } listener.initialize() diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/DebuggerActionListener.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ShizukuActionListener.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/action/DebuggerActionListener.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ShizukuActionListener.kt index 195631086a..2d9b482e1d 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/DebuggerActionListener.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ShizukuActionListener.kt @@ -19,9 +19,9 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach /** 基于Shizuku的UI操作监听器 作为管理员模式的 Shizuku 后端 */ -class DebuggerActionListener(private val context: Context) : ActionListener { +class ShizukuActionListener(private val context: Context) : ActionListener { companion object { - private const val TAG = "DebuggerActionListener" + private const val TAG = "ShizukuActionListener" /** 添加状态变更监听器 */ fun addStateChangeListener(listener: () -> Unit) { @@ -96,7 +96,7 @@ class DebuggerActionListener(private val context: Context) : ActionListener { // 启动系统级事件监控 startSystemEventMonitoring() - return@withContext ActionListener.ListeningResult.success(context.getString(R.string.debugger_ui_listener_started)) + return@withContext ActionListener.ListeningResult.success(context.getString(R.string.shizuku_ui_listener_started)) } catch (e: Exception) { AppLogger.e(TAG, "启动调试器UI操作监听失败", e) isListening.set(false) diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt index 468e940404..cf010b35e9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt @@ -17,7 +17,7 @@ class ShellExecutorFactory { val appContext = context.applicationContext val executor = when (backend) { PermissionBackend.STANDARD -> StandardShellExecutor(appContext) - PermissionBackend.SHIZUKU -> DebuggerShellExecutor(appContext) + PermissionBackend.SHIZUKU -> ShizukuShellExecutor(appContext) PermissionBackend.ROOT -> RootShellExecutor(appContext) PermissionBackend.ACCESSIBILITY -> error("Accessibility does not provide a shell backend") } diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/DebuggerShellExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShizukuShellExecutor.kt similarity index 96% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/DebuggerShellExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShizukuShellExecutor.kt index 071de7c8d3..8b70fdc431 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/DebuggerShellExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShizukuShellExecutor.kt @@ -38,9 +38,9 @@ import moe.shizuku.server.IRemoteProcess import moe.shizuku.server.IShizukuService /** 基于Shizuku的Shell命令执行器 作为管理员模式的 Shizuku 后端 */ -class DebuggerShellExecutor(private val context: Context) : ShellExecutor { +class ShizukuShellExecutor(private val context: Context) : ShellExecutor { companion object { - private const val TAG = "DebuggerShellExecutor" + private const val TAG = "ShizukuShellExecutor" private val serviceCache = ConcurrentHashMap() /** 添加状态变更监听器 */ @@ -449,7 +449,7 @@ class DebuggerShellExecutor(private val context: Context) : ShellExecutor { * stdout 与 stderr 必须同时消费,否则任一管道写满都会阻塞远程进程;stdin * 也必须主动关闭,否则需要 EOF 的命令会一直等待输入。 */ -private const val DEBUGGER_SHELL_TAG = "DebuggerShellExecutor" +private const val SHIZUKU_SHELL_TAG = "ShizukuShellExecutor" private const val REMOTE_PROCESS_POLL_INTERVAL_MS = 100L private const val POST_EXIT_OUTPUT_DRAIN_GRACE_MS = 1_000L private const val OUTPUT_TRUNCATION_NOTICE = @@ -553,10 +553,10 @@ private suspend fun executeRemoteProcess( // cancellation is allowed to leave this function. throw e } catch (e: RemoteException) { - AppLogger.e(DEBUGGER_SHELL_TAG, "Remote process operation failed: $command", e) + AppLogger.e(SHIZUKU_SHELL_TAG, "Remote process operation failed: $command", e) ShellExecutor.CommandResult(false, "", "Remote exception: ${e.message}") } catch (e: Exception) { - AppLogger.e(DEBUGGER_SHELL_TAG, "Remote process execution failed: $command", e) + AppLogger.e(SHIZUKU_SHELL_TAG, "Remote process execution failed: $command", e) ShellExecutor.CommandResult(false, "", "Error: ${e.message}") } finally { // Covers failures before the structured reader scope was created. @@ -585,7 +585,7 @@ private fun closeRemoteStdin(process: IRemoteProcess) { process.getOutputStream()?.close() } catch (e: Exception) { // A command may still be usable when the optional stdin descriptor is unavailable. - AppLogger.v(DEBUGGER_SHELL_TAG, "Unable to close remote stdin", e) + AppLogger.v(SHIZUKU_SHELL_TAG, "Unable to close remote stdin", e) } } @@ -594,7 +594,7 @@ private fun destroyRemoteProcess(process: IRemoteProcess?) { try { process.destroy() } catch (e: Exception) { - AppLogger.v(DEBUGGER_SHELL_TAG, "Unable to destroy remote process", e) + AppLogger.v(SHIZUKU_SHELL_TAG, "Unable to destroy remote process", e) } } @@ -603,7 +603,7 @@ private fun closeDescriptor(descriptor: ParcelFileDescriptor?, label: String) { try { descriptor.close() } catch (e: Exception) { - AppLogger.v(DEBUGGER_SHELL_TAG, "Unable to close $label", e) + AppLogger.v(SHIZUKU_SHELL_TAG, "Unable to close $label", e) } } @@ -626,9 +626,9 @@ private fun drainDescriptor( } } catch (e: IOException) { // Closing a descriptor during cancellation or post-exit cleanup is expected. - AppLogger.v(DEBUGGER_SHELL_TAG, "Reading remote $label stopped", e) + AppLogger.v(SHIZUKU_SHELL_TAG, "Reading remote $label stopped", e) } catch (e: Exception) { - AppLogger.w(DEBUGGER_SHELL_TAG, "Reading remote $label failed", e) + AppLogger.w(SHIZUKU_SHELL_TAG, "Reading remote $label failed", e) } } @@ -742,7 +742,7 @@ private class ShizukuShellProcess( completion.complete(-1) throw e } catch (e: Exception) { - AppLogger.e(DEBUGGER_SHELL_TAG, "Interactive Shizuku process failed: $command", e) + AppLogger.e(SHIZUKU_SHELL_TAG, "Interactive Shizuku process failed: $command", e) completion.complete(-1) } finally { if (!processFinished && !destroyed.get()) { @@ -771,11 +771,11 @@ private class ShizukuShellProcess( } } catch (e: IOException) { if (!destroyed.get()) { - AppLogger.v(DEBUGGER_SHELL_TAG, "Reading interactive $label stopped", e) + AppLogger.v(SHIZUKU_SHELL_TAG, "Reading interactive $label stopped", e) } } catch (e: Exception) { if (!destroyed.get()) { - AppLogger.w(DEBUGGER_SHELL_TAG, "Reading interactive $label failed", e) + AppLogger.w(SHIZUKU_SHELL_TAG, "Reading interactive $label failed", e) } } finally { channel.close() diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 9d7c8b5975..e3592c378f 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -7115,8 +7115,8 @@ Cannot decode Bitmap from URI Cannot open input stream for URI - - Debugger UI operation listener started + + Shizuku UI listener started Default Config diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 9f8241bb8b..b0c5c07d89 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -6191,7 +6191,7 @@ No se puede leer el archivo de imagen: %1$s No se puede decodificar Bitmap desde la URI No se puede abrir el flujo de entrada de la URI - Monitor de operaciones de UI del depurador iniciado + Monitor de operaciones de UI de Shizuku iniciado Configuración predeterminada Configuración %1$s Error al importar: %1$s diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index a4e3fec218..97bf331701 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -6049,7 +6049,7 @@ Tidak dapat mendekode Bitmap dari URI Tidak dapat membuka aliran input URI - Pemantauan aksi UI debugger telah dimulai + Pemantauan aksi UI Shizuku telah dimulai Konfigurasi default Konfigurasi %1$s Gagal mengimpor: %1$s diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index cf0436df8b..440069b6dd 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -7805,7 +7805,7 @@ プロフィール AI アシスタントのフローティングウィンドウ AI アシスタントはバックグラウンドで動作しています - デバッガーによる UI 操作の監視を開始しました + Shizuku による UI 操作の監視を開始しました 設定 %1$s 名前のないタグ ワークスペースをバックアップしています... diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index d148076161..23d3678c09 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -6294,7 +6294,7 @@ 이미지 파일을 읽을 수 없습니다: %1$s URI에서 비트맵을 디코딩할 수 없습니다. URI에 대한 입력 스트림을 열 수 없습니다. - 디버거 UI 작업 리스너가 시작되었습니다. + Shizuku UI 작업 리스너가 시작되었습니다. 기본 구성 %1$s 구성 가져오기 실패: %1$s diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml index 2375a67cad..4630e488a8 100644 --- a/app/src/main/res/values-ms/strings.xml +++ b/app/src/main/res/values-ms/strings.xml @@ -6111,7 +6111,7 @@ Tidak dapat membaca fail imej: %1$s Tidak dapat menyahkod Bitmap dari URI Tidak dapat membuka aliran input URI - Pendengar tindakan UI penyahpepijat telah dimulakan + Pendengar tindakan UI Shizuku telah dimulakan Konfigurasi lalai Konfigurasi %1$s Import gagal: %1$s diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 1fac5d599c..0596632631 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -5772,7 +5772,7 @@ Não foi possível ler o arquivo de imagem: %1$s Não é possível decodificar o bitmap do URI Não foi possível abrir o fluxo de entrada para URI - O monitoramento da operação da IU do depurador foi iniciado + O monitoramento da operação da IU do Shizuku foi iniciado Configuração padrão Configurar %1$s Falha na importação: %1$s diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 3f6e86c131..8e95edc428 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -7300,8 +7300,8 @@ Nu se poate de laURIDecodareBitmap Nu se poate deschideURIfluxul de intrare - - DebuggerUIMonitorizarea operațiunilor a fost activată + + Ascultătorul UI Shizuku a pornit Configurația implicită diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1f25a4090e..01532b9422 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7720,8 +7720,8 @@ 无法从URI解码Bitmap 无法打开URI的输入流 - - 调试器UI操作监听已启动 + + Shizuku UI 监听器已启动 默认配置 diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt index c221b3707d..6fb6590b6f 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt @@ -8,21 +8,21 @@ import org.junit.Test import java.util.Locale class PermissionCapabilitiesTest { - @Test fun userModesAreExactlyThreeAndLegacyNamesMapToAdmin() { + @Test fun userModesAreExactlyThreeAndLegacyNamesAreNotRuntimeModes() { assertEquals(listOf("STANDARD", "ADMIN", "ROOT"), AndroidPermissionLevel.values().map { it.name }) - for (name in listOf("ACCESSIBILITY", "DEBUGGER", "accessibility", "debugger", "ADMIN")) { - assertEquals(AndroidPermissionLevel.ADMIN, AndroidPermissionLevel.fromString(name)) + for (name in listOf("ACCESSIBILITY", "DEBUGGER", "accessibility", "debugger")) { + assertEquals(AndroidPermissionLevel.STANDARD, AndroidPermissionLevel.fromString(name)) } assertEquals(AndroidPermissionLevel.STANDARD, AndroidPermissionLevel.fromString(null)) assertEquals(AndroidPermissionLevel.STANDARD, AndroidPermissionLevel.fromString("unknown")) assertEquals(AndroidPermissionLevel.ROOT, AndroidPermissionLevel.fromString("ROOT")) } - @Test fun legacyNamesDoNotDependOnDeviceLocale() { + @Test fun modeNamesDoNotDependOnDeviceLocale() { val previous = Locale.getDefault() try { Locale.setDefault(Locale.forLanguageTag("tr-TR")) - assertEquals(AndroidPermissionLevel.ADMIN, AndroidPermissionLevel.fromString("accessibility")) + assertEquals(AndroidPermissionLevel.ROOT, AndroidPermissionLevel.fromString("root")) assertEquals(AndroidPermissionLevel.ADMIN, AndroidPermissionLevel.fromString("admin")) } finally { Locale.setDefault(previous) diff --git a/docs/TODO/chore/tools-permissions-layout/01-permissions.md b/docs/TODO/chore/tools-permissions-layout/01-permissions.md new file mode 100644 index 0000000000..9e793884e5 --- /dev/null +++ b/docs/TODO/chore/tools-permissions-layout/01-permissions.md @@ -0,0 +1,25 @@ +# 01 权限实现收口 + +## 原实现与目标 + +用户模式已经是 `STANDARD`、`ADMIN`、`ROOT`,但文件、系统、设备和 UI 工具仍经过无障碍、调试、管理员等历史继承层。目标是让工具实现直接对应实际职责,管理员统一使用已授权的无障碍和 Shizuku,Root 保留自身 UI 行为及现有能力选择。 + +## 修改范围 + +- 文件工具:将调试文件实现与管理员路由合并,直接继承标准文件工具,保留只读与写入操作原有路由。 +- UI 工具:将无障碍操作与 Shell 操作收入管理员工具,显式区分内部操作方法;Root 继续继承管理员实现。 +- 系统工具:管理员直接继承标准实现,承接原 Shell 操作。 +- 设备信息及 Root 文件、系统工具:移除没有独立行为的工具壳,通过现有授权能力选择执行后端。 +- Shell 与操作监听器:将 `Debugger` 实现准确命名为 `Shizuku`,同步工厂、日志和提示。 +- 配置:历史值只由现有 DataStore 迁移入口转换为 `ADMIN`,运行时模式解析只识别三档名称。 +- 回归覆盖:维护现有权限能力组合与偏好迁移测试,交由仓库工作流执行。 + +## 验收 + +- [x] 工具实现中不再存在无障碍等级、调试等级及对应继承层 +- [x] 管理员包含原无障碍和 Shell 操作,Root 保留原操作行为 +- [x] 运行时模式只有标准、管理员、Root,旧偏好可迁移 +- [x] 工具名称、参数和结果格式保持现有契约 +- [x] 静态引用与语法检查完成,操作体迁移逐项对比;仓库验证尚未派发 + +[DONE] 权限收口代码及静态核对完成,运行验证以工作流结果为准。 diff --git a/docs/TODO/chore/tools-permissions-layout/index.md b/docs/TODO/chore/tools-permissions-layout/index.md new file mode 100644 index 0000000000..2f225ef9a8 --- /dev/null +++ b/docs/TODO/chore/tools-permissions-layout/index.md @@ -0,0 +1,29 @@ +--- +fork: https://github.com/3316891527/Operit +status: in-progress +--- +# 工具权限收口与目录整理 + +本次工作先将工具权限实现统一为标准、管理员和 Root 三档,再依据逐文件迁移清单整理工具目录。权限收口与目录迁移分别提交,便于核对行为变化与路径变化。 + +## 当前状况 + +用户可选模式已经是 `STANDARD`、`ADMIN`、`ROOT`,工具实现仍保留 Standard、Accessibility、Debugger、Admin、Root 多层继承。`core.tools.packTool` 的解析、加载、运行、安装、界面 DSL 和元数据文件混合放置,工具的其他目录也需要按职责整理。 + +## 执行顺序 + +1. [权限实现收口](01-permissions.md):删除旧工具等级和无行为的中间层,管理员按实际授权使用无障碍、Shizuku,Root 复用管理员能力。 +2. 目录迁移:读取权限收口后的工具源码,先记录逐文件当前路径、目标路径及目标包名,再按清单迁移并同步引用。 + +迁移清单只记录本次实际迁移的文件。目录整理以保持工具调用接口及现有行为为目标。 + +## 验证与交付 + +记录静态引用、路径、配置及差异检查;本地不执行编译、构建或测试。推送工作分支后先派发仓库工作流,再创建以 `dev` 为目标的 PR。工作流受理与实际运行结果分别记录。 + +## 进度 + +- [x] 权限实现统一为三档,旧配置只在迁移入口识别 +- [ ] 形成逐文件目标路径清单 +- [ ] 完成清单中全部迁移及调用方同步 +- [ ] 完成静态核对、提交、工作流派发与 PR From f33b310ea5791946a7f6d07cbfdd6daa22bedd6d Mon Sep 17 00:00:00 2001 From: kong <135376906+3316891527@users.noreply.github.com> Date: Thu, 29 Oct 2026 12:22:58 +0000 Subject: [PATCH 2/4] =?UTF-8?q?refactor(tools):=20=E6=8C=89=E9=80=90?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=B8=85=E5=8D=95=E6=95=B4=E7=90=86=E5=86=85?= =?UTF-8?q?=E7=BD=AE=E5=B7=A5=E5=85=B7=E4=B8=8E=E6=8F=92=E4=BB=B6=E5=8C=85?= =?UTF-8?q?=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...oolPkgComposeDslWebViewFocusAndroidTest.kt | 2 +- .../media}/ffmpeg/ffmpeg_probe.js | 0 .../standard => builtin/web}/browser/main.js | 0 .../standard => builtin/web}/browser/probe.js | 0 .../bridge_contract/suspend_await.js | 6 +- app/src/main/AndroidManifest.xml | 8 +- .../operit/api/chat/EnhancedAIService.kt | 4 +- .../core/application/OperitApplication.kt | 6 +- .../operit/core/chat/AIMessageManager.kt | 4 +- .../core/chat/context/ConversationService.kt | 6 +- .../protocol/ConversationMarkupManager.kt | 2 +- .../core/chat/tools/ToolExecutionManager.kt | 8 +- .../operit/core/config/SystemPromptConfig.kt | 2 +- .../operit/core/config/SystemToolPrompts.kt | 2 +- .../extraction/ChatMemoryRebuildManager.kt | 2 +- .../extraction/ConversationMemoryExtractor.kt | 2 +- .../extraction/MemoryAutoSaveScheduler.kt | 2 +- .../performance/PerformanceMonitorManager.kt | 2 +- .../operit/core/tools/ToolPackage.kt | 3 +- .../operit/core/tools/agent/PhoneAgent.kt | 6 +- .../{defaultTool => builtin}/ToolGetter.kt | 34 +- .../a2ui/A2uiToolDefinitions.kt | 2 +- .../a2ui/A2uiToolRuntime.kt | 2 +- .../a2ui/A2uiTools.kt | 4 +- .../calculator}/StandardCalculator.kt | 2 +- .../chat}/StandardChatManagerTool.kt | 2 +- .../device}/StandardDeviceInfoToolExecutor.kt | 4 +- .../filesystem}/AdminFileSystemTools.kt | 14 +- .../filesystem}/LinuxFileSystemTools.kt | 8 +- .../filesystem}/PathValidator.kt | 2 +- .../filesystem}/SafFileSystemTools.kt | 6 +- .../filesystem}/StandardFileSystemTools.kt | 9 +- .../media}/BluetoothSessionManager.kt | 2 +- .../media}/StandardFFmpegTool.kt | 4 +- .../media}/StandardMusicPlaybackTools.kt | 2 +- .../memory}/MemoryQueryToolExecutor.kt | 4 +- .../StandardSoftwareSettingsModifyTools.kt | 4 +- .../settings}/ToolPermissionModeSupport.kt | 2 +- .../shell}/ShellCommandSafety.kt | 2 +- .../shell}/StandardShellToolExecutor.kt | 6 +- .../system}/AdminSystemOperationTools.kt | 7 +- .../system}/StandardIntentToolExecutor.kt | 2 +- .../StandardSendBroadcastToolExecutor.kt | 2 +- .../system}/StandardSystemOperationTools.kt | 7 +- .../StandardTerminalCommandExecutor.kt | 4 +- .../admin => builtin/ui}/AdminUITools.kt | 8 +- .../root => builtin/ui}/RootUITools.kt | 6 +- .../ui}/StandardUITools.kt | 10 +- .../web}/CookiePrivacyManager.kt | 2 +- .../web}/StandardBrowserSessionTools.kt | 90 +- .../web}/StandardHttpTools.kt | 2 +- .../web}/StandardWebVisitTool.kt | 4 +- .../browser/BrowserDownloadSupport.kt | 4 +- .../browser/BrowserNavigationPolicy.kt | 2 +- .../browser/BrowserPageExecutionSupport.kt | 4 +- .../session}/browser/BrowserToolSupport.kt | 6 +- .../session}/browser/BrowserWebViewSupport.kt | 6 +- .../session}/browser/WebSessionBrowserHost.kt | 4 +- .../browser/WebSessionBrowserHostState.kt | 4 +- .../browser/WebSessionHistoryStore.kt | 2 +- .../WebSessionPermissionRequestActivity.kt | 2 +- .../session}/browser/WebSessionWebViewHost.kt | 2 +- .../UserscriptCapabilityRegistry.kt | 2 +- .../session}/userscript/UserscriptMatcher.kt | 2 +- .../userscript/UserscriptMetadataParser.kt | 2 +- .../session}/userscript/UserscriptModels.kt | 2 +- .../install/UserscriptImportCoordinator.kt | 2 +- .../install/UserscriptImportPickerActivity.kt | 2 +- .../runtime/UserscriptBootstrapScript.kt | 2 +- .../runtime/UserscriptCookieService.kt | 2 +- .../runtime/UserscriptStorageNotifier.kt | 2 +- .../runtime/UserscriptTabStateStore.kt | 2 +- .../runtime/UserscriptWebRequestEngine.kt | 2 +- .../runtime/WebSessionUserscriptManager.kt | 28 +- .../userscript/storage/UserscriptEntities.kt | 2 +- .../userscript/storage/UserscriptJsonStore.kt | 2 +- .../storage/UserscriptRepository.kt | 30 +- .../ui/WebSessionUserscriptUiStateStore.kt | 12 +- .../workflow}/StandardWorkflowTools.kt | 2 +- .../core/tools/climode/CliToolModeSupport.kt | 2 +- .../javascript/ComposeDslActionRetention.kt | 4 +- .../operit/core/tools/javascript/JsEngine.kt | 14 +- .../javascript/JsNativeInterfaceDelegates.kt | 4 +- .../core/tools/javascript/JsToolManager.kt | 2 +- .../tools/javascript/JsToolPkgRegistration.kt | 8 +- .../operit/core/tools/mcp/MCPToolExecutor.kt | 4 +- .../packTool/PackageDebugRefreshReceiver.kt | 3 +- .../packTool/ToolPkgDebugInstallReceiver.kt | 3 +- .../{ => install}/PackageFileImportSupport.kt | 3 +- .../{ => install}/PackageSourceDeletion.kt | 2 +- .../{ => install}/PackageTemplateFactory.kt | 2 +- .../packTool/{ => loader}/ToolPkgLoadOrder.kt | 5 +- .../packTool/{ => loader}/ToolPkgLoader.kt | 8 +- .../{ => metadata}/BuiltInPackageDefaults.kt | 3 +- .../{ => metadata}/ToolPkgApiVersion.kt | 2 +- .../ToolPkgCommonPluginConstants.kt | 2 +- .../ToolPkgManifestRequirement.kt | 2 +- .../{ => metadata}/ToolPkgMarketOrigin.kt | 2 +- .../{ => metadata}/ToolPkgTemplateModels.kt | 2 +- .../minify/ToolPkgArtifactMinifier.kt | 6 +- .../ToolPkgMainRegistrationScriptParser.kt | 23 +- .../packTool/{ => parser}/ToolPkgParser.kt | 14 +- .../{ => runtime}/PackageActivationResult.kt | 2 +- .../packTool/{ => runtime}/PackageManager.kt | 22 +- .../PackageManagerToolPkgFacade.kt | 9 +- .../{ => runtime}/ToolPkgHookModels.kt | 2 +- .../packTool/{ => runtime}/ToolPkgManager.kt | 6 +- .../{ => runtime}/ToolPkgRuntimeMonitor.kt | 2 +- .../{ => uidsl}/ToolPkgComposeDslParser.kt | 2 +- .../AndroidPermissionLevel.kt | 2 +- .../permissions/PermissionCapabilities.kt | 4 +- .../PermissionCapabilityResolver.kt | 4 +- .../PermissionCapabilitySession.kt | 2 +- .../AccessibilityProviderInstaller.kt | 2 +- .../authorization}/RootAuthorizer.kt | 4 +- .../authorization}/ShizukuAuthorizer.kt | 2 +- .../authorization}/ShizukuInstaller.kt | 2 +- .../core/tools/{ => runtime}/AIToolHandler.kt | 5 +- .../core/tools/{ => runtime}/AIToolHook.kt | 2 +- .../{ => runtime}/ToolExecutionLimits.kt | 2 +- .../tools/{ => runtime}/ToolProgressBus.kt | 2 +- .../tools/{ => runtime}/ToolRegistration.kt | 9 +- .../action/AccessibilityActionListener.kt | 2 +- .../tools/system/action/ActionListener.kt | 2 +- .../system/action/ActionListenerFactory.kt | 2 +- .../core/tools/system/action/ActionManager.kt | 2 +- .../tools/system/action/RootActionListener.kt | 2 +- .../system/action/ShizukuActionListener.kt | 4 +- .../system/action/StandardActionListener.kt | 2 +- .../MediaProjectionCaptureManager.kt | 2 +- .../{ => capture}/MediaProjectionHolder.kt | 2 +- .../{ => capture}/ScreenCaptureActivity.kt | 2 +- .../{ => capture}/ScreenCaptureService.kt | 2 +- .../{ => shell}/AndroidShellExecutor.kt | 3 +- .../tools/system/shell/RootShellExecutor.kt | 4 +- .../core/tools/system/shell/ShellExecutor.kt | 4 +- .../system/shell/ShellExecutorFactory.kt | 2 +- .../system/shell/ShizukuShellExecutor.kt | 6 +- .../system/shell/StandardShellExecutor.kt | 4 +- .../system/shower/OperitShowerShellRunner.kt | 4 +- .../{ => terminal}/OperitTerminalManager.kt | 2 +- .../tools/system/{ => terminal}/Terminal.kt | 2 +- .../uiautomator/UiAutomatorDumpGuard.kt | 2 +- .../operit/core/workflow/WorkflowExecutor.kt | 2 +- .../operit/data/mcp/MCPLocalServer.kt | 2 +- .../operit/data/mcp/MCPRepository.kt | 2 +- .../operit/data/mcp/plugins/MCPBridge.kt | 4 +- .../operit/data/mcp/plugins/MCPDeployer.kt | 4 +- .../data/mcp/plugins/MCPSharedSession.kt | 2 +- .../operit/data/mcp/plugins/MCPStarter.kt | 2 +- .../AndroidPermissionModeMigration.kt | 2 +- .../AndroidPermissionPreferences.kt | 2 +- .../CharacterCardToolAccessResolver.kt | 2 +- .../data/repository/UIHierarchyManager.kt | 2 +- .../data/storage/PackageSkillInventory.kt | 4 +- .../ToolPkgDesktopWidgetConfigActivity.kt | 2 +- .../ToolPkgDesktopWidgetDslRenderer.kt | 10 +- .../appwidget/ToolPkgDesktopWidgetHost.kt | 4 +- .../ExternalChatRequestExecutor.kt | 6 +- .../AppLifecycleHookPluginRegistry.kt | 24 +- .../toolpkg/ToolPkgAiProviderRegistry.kt | 4 +- .../toolpkg/ToolPkgChatInputHookBridge.kt | 6 +- .../toolpkg/ToolPkgChatMessageHookBridge.kt | 6 +- .../ToolPkgChatMessageMenuItemBridge.kt | 8 +- .../toolpkg/ToolPkgChatRuntimeHookBridge.kt | 6 +- .../toolpkg/ToolPkgChatViewHookBridge.kt | 6 +- .../toolpkg/ToolPkgCommonBridgePlugin.kt | 16 +- .../toolpkg/ToolPkgHookBridgeSupport.kt | 6 +- .../plugins/toolpkg/ToolPkgLifecyclePlugin.kt | 6 +- .../toolpkg/ToolPkgPromptHookBridge.kt | 18 +- .../toolpkg/ToolPkgSummaryHookBridge.kt | 6 +- .../toolpkg/ToolPkgToolLifecycleBridge.kt | 12 +- .../toolpkg/ai/ToolPkgJsAiProviderService.kt | 8 +- .../operit/services/ChatServiceCore.kt | 2 +- .../services/TermuxCommandResultService.kt | 2 +- .../services/core/AttachmentDelegate.kt | 4 +- .../core/MessageCoordinationDelegate.kt | 2 +- .../core/MessageProcessingDelegate.kt | 4 +- .../composedsl/ToolPkgComposeDslActions.kt | 2 +- .../ToolPkgComposeDslDebugSnapshotStore.kt | 4 +- .../ToolPkgComposeDslGeneratedRenderers.kt | 4 +- .../composedsl/ToolPkgComposeDslScreen.kt | 10 +- .../composedsl/ToolPkgComposeDslWebView.kt | 4 +- .../markdown/XmlRenderPluginRegistry.kt | 8 +- .../browser/WebSessionBookmarkSheet.kt | 2 +- .../browser/WebSessionBrowserScreen.kt | 16 +- .../browser/WebSessionDownloadSheet.kt | 8 +- .../browser/WebSessionHistorySheet.kt | 4 +- .../websession/browser/WebSessionMenuSheet.kt | 2 +- .../browser/WebSessionMinimizedIndicator.kt | 2 +- .../websession/browser/WebSessionTabSheet.kt | 2 +- .../browser/WebSessionUserscriptSheet.kt | 12 +- .../workflow/screens/WorkflowDetailScreen.kt | 2 +- .../workflow/screens/WorkflowListScreen.kt | 2 +- .../workflow/viewmodel/WorkflowViewModel.kt | 4 +- .../chat/components/AttachmentSelector.kt | 4 +- .../chat/components/SharedFileTargetDialog.kt | 6 +- .../input/agent/AgentChatInputSection.kt | 2 +- .../input/classic/ClassicChatInputSection.kt | 2 +- .../export/htmlpackager/HtmlPackagerScreen.kt | 2 +- .../conversation/chat/screens/AIChatScreen.kt | 2 +- .../chat/viewmodel/ChatViewModel.kt | 4 +- .../chat/webview/LocalWebServer.kt | 2 +- .../chat/webview/WorkspaceFileSelector.kt | 4 +- .../chat/webview/workspace/FileManager.kt | 2 +- .../workspace/WorkspaceBackupManager.kt | 4 +- .../webview/workspace/WorkspaceManager.kt | 2 +- .../WorkspaceReadOnlyDocumentPreview.kt | 2 +- .../chat/webview/workspace/WorkspaceSetup.kt | 4 +- .../browser/WorkspaceBrowserOperations.kt | 2 +- .../workspace/links/WorkspaceFileLinkHost.kt | 2 +- .../process/WorkspaceRuleFileReader.kt | 2 +- .../memory/viewmodel/MemoryViewModel.kt | 2 +- .../workbench/MemoryDocumentImporter.kt | 2 +- .../dialogs/MCPPackageDetailsDialog.kt | 2 +- .../dialogs/PackageAddActionDialog.kt | 2 +- .../packages/dialogs/PackageDetailsDialog.kt | 4 +- .../dialogs/PackageTemplateIdentityDialog.kt | 4 +- .../packages/dialogs/ScriptExecutionDialog.kt | 2 +- .../market/ArtifactLocalInstallSupport.kt | 2 +- .../market/GitHubForgePublishService.kt | 2 +- .../market/MarketEntryInstallController.kt | 4 +- .../packages/market/MarketInstallMarker.kt | 2 +- .../packages/screens/PackageManagerDialogs.kt | 2 +- .../packages/screens/PackageManagerScreen.kt | 12 +- .../packages/screens/PackageSearch.kt | 2 +- .../packages/screens/PluginTabContent.kt | 2 +- .../screens/QuickPluginCreatorSetupSupport.kt | 4 +- .../viewmodel/ArtifactMarketViewModel.kt | 4 +- .../viewmodel/UnifiedMarketBrowseViewModel.kt | 4 +- .../viewmodel/UnifiedMarketDetailViewModel.kt | 4 +- .../resources/hub/ResourceHubViewModel.kt | 2 +- .../components/CharacterCardDialog.kt | 4 +- .../settings/display/DisplayBehaviorState.kt | 2 +- .../toolpermissions/ToolPermissionPage.kt | 2 +- .../ConfigurationResourceStorageScreen.kt | 2 +- .../ConfigurationResourceStorageViewModel.kt | 2 +- .../management/storage/DataStorageScreen.kt | 2 +- .../demo/components/PermissionLevelCard.kt | 4 +- .../support/demo/screens/ShizukuDemoScreen.kt | 8 +- .../support/demo/state/DemoStateManager.kt | 10 +- .../demo/viewmodel/ShizukuDemoViewModel.kt | 4 +- .../uidebugger/UIDebuggerViewModel.kt | 2 +- .../screen/FloatingScreenOcrScreen.kt | 2 +- .../assistance/operit/ui/main/MainActivity.kt | 2 +- .../ai/assistance/operit/ui/main/OperitApp.kt | 4 +- .../ui/main/components/DrawerContent.kt | 6 +- .../ui/main/navigation/AppRouteCatalog.kt | 6 +- ...onversationMarkupManagerResultLimitTest.kt | 2 +- .../a2ui/A2uiToolsTest.kt | 2 +- .../ToolPermissionModeSupportTest.kt | 2 +- .../shell}/ShellCommandSafetyTest.kt | 2 +- .../browser/BrowserNavigationPolicyTest.kt | 2 +- .../ComposeDslActionRetentionTest.kt | 4 +- .../PackageFileImportSupportTest.kt | 2 +- .../PackageSourceDeletionTest.kt | 2 +- .../PackageTemplateFactoryTest.kt | 2 +- .../ToolPkgApiDeclarationTest.kt | 2 +- .../ToolPkgMarketOriginCodecTest.kt | 2 +- .../ToolPkgManifestSelectionTest.kt | 2 +- .../PackageActivationResultTest.kt | 2 +- .../{ => runtime}/ToolPkgManagerTest.kt | 2 +- .../permissions/PermissionCapabilitiesTest.kt | 4 +- .../PermissionCapabilitySessionTest.kt | 2 +- .../PermissionOperationRouterTest.kt | 2 +- .../uiautomator/UiAutomatorDumpGuardTest.kt | 2 +- docs/TODO/chore/README.md | 2 + .../01-permissions.md | 2 +- .../tools-permissions-layout/02-layout.md | 303 +++++ .../chore/tools-permissions-layout/files.json | 1060 +++++++++++++++++ .../chore/tools-permissions-layout/index.md | 15 +- .../tools-permissions-layout/verification.md | 27 + .../architecture/DEFAULT_TOOLS_ARCH.md | 20 +- .../04_modules/android.md | 2 +- .../04_modules/ffmpeg.md | 2 +- .../04_modules/files.md | 8 +- .../04_modules/memory.md | 4 +- .../04_modules/network.md | 8 +- .../04_modules/okhttp.md | 4 +- .../04_modules/system.md | 14 +- .../04_modules/tasker.md | 4 +- .../04_modules/tool-types.md | 2 +- .../04_modules/ui.md | 7 +- .../05_hooks/render_and_toggle.md | 2 +- .../05_hooks/tool_lifecycle.md | 2 +- .../09_compatibility/api_versions.md | 4 +- .../toolpkg_developer_documentation/index.md | 4 +- tools/adb/JS_ADB_README.md | 16 +- tools/adb/JS_ADB_README_zh.md | 20 +- .../verify_layout_completion.py | 2 +- tools/string/count_ui_strings.py | 2 +- 291 files changed, 2172 insertions(+), 588 deletions(-) rename app/src/androidTest/js/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/media}/ffmpeg/ffmpeg_probe.js (100%) rename app/src/androidTest/js/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/web}/browser/main.js (100%) rename app/src/androidTest/js/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/web}/browser/probe.js (100%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool => builtin}/ToolGetter.kt (76%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool => builtin}/a2ui/A2uiToolDefinitions.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool => builtin}/a2ui/A2uiToolRuntime.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool => builtin}/a2ui/A2uiTools.kt (97%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/calculator}/StandardCalculator.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/chat}/StandardChatManagerTool.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/device}/StandardDeviceInfoToolExecutor.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/admin => builtin/filesystem}/AdminFileSystemTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/filesystem}/LinuxFileSystemTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool => builtin/filesystem}/PathValidator.kt (97%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/filesystem}/SafFileSystemTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/filesystem}/StandardFileSystemTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/media}/BluetoothSessionManager.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/media}/StandardFFmpegTool.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/media}/StandardMusicPlaybackTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/memory}/MemoryQueryToolExecutor.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/settings}/StandardSoftwareSettingsModifyTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/settings}/ToolPermissionModeSupport.kt (93%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/shell}/ShellCommandSafety.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/shell}/StandardShellToolExecutor.kt (94%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/admin => builtin/system}/AdminSystemOperationTools.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/system}/StandardIntentToolExecutor.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/system}/StandardSendBroadcastToolExecutor.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/system}/StandardSystemOperationTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/terminal}/StandardTerminalCommandExecutor.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/admin => builtin/ui}/AdminUITools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/root => builtin/ui}/RootUITools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/ui}/StandardUITools.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/web}/CookiePrivacyManager.kt (92%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/web}/StandardBrowserSessionTools.kt (90%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/web}/StandardHttpTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/web}/StandardWebVisitTool.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/BrowserDownloadSupport.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/BrowserNavigationPolicy.kt (96%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/BrowserPageExecutionSupport.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/BrowserToolSupport.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/BrowserWebViewSupport.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/WebSessionBrowserHost.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/WebSessionBrowserHostState.kt (95%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/WebSessionHistoryStore.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/WebSessionPermissionRequestActivity.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/WebSessionWebViewHost.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/UserscriptCapabilityRegistry.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/UserscriptMatcher.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/UserscriptMetadataParser.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/UserscriptModels.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/install/UserscriptImportCoordinator.kt (96%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/install/UserscriptImportPickerActivity.kt (97%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/runtime/UserscriptBootstrapScript.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/runtime/UserscriptCookieService.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/runtime/UserscriptStorageNotifier.kt (88%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/runtime/UserscriptTabStateStore.kt (91%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/runtime/UserscriptWebRequestEngine.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/runtime/WebSessionUserscriptManager.kt (97%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/storage/UserscriptEntities.kt (95%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/storage/UserscriptJsonStore.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/storage/UserscriptRepository.kt (94%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/userscript/ui/WebSessionUserscriptUiStateStore.kt (73%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/workflow}/StandardWorkflowTools.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => install}/PackageFileImportSupport.kt (96%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => install}/PackageSourceDeletion.kt (90%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => install}/PackageTemplateFactory.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => loader}/ToolPkgLoadOrder.kt (96%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => loader}/ToolPkgLoader.kt (89%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/BuiltInPackageDefaults.kt (85%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/ToolPkgApiVersion.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/ToolPkgCommonPluginConstants.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/ToolPkgManifestRequirement.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/ToolPkgMarketOrigin.kt (97%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/ToolPkgTemplateModels.kt (94%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => parser}/ToolPkgMainRegistrationScriptParser.kt (93%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => parser}/ToolPkgParser.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/PackageActivationResult.kt (94%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/PackageManager.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/PackageManagerToolPkgFacade.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/ToolPkgHookModels.kt (95%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/ToolPkgManager.kt (97%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/ToolPkgRuntimeMonitor.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/packTool/{ => uidsl}/ToolPkgComposeDslParser.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{system => permissions}/AndroidPermissionLevel.kt (93%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{system => permissions/authorization}/AccessibilityProviderInstaller.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{system => permissions/authorization}/RootAuthorizer.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{system => permissions/authorization}/ShizukuAuthorizer.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{system => permissions/authorization}/ShizukuInstaller.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{ => runtime}/AIToolHandler.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{ => runtime}/AIToolHook.kt (96%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{ => runtime}/ToolExecutionLimits.kt (86%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{ => runtime}/ToolProgressBus.kt (97%) rename app/src/main/java/com/ai/assistance/operit/core/tools/{ => runtime}/ToolRegistration.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/{ => capture}/MediaProjectionCaptureManager.kt (99%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/{ => capture}/MediaProjectionHolder.kt (92%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/{ => capture}/ScreenCaptureActivity.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/{ => capture}/ScreenCaptureService.kt (98%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/{ => shell}/AndroidShellExecutor.kt (95%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/{ => terminal}/OperitTerminalManager.kt (96%) rename app/src/main/java/com/ai/assistance/operit/core/tools/system/{ => terminal}/Terminal.kt (99%) rename app/src/test/java/com/ai/assistance/operit/core/tools/{defaultTool => builtin}/a2ui/A2uiToolsTest.kt (99%) rename app/src/test/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/settings}/ToolPermissionModeSupportTest.kt (95%) rename app/src/test/java/com/ai/assistance/operit/core/tools/{defaultTool/standard => builtin/shell}/ShellCommandSafetyTest.kt (98%) rename app/src/test/java/com/ai/assistance/operit/core/tools/{defaultTool/websession => builtin/web/session}/browser/BrowserNavigationPolicyTest.kt (98%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => install}/PackageFileImportSupportTest.kt (93%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => install}/PackageSourceDeletionTest.kt (97%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => install}/PackageTemplateFactoryTest.kt (98%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/ToolPkgApiDeclarationTest.kt (94%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => metadata}/ToolPkgMarketOriginCodecTest.kt (97%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => parser}/ToolPkgManifestSelectionTest.kt (96%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/PackageActivationResultTest.kt (97%) rename app/src/test/java/com/ai/assistance/operit/core/tools/packTool/{ => runtime}/ToolPkgManagerTest.kt (98%) create mode 100644 docs/TODO/chore/tools-permissions-layout/02-layout.md create mode 100644 docs/TODO/chore/tools-permissions-layout/files.json create mode 100644 docs/TODO/chore/tools-permissions-layout/verification.md diff --git a/app/src/androidTest/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebViewFocusAndroidTest.kt b/app/src/androidTest/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebViewFocusAndroidTest.kt index ab0285d976..0536322c49 100644 --- a/app/src/androidTest/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebViewFocusAndroidTest.kt +++ b/app/src/androidTest/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebViewFocusAndroidTest.kt @@ -29,7 +29,7 @@ import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Rule diff --git a/app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/ffmpeg/ffmpeg_probe.js b/app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/media/ffmpeg/ffmpeg_probe.js similarity index 100% rename from app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/ffmpeg/ffmpeg_probe.js rename to app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/media/ffmpeg/ffmpeg_probe.js diff --git a/app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/main.js b/app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/main.js similarity index 100% rename from app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/main.js rename to app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/main.js diff --git a/app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/probe.js b/app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/probe.js similarity index 100% rename from app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/probe.js rename to app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/probe.js diff --git a/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract/suspend_await.js b/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract/suspend_await.js index 2a936bdbcf..5b4c5c20af 100644 --- a/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract/suspend_await.js +++ b/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract/suspend_await.js @@ -7,7 +7,7 @@ const { runSuite, } = require('./common'); -const AndroidShellExecutor = Java.com.ai.assistance.operit.core.tools.system.AndroidShellExecutor; +const AndroidShellExecutor = Java.com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor; const StandardActionListener = Java.com.ai.assistance.operit.core.tools.system.action.StandardActionListener; const StreamBuildersKt = Java.type('com.ai.assistance.operit.util.stream.StreamBuildersKt'); @@ -28,7 +28,7 @@ function assertCommandResultProxy(result, label) { assert(result && typeof result === 'object', (label || 'result') + ' should be an object'); assertEq( String(result.className), - 'com.ai.assistance.operit.core.tools.system.AndroidShellExecutor$CommandResult', + 'com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor$CommandResult', (label || 'result') + ' className mismatch' ); assertEq(typeof result.success, 'boolean', (label || 'result') + ' success should be boolean'); @@ -51,7 +51,7 @@ exports.run = async function run() { test('Java.callSuspend awaits companion suspend method and returns proxy result', async () => { const result = await withTimeout( Java.callSuspend( - 'com.ai.assistance.operit.core.tools.system.AndroidShellExecutor', + 'com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor', 'executeShellCommand', 'echo bridge-contract-suspend-top-level' ), diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6bcd5c683f..7e37adc31c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -120,7 +120,7 @@ tools:node="remove" /> @@ -327,7 +327,7 @@ android:foregroundServiceType="dataSync" /> diff --git a/app/src/main/java/com/ai/assistance/operit/api/chat/EnhancedAIService.kt b/app/src/main/java/com/ai/assistance/operit/api/chat/EnhancedAIService.kt index b54aac3afb..13e5687102 100644 --- a/app/src/main/java/com/ai/assistance/operit/api/chat/EnhancedAIService.kt +++ b/app/src/main/java/com/ai/assistance/operit/api/chat/EnhancedAIService.kt @@ -37,11 +37,11 @@ import com.ai.assistance.operit.core.chat.hooks.mergeAdjacentTurns import com.ai.assistance.operit.core.chat.hooks.toPromptTurns import com.ai.assistance.operit.core.chat.hooks.toRoleContentPairs import com.ai.assistance.operit.core.application.ActivityLifecycleManager -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.climode.CliToolModeSupport import com.ai.assistance.operit.core.tools.climode.ToolExposureMode -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilitySession import com.ai.assistance.operit.data.model.FunctionType import com.ai.assistance.operit.data.model.InputProcessingState diff --git a/app/src/main/java/com/ai/assistance/operit/core/application/OperitApplication.kt b/app/src/main/java/com/ai/assistance/operit/core/application/OperitApplication.kt index 72fd4c08d2..e123e36db3 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/application/OperitApplication.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/application/OperitApplication.kt @@ -28,9 +28,9 @@ import com.ai.assistance.operit.plugins.lifecycle.AppLifecycleEvent import com.ai.assistance.operit.plugins.lifecycle.AppLifecycleHookParams import com.ai.assistance.operit.plugins.lifecycle.AppLifecycleHookPluginRegistry import com.ai.assistance.operit.core.config.SystemPromptConfig -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor -import com.ai.assistance.operit.core.tools.system.Terminal +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.terminal.Terminal import com.ai.assistance.operit.core.workflow.WorkflowSchedulerInitializer import com.ai.assistance.operit.data.backup.RoomDatabaseBackupPreferences import com.ai.assistance.operit.data.backup.RoomDatabaseBackupScheduler diff --git a/app/src/main/java/com/ai/assistance/operit/core/chat/AIMessageManager.kt b/app/src/main/java/com/ai/assistance/operit/core/chat/AIMessageManager.kt index d14c9c3012..cc52ba0c22 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/chat/AIMessageManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/chat/AIMessageManager.kt @@ -25,9 +25,9 @@ import com.ai.assistance.operit.core.chat.hooks.PromptTurnKind import com.ai.assistance.operit.core.chat.plugins.MessageProcessingController import com.ai.assistance.operit.core.chat.plugins.MessageProcessingHookParams import com.ai.assistance.operit.core.chat.plugins.MessageProcessingPluginRegistry -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.MemoryQueryResultData -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.AttachmentInfo import com.ai.assistance.operit.data.model.ChatMessage diff --git a/app/src/main/java/com/ai/assistance/operit/core/chat/context/ConversationService.kt b/app/src/main/java/com/ai/assistance/operit/core/chat/context/ConversationService.kt index 95d01e01f2..f6a6dccf7e 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/chat/context/ConversationService.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/chat/context/ConversationService.kt @@ -20,8 +20,8 @@ import com.ai.assistance.operit.core.chat.hooks.toPromptTurns import com.ai.assistance.operit.core.config.SystemPromptConfig import com.ai.assistance.operit.core.tools.climode.ToolExposureMode import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ConversationSummaryConfig import com.ai.assistance.operit.data.model.FunctionType @@ -47,7 +47,7 @@ import com.ai.assistance.operit.util.stream.TextStreamEventType import com.ai.assistance.operit.util.stream.TextStreamRevisionTracker import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch -import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus import com.ai.assistance.operit.util.streamnative.NativeXmlSplitter import com.github.difflib.DiffUtils import com.github.difflib.UnifiedDiffUtils diff --git a/app/src/main/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManager.kt b/app/src/main/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManager.kt index d67bce04fb..a65707cbc0 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManager.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.core.chat.protocol import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.core.chat.media.MediaLinkParser -import com.ai.assistance.operit.core.tools.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.runtime.ToolExecutionLimits import com.ai.assistance.operit.core.chat.protocol.ChatMarkupRegex import com.ai.assistance.operit.util.media.ImagePoolManager import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/chat/tools/ToolExecutionManager.kt b/app/src/main/java/com/ai/assistance/operit/core/chat/tools/ToolExecutionManager.kt index 30414ad50e..51aa2eaa1e 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/chat/tools/ToolExecutionManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/chat/tools/ToolExecutionManager.kt @@ -5,16 +5,16 @@ import com.ai.assistance.operit.ui.common.a2ui.CardFences import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.AIToolHookDecision +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHookDecision import com.ai.assistance.operit.core.chat.protocol.toolFailurePayload import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutor +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor import com.ai.assistance.operit.core.tools.climode.CliToolModeSupport import com.ai.assistance.operit.core.tools.climode.ToolExposureMode import com.ai.assistance.operit.data.model.ToolInvocation import com.ai.assistance.operit.data.model.ToolResult -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilitySession import com.ai.assistance.operit.util.stream.StreamCollector diff --git a/app/src/main/java/com/ai/assistance/operit/core/config/SystemPromptConfig.kt b/app/src/main/java/com/ai/assistance/operit/core/config/SystemPromptConfig.kt index 431fe5f31b..b312156562 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/config/SystemPromptConfig.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/config/SystemPromptConfig.kt @@ -6,7 +6,7 @@ import com.ai.assistance.operit.core.chat.hooks.PromptHookContext import com.ai.assistance.operit.core.chat.hooks.PromptHookRegistry import com.ai.assistance.operit.core.tools.climode.CliToolModeSupport import com.ai.assistance.operit.core.tools.climode.ToolExposureMode -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.preferences.ApiPreferences import com.ai.assistance.operit.data.skill.SkillRepository import com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace.process.WorkspaceRuleFileReader diff --git a/app/src/main/java/com/ai/assistance/operit/core/config/SystemToolPrompts.kt b/app/src/main/java/com/ai/assistance/operit/core/config/SystemToolPrompts.kt index 4315712ae1..edeb081ae1 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/config/SystemToolPrompts.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/config/SystemToolPrompts.kt @@ -5,7 +5,7 @@ import com.ai.assistance.operit.core.chat.hooks.PromptHookRegistry import com.ai.assistance.operit.data.model.SystemToolPromptCategory import com.ai.assistance.operit.data.model.ToolPrompt import com.ai.assistance.operit.data.model.ToolParameterSchema -import com.ai.assistance.operit.core.tools.defaultTool.a2ui.A2uiToolDefinitions +import com.ai.assistance.operit.core.tools.builtin.a2ui.A2uiToolDefinitions /** * 系统工具提示词管理器 diff --git a/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ChatMemoryRebuildManager.kt b/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ChatMemoryRebuildManager.kt index aaa3b94dae..11d84d4dca 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ChatMemoryRebuildManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ChatMemoryRebuildManager.kt @@ -4,7 +4,7 @@ import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.data.memory.resolveChatMemorySpaceId import com.ai.assistance.operit.api.chat.EnhancedAIService -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.ChatHistory import com.ai.assistance.operit.data.model.FunctionType import com.ai.assistance.operit.data.preferences.CharacterCardManager diff --git a/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ConversationMemoryExtractor.kt b/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ConversationMemoryExtractor.kt index d3d217f165..0e615451a3 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ConversationMemoryExtractor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/ConversationMemoryExtractor.kt @@ -6,7 +6,7 @@ import com.ai.assistance.operit.core.chat.protocol.ChatMarkupRegex import com.ai.assistance.operit.core.chat.protocol.ThinkingMarkup import com.ai.assistance.operit.R import com.ai.assistance.operit.api.chat.AIService -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.Memory import com.ai.assistance.operit.data.preferences.ApiPreferences import com.ai.assistance.operit.data.preferences.MemorySearchSettingsPreferences diff --git a/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/MemoryAutoSaveScheduler.kt b/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/MemoryAutoSaveScheduler.kt index 85d42a41a7..6006e40ba9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/MemoryAutoSaveScheduler.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/memory/extraction/MemoryAutoSaveScheduler.kt @@ -2,7 +2,7 @@ package com.ai.assistance.operit.core.memory.extraction import android.content.Context import com.ai.assistance.operit.api.chat.EnhancedAIService -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.db.AppDatabase import com.ai.assistance.operit.data.model.FunctionType import com.ai.assistance.operit.data.model.MemoryAutoSaveCandidate diff --git a/app/src/main/java/com/ai/assistance/operit/core/performance/PerformanceMonitorManager.kt b/app/src/main/java/com/ai/assistance/operit/core/performance/PerformanceMonitorManager.kt index 702c260e73..5a3c703622 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/performance/PerformanceMonitorManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/performance/PerformanceMonitorManager.kt @@ -8,7 +8,7 @@ import android.os.Process import android.os.SystemClock import android.system.Os import android.system.OsConstants -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.terminal.TerminalManager import com.ai.assistance.operit.util.logging.AppLogger import java.io.File diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolPackage.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/ToolPackage.kt index 362a87c8d5..69916a97b1 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolPackage.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/ToolPackage.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.core.tools import android.content.Context import android.os.Build import com.ai.assistance.operit.core.tools.javascript.JsToolManager - import com.ai.assistance.operit.core.tools.packTool.PackageManager + import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.data.model.ToolValidationResult @@ -32,6 +32,7 @@ import kotlinx.serialization.json.JsonPrimitive import kotlinx.coroutines.runBlocking import kotlinx.coroutines.flow.last import java.util.Locale +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor /** * Represents a package of tools that can be imported by the AI diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/agent/PhoneAgent.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/agent/PhoneAgent.kt index d91d03440b..111f45cd7f 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/agent/PhoneAgent.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/agent/PhoneAgent.kt @@ -13,11 +13,11 @@ import androidx.core.content.FileProvider import com.ai.assistance.operit.R import com.ai.assistance.operit.api.chat.AIService import com.ai.assistance.operit.core.chat.hooks.toPromptTurns -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.AppListData -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardUITools +import com.ai.assistance.operit.core.tools.builtin.ui.StandardUITools import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ToolGetter.kt similarity index 76% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ToolGetter.kt index 91ea22b74b..3e428564ec 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ToolGetter.kt @@ -1,11 +1,35 @@ -package com.ai.assistance.operit.core.tools.defaultTool +package com.ai.assistance.operit.core.tools.builtin import android.content.Context -import com.ai.assistance.operit.core.tools.defaultTool.admin.* -import com.ai.assistance.operit.core.tools.defaultTool.root.* -import com.ai.assistance.operit.core.tools.defaultTool.standard.* -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel + + + +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.preferences.androidPermissionPreferences +import com.ai.assistance.operit.core.tools.builtin.calculator.StandardCalculator +import com.ai.assistance.operit.core.tools.builtin.chat.StandardChatManagerTool +import com.ai.assistance.operit.core.tools.builtin.device.StandardDeviceInfoToolExecutor +import com.ai.assistance.operit.core.tools.builtin.filesystem.AdminFileSystemTools +import com.ai.assistance.operit.core.tools.builtin.filesystem.StandardFileSystemTools +import com.ai.assistance.operit.core.tools.builtin.media.StandardFFmpegConvertToolExecutor +import com.ai.assistance.operit.core.tools.builtin.media.StandardFFmpegInfoToolExecutor +import com.ai.assistance.operit.core.tools.builtin.media.StandardFFmpegToolExecutor +import com.ai.assistance.operit.core.tools.builtin.media.StandardMusicPlaybackTools +import com.ai.assistance.operit.core.tools.builtin.memory.MemoryQueryToolExecutor +import com.ai.assistance.operit.core.tools.builtin.settings.StandardSoftwareSettingsModifyTools +import com.ai.assistance.operit.core.tools.builtin.shell.StandardShellToolExecutor +import com.ai.assistance.operit.core.tools.builtin.system.AdminSystemOperationTools +import com.ai.assistance.operit.core.tools.builtin.system.StandardIntentToolExecutor +import com.ai.assistance.operit.core.tools.builtin.system.StandardSendBroadcastToolExecutor +import com.ai.assistance.operit.core.tools.builtin.system.StandardSystemOperationTools +import com.ai.assistance.operit.core.tools.builtin.terminal.StandardTerminalCommandExecutor +import com.ai.assistance.operit.core.tools.builtin.ui.AdminUITools +import com.ai.assistance.operit.core.tools.builtin.ui.RootUITools +import com.ai.assistance.operit.core.tools.builtin.ui.StandardUITools +import com.ai.assistance.operit.core.tools.builtin.web.StandardBrowserSessionTools +import com.ai.assistance.operit.core.tools.builtin.web.StandardHttpTools +import com.ai.assistance.operit.core.tools.builtin.web.StandardWebVisitTool +import com.ai.assistance.operit.core.tools.builtin.workflow.StandardWorkflowTools /** 工具获取器 - 根据三档用户模式获取工具,管理员工具在操作时按实际授权选择后端 */ object ToolGetter { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolDefinitions.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolDefinitions.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolDefinitions.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolDefinitions.kt index d283c69673..edbd97302a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolDefinitions.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolDefinitions.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.a2ui +package com.ai.assistance.operit.core.tools.builtin.a2ui import com.ai.assistance.operit.data.model.SystemToolPromptCategory import com.ai.assistance.operit.data.model.ToolParameterSchema diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolRuntime.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolRuntime.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolRuntime.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolRuntime.kt index 84495736e1..6c64e67e41 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolRuntime.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolRuntime.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.a2ui +package com.ai.assistance.operit.core.tools.builtin.a2ui import com.ai.assistance.operit.core.chat.tools.ToolExecutionManager.ToolRuntimeContext import com.ai.assistance.operit.ui.common.a2ui.CardDelivery diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiTools.kt similarity index 97% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiTools.kt index 0078867906..16478c4916 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiTools.kt @@ -1,8 +1,8 @@ -package com.ai.assistance.operit.core.tools.defaultTool.a2ui +package com.ai.assistance.operit.core.tools.builtin.a2ui import android.content.Context import com.ai.assistance.operit.core.chat.tools.ToolExecutionManager -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardCalculator.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/calculator/StandardCalculator.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardCalculator.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/calculator/StandardCalculator.kt index ec75b62e78..7bec4ed615 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardCalculator.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/calculator/StandardCalculator.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.calculator import com.ai.assistance.operit.core.tools.CalculationResultData import com.ai.assistance.operit.core.tools.DateResultData diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardChatManagerTool.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/chat/StandardChatManagerTool.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardChatManagerTool.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/chat/StandardChatManagerTool.kt index 833313a5e9..2d733388d1 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardChatManagerTool.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/chat/StandardChatManagerTool.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.chat import android.content.ComponentName import android.content.Context diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardDeviceInfoToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/device/StandardDeviceInfoToolExecutor.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardDeviceInfoToolExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/device/StandardDeviceInfoToolExecutor.kt index d12b500507..324edf4612 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardDeviceInfoToolExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/device/StandardDeviceInfoToolExecutor.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.device import android.content.Context import android.content.Intent @@ -10,7 +10,7 @@ import android.os.StatFs import android.provider.Settings import com.ai.assistance.operit.core.tools.DeviceInfoResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutor +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/AdminFileSystemTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/AdminFileSystemTools.kt index 2d043eb36a..0c03afbffa 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/AdminFileSystemTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.admin +package com.ai.assistance.operit.core.tools.builtin.filesystem import android.content.ActivityNotFoundException import android.content.ClipData @@ -7,7 +7,7 @@ import android.content.Intent import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import com.ai.assistance.operit.BuildConfig -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.DirectoryListingData import com.ai.assistance.operit.core.tools.FileContentData import com.ai.assistance.operit.core.tools.FileExistsData @@ -16,13 +16,13 @@ import com.ai.assistance.operit.core.tools.FileOperationData import com.ai.assistance.operit.core.tools.FilePartContentData import com.ai.assistance.operit.core.tools.FindFilesResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutionLimits -import com.ai.assistance.operit.core.tools.ToolProgressBus -import com.ai.assistance.operit.core.tools.defaultTool.PathValidator -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardFileSystemTools +import com.ai.assistance.operit.core.tools.runtime.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus +import com.ai.assistance.operit.core.tools.builtin.filesystem.PathValidator +import com.ai.assistance.operit.core.tools.builtin.filesystem.StandardFileSystemTools import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver import com.ai.assistance.operit.core.tools.permissions.PermissionOperationRouter -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/LinuxFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/LinuxFileSystemTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/LinuxFileSystemTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/LinuxFileSystemTools.kt index 1a940dd0c1..0d72b5e90b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/LinuxFileSystemTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/LinuxFileSystemTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.filesystem import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger @@ -12,13 +12,13 @@ import com.ai.assistance.operit.core.tools.FilePartContentData import com.ai.assistance.operit.core.tools.FindFilesResultData import com.ai.assistance.operit.core.tools.GrepResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolProgressBus -import com.ai.assistance.operit.core.tools.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolExecutionLimits import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.util.files.FileUtils -import com.ai.assistance.operit.core.tools.defaultTool.PathValidator +import com.ai.assistance.operit.core.tools.builtin.filesystem.PathValidator import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Semaphore diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/PathValidator.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/PathValidator.kt similarity index 97% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/PathValidator.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/PathValidator.kt index 1055033993..450b182625 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/PathValidator.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/PathValidator.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool +package com.ai.assistance.operit.core.tools.builtin.filesystem import com.ai.assistance.operit.core.tools.FileOperationData import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/SafFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/SafFileSystemTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/SafFileSystemTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/SafFileSystemTools.kt index 4d74aa97a8..ec3d5c5c5e 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/SafFileSystemTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/SafFileSystemTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.filesystem import android.content.Context import android.database.Cursor @@ -16,8 +16,8 @@ import com.ai.assistance.operit.core.tools.FilePartContentData import com.ai.assistance.operit.core.tools.FindFilesResultData import com.ai.assistance.operit.core.tools.GrepResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutionLimits -import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.data.preferences.ApiPreferences diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFileSystemTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/StandardFileSystemTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFileSystemTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/StandardFileSystemTools.kt index 59f36e65c8..15f117263b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFileSystemTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/StandardFileSystemTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.filesystem import android.content.Context import com.ai.assistance.operit.R @@ -16,10 +16,10 @@ import com.ai.assistance.operit.core.tools.FileInfoData import com.ai.assistance.operit.core.tools.FileOperationData import com.ai.assistance.operit.core.tools.FilePartContentData import com.ai.assistance.operit.core.tools.FindFilesResultData -import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus import com.ai.assistance.operit.core.tools.GrepResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.runtime.ToolExecutionLimits import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.FunctionType import com.ai.assistance.operit.data.model.ModelParameter @@ -70,11 +70,12 @@ import com.ai.assistance.operit.data.preferences.ModelConfigManager import com.ai.assistance.operit.terminal.TerminalManager import com.ai.assistance.operit.terminal.provider.filesystem.FileSystemProvider import com.ai.assistance.operit.terminal.utils.SSHFileConnectionManager -import com.ai.assistance.operit.core.tools.defaultTool.PathValidator +import com.ai.assistance.operit.core.tools.builtin.filesystem.PathValidator import com.ai.assistance.operit.util.android.LocaleUtils import com.ai.assistance.operit.util.ripgrep.NativeRipgrep import org.json.JSONObject import java.util.concurrent.atomic.AtomicInteger +import com.ai.assistance.operit.core.tools.builtin.web.StandardWebVisitTool /** * Collection of file system operation tools for the AI assistant These tools use Java File APIs for diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/BluetoothSessionManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/BluetoothSessionManager.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/BluetoothSessionManager.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/BluetoothSessionManager.kt index faf52c5b17..d8e57e11f5 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/BluetoothSessionManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/BluetoothSessionManager.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.media import android.annotation.SuppressLint import android.bluetooth.BluetoothAdapter diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFFmpegTool.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardFFmpegTool.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFFmpegTool.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardFFmpegTool.kt index 1eff9787c6..a7e8b7d9fb 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFFmpegTool.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardFFmpegTool.kt @@ -1,9 +1,9 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.media import android.content.Context import com.ai.assistance.operit.core.tools.FFmpegResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutor +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.data.model.ToolValidationResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardMusicPlaybackTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardMusicPlaybackTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardMusicPlaybackTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardMusicPlaybackTools.kt index 94e9c14345..afef6c25fc 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardMusicPlaybackTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardMusicPlaybackTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.media import android.content.Context import android.net.Uri diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/MemoryQueryToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/memory/MemoryQueryToolExecutor.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/MemoryQueryToolExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/memory/MemoryQueryToolExecutor.kt index d815301332..485ccd28f6 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/MemoryQueryToolExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/memory/MemoryQueryToolExecutor.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.memory import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger @@ -7,7 +7,7 @@ import com.ai.assistance.operit.core.tools.MemoryQueryResultData import com.ai.assistance.operit.core.tools.MemoryLinkResultData import com.ai.assistance.operit.core.tools.MemoryLinkQueryResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutor +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.CharacterCardMemoryProfileBindingMode import com.ai.assistance.operit.data.model.Memory diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSoftwareSettingsModifyTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/StandardSoftwareSettingsModifyTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSoftwareSettingsModifyTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/StandardSoftwareSettingsModifyTools.kt index aa6cbf0d33..1361d4a399 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSoftwareSettingsModifyTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/StandardSoftwareSettingsModifyTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.settings import com.ai.assistance.operit.data.model.ModelConfigDefaults @@ -49,7 +49,7 @@ import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.ToolPermissionModeResultData import com.ai.assistance.operit.core.tools.javascript.JsEngine import com.ai.assistance.operit.core.tools.javascript.JsExecutionTraceRecorder -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ApiProviderType import com.ai.assistance.operit.data.model.CharacterCard diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupport.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupport.kt similarity index 93% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupport.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupport.kt index a4f9ceae01..b8f66c5183 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupport.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.settings import com.ai.assistance.operit.core.tools.ToolPermissionModeResultData import com.ai.assistance.operit.ui.permissions.PermissionLevel diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafety.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafety.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafety.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafety.kt index b8baf82689..3cb5081408 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafety.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafety.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.shell /** * Lightweight shell command safety validator. diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardShellToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/StandardShellToolExecutor.kt similarity index 94% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardShellToolExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/StandardShellToolExecutor.kt index 2b6152ab4c..86941a73fa 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardShellToolExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/StandardShellToolExecutor.kt @@ -1,11 +1,11 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.shell import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.core.tools.ADBResultData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor -import com.ai.assistance.operit.core.tools.system.ShizukuAuthorizer +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuAuthorizer import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.data.model.ToolValidationResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/AdminSystemOperationTools.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/AdminSystemOperationTools.kt index 101d5a2fe1..2697ad5b7b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/AdminSystemOperationTools.kt @@ -1,16 +1,17 @@ -package com.ai.assistance.operit.core.tools.defaultTool.admin +package com.ai.assistance.operit.core.tools.builtin.system import android.content.Context import com.ai.assistance.operit.core.tools.AppOperationData import com.ai.assistance.operit.core.tools.NotificationData import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.SystemSettingData -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardSystemOperationTools +import com.ai.assistance.operit.core.tools.builtin.system.StandardSystemOperationTools import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.util.logging.AppLogger +import com.ai.assistance.operit.core.tools.builtin.filesystem.AdminFileSystemTools /** 管理员系统工具按现有授权能力执行 Shell 或标准系统操作。 */ open class AdminSystemOperationTools(private val context: Context) : StandardSystemOperationTools(context) { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardIntentToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardIntentToolExecutor.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardIntentToolExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardIntentToolExecutor.kt index 7769c1c058..82113cabdc 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardIntentToolExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardIntentToolExecutor.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.system import android.content.Context import android.content.Intent diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSendBroadcastToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSendBroadcastToolExecutor.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSendBroadcastToolExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSendBroadcastToolExecutor.kt index 12a6f42c46..f4811413fb 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSendBroadcastToolExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSendBroadcastToolExecutor.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.system import android.content.Context import android.content.Intent diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSystemOperationTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSystemOperationTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSystemOperationTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSystemOperationTools.kt index c451619304..109aac3044 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSystemOperationTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSystemOperationTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.system import com.ai.assistance.operit.ui.common.oktoast.OKToast @@ -30,8 +30,8 @@ import com.ai.assistance.operit.core.tools.LocationData import com.ai.assistance.operit.core.tools.NotificationData import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.SystemSettingData -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionPermissionRequestCoordinator -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionPermissionRequestCoordinator +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import java.util.Locale @@ -53,6 +53,7 @@ import com.ai.assistance.operit.services.notification.OperitNotificationStore import com.ai.assistance.operit.R import com.ai.assistance.operit.util.files.AndroidUserPathUtils import com.ai.assistance.operit.util.files.OperitPaths +import com.ai.assistance.operit.core.tools.builtin.media.BluetoothSessionManager /** 提供系统级操作的工具类 包括系统设置修改、应用安装和卸载等 这些操作需要用户明确授权 */ open class StandardSystemOperationTools(private val context: Context) { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardTerminalCommandExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/terminal/StandardTerminalCommandExecutor.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardTerminalCommandExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/terminal/StandardTerminalCommandExecutor.kt index 620c41aee4..c295ca9100 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardTerminalCommandExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/terminal/StandardTerminalCommandExecutor.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.terminal import android.content.Context import com.ai.assistance.operit.R @@ -6,7 +6,7 @@ import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.core.tools.* import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult -import com.ai.assistance.operit.core.tools.system.Terminal +import com.ai.assistance.operit.core.tools.system.terminal.Terminal import com.ai.assistance.operit.terminal.provider.type.HiddenExecResult import com.ai.assistance.operit.terminal.view.domain.ansi.TerminalChar import kotlinx.coroutines.* diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/AdminUITools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/AdminUITools.kt index e51a064513..48ee3bda6d 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/AdminUITools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.admin +package com.ai.assistance.operit.core.tools.builtin.ui import android.annotation.SuppressLint import android.content.ClipData @@ -10,10 +10,10 @@ import com.ai.assistance.operit.core.tools.SimplifiedUINode import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.UIActionResultData import com.ai.assistance.operit.core.tools.UIPageResultData -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardUITools +import com.ai.assistance.operit.core.tools.builtin.ui.StandardUITools import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity import com.ai.assistance.operit.core.tools.system.uiautomator.UiAutomatorDumpGuard import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/RootUITools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/RootUITools.kt index f0b52dbd44..b25d28e443 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/RootUITools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.root +package com.ai.assistance.operit.core.tools.builtin.ui import android.content.ClipData import android.content.ClipboardManager @@ -8,9 +8,9 @@ import com.ai.assistance.operit.core.tools.SimplifiedUINode import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.UIActionResultData import com.ai.assistance.operit.core.tools.UIPageResultData -import com.ai.assistance.operit.core.tools.defaultTool.admin.AdminUITools +import com.ai.assistance.operit.core.tools.builtin.ui.AdminUITools import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/StandardUITools.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/StandardUITools.kt index 8df2c40517..405d969f82 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/StandardUITools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.ui import android.content.Context import android.graphics.Bitmap @@ -12,10 +12,10 @@ import com.ai.assistance.operit.core.tools.SimplifiedUINode import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.UIPageResultData import com.ai.assistance.operit.core.tools.AppListData -import com.ai.assistance.operit.core.tools.defaultTool.ToolGetter -import com.ai.assistance.operit.core.tools.system.MediaProjectionCaptureManager -import com.ai.assistance.operit.core.tools.system.MediaProjectionHolder -import com.ai.assistance.operit.core.tools.system.ScreenCaptureActivity +import com.ai.assistance.operit.core.tools.builtin.ToolGetter +import com.ai.assistance.operit.core.tools.system.capture.MediaProjectionCaptureManager +import com.ai.assistance.operit.core.tools.system.capture.MediaProjectionHolder +import com.ai.assistance.operit.core.tools.system.capture.ScreenCaptureActivity import kotlinx.coroutines.delay import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.FunctionType diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/CookiePrivacyManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/CookiePrivacyManager.kt similarity index 92% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/CookiePrivacyManager.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/CookiePrivacyManager.kt index 34ec15bc3c..350c0e9e82 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/CookiePrivacyManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/CookiePrivacyManager.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.web import android.webkit.CookieManager import kotlin.coroutines.resume diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardBrowserSessionTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardBrowserSessionTools.kt similarity index 90% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardBrowserSessionTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardBrowserSessionTools.kt index 7ebd2565d6..3f7b495d4d 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardBrowserSessionTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardBrowserSessionTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.web import com.ai.assistance.operit.ui.common.oktoast.OKToast @@ -41,11 +41,11 @@ import android.webkit.WebViewClient import com.ai.assistance.operit.R import com.ai.assistance.operit.core.application.ActivityLifecycleManager import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutor -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.* -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallSourceType -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime.WebSessionUserscriptManager -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage.UserscriptRepository +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor + +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallSourceType +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime.WebSessionUserscriptManager +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage.UserscriptRepository import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.util.logging.AppLogger @@ -69,6 +69,84 @@ import kotlinx.coroutines.runBlocking import androidx.core.content.ContextCompat import org.json.JSONArray import org.json.JSONObject +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserConsoleEntry +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserNavigationPolicy +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserNetworkRequestEntry +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserPageRegistry +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserSnapshot +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.PendingAsyncJsCall +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.PendingDialog +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.PendingExternalOpenRequest +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebDownloadEvent +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionBrowserHost +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionHistoryStore +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.activateSessionOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.applyViewportOverride +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.boolParam +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.browserRefResolverScript +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.buildBrowserResponse +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.buildClickCode +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.buildPageRegistry +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.buildSettledBrowserResponse +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.buildWaitForCode +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.captureActionMarkers +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.captureSnapshotModel +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.captureSnapshotText +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.closeSession +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.createSessionTabOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.currentTabIndex +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.ensureDesktopModeInitialized +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.ensureOverlayPermission +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.ensureSessionAttachedOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.error +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.evaluateJavascriptAsync +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.evaluatePageFunction +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.extractAsyncJsValue +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.fillFormFields +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.formatBrowserFileLink +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.getSession +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.handleUserscriptDownloadOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.initializeBrowserDownloadSupport +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.intParam +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.latestBrowserDownloadEventAfter +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.latestSnapshot +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.locatorExpressionForRef +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.navigateSessionOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.notifySessionStateChanged +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.ok +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.openUserscriptSheetOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.openUserscriptTabOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.orderedSessionIds +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.pageError +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.param +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.parseFormFields +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.parseHeaders +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.parseStringArrayParam +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.pressKeyOnPage +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.quoteJsCode +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.refreshNavigationStateAsync +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.refreshSessionUiOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.renderAllConsoleMessages +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.renderJsArrayCode +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.renderManagedDownloads +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.renderModalState +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.renderNetworkRequestLog +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.renderOpenTabs +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.renderPageState +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.requireSnapshotNode +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.resolveElementRect +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.resolvePendingDialogOnMain +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.resolvePreferredSessionId +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.runPlaywrightLikeCode +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.selectOptionsByRef +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.sessionById +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.sessionIdAtIndex +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.settleBrowserAction +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.takeScreenshot +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.typeIntoElementByRef +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.waitForDocumentReady +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.waitForTextState +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.writeBrowserTextOutput class StandardBrowserSessionTools(internal val context: Context) : ToolExecutor { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardHttpTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardHttpTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardHttpTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardHttpTools.kt index d07f88e73e..f575a87f7e 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardHttpTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardHttpTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.web import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWebVisitTool.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardWebVisitTool.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWebVisitTool.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardWebVisitTool.kt index 74bb0ddf71..cdcdc90720 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWebVisitTool.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardWebVisitTool.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.web import android.content.Context import android.graphics.Color as AndroidColor @@ -67,7 +67,7 @@ import androidx.savedstate.SavedStateRegistryOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner import com.ai.assistance.operit.R import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutor +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor import com.ai.assistance.operit.core.tools.VisitWebResultData import com.ai.assistance.operit.data.preferences.DisplayPreferencesManager import com.ai.assistance.operit.data.model.AITool diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserDownloadSupport.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserDownloadSupport.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserDownloadSupport.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserDownloadSupport.kt index 869c159637..db3f45711c 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserDownloadSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserDownloadSupport.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import com.ai.assistance.operit.ui.common.oktoast.OKToast @@ -10,7 +10,7 @@ import android.os.Environment import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import com.ai.assistance.operit.core.application.ActivityLifecycleManager -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardBrowserSessionTools +import com.ai.assistance.operit.core.tools.builtin.web.StandardBrowserSessionTools import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.util.network.HttpMultiPartDownloader import java.io.File diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicy.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicy.kt similarity index 96% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicy.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicy.kt index e15df71a2c..4c5e2499fd 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicy.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicy.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser /** 自动开窗按文档限流;外部请求的抑制跨重定向保留,用户主动操作仍可重试。 */ internal class BrowserNavigationPolicy { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserPageExecutionSupport.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserPageExecutionSupport.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserPageExecutionSupport.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserPageExecutionSupport.kt index 8274eee0f2..9e73576753 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserPageExecutionSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserPageExecutionSupport.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import com.ai.assistance.operit.ui.common.oktoast.OKToast @@ -20,7 +20,7 @@ import android.webkit.URLUtil import android.webkit.WebView import com.ai.assistance.operit.R import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardBrowserSessionTools +import com.ai.assistance.operit.core.tools.builtin.web.StandardBrowserSessionTools import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.util.logging.AppLogger diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserToolSupport.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserToolSupport.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserToolSupport.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserToolSupport.kt index 122b01882b..08f703a83a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserToolSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserToolSupport.kt @@ -1,10 +1,10 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import android.webkit.JsPromptResult import android.webkit.JsResult import android.webkit.WebResourceRequest import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardBrowserSessionTools +import com.ai.assistance.operit.core.tools.builtin.web.StandardBrowserSessionTools import java.util.Locale import java.util.concurrent.CountDownLatch import org.json.JSONArray @@ -193,7 +193,7 @@ internal fun StandardBrowserSessionTools.recordNetworkRequest( val headers = request.requestHeaders?.mapKeys { it.key ?: "" } ?: emptyMap() val acceptHeader = headers.entries.firstOrNull { it.key.equals("Accept", ignoreCase = true) }?.value val entry = - com.ai.assistance.operit.core.tools.defaultTool.websession.browser.BrowserNetworkRequestEntry( + com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserNetworkRequestEntry( method = request.method.orEmpty().ifBlank { "GET" }, url = url, isMainFrame = request.isForMainFrame, diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserWebViewSupport.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserWebViewSupport.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserWebViewSupport.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserWebViewSupport.kt index 063b3090ce..4bec95d159 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserWebViewSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserWebViewSupport.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import com.ai.assistance.operit.ui.common.oktoast.OKToast @@ -31,8 +31,8 @@ import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewFeature import com.ai.assistance.operit.R import com.ai.assistance.operit.core.application.ActivityLifecycleManager -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardBrowserSessionTools -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallSourceType +import com.ai.assistance.operit.core.tools.builtin.web.StandardBrowserSessionTools +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallSourceType import com.ai.assistance.operit.util.logging.AppLogger import java.util.LinkedHashSet import java.util.Locale diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHost.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHost.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHost.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHost.kt index 12c97a6282..c5e3b3cc25 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHost.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHost.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import com.ai.assistance.operit.ui.common.oktoast.OKToast @@ -38,7 +38,7 @@ import androidx.savedstate.SavedStateRegistryController import androidx.savedstate.SavedStateRegistryOwner import androidx.savedstate.setViewTreeSavedStateRegistryOwner import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ui.WebSessionUserscriptUiStateStore +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ui.WebSessionUserscriptUiStateStore import com.ai.assistance.operit.ui.features.automation.websession.browser.WebSessionBrowserScreen import com.ai.assistance.operit.ui.features.automation.websession.browser.WebSessionFloatingTheme import com.ai.assistance.operit.ui.features.automation.websession.browser.WebSessionMinimizedIndicator diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHostState.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHostState.kt similarity index 95% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHostState.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHostState.kt index 0ce2e9ae88..05fcfb6047 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHostState.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHostState.kt @@ -1,7 +1,7 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import androidx.compose.runtime.Immutable -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageMenuCommand +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageMenuCommand import kotlinx.serialization.Serializable internal enum class WebSessionBrowserSheetRoute { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionHistoryStore.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionHistoryStore.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionHistoryStore.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionHistoryStore.kt index 1597351317..79fde8654d 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionHistoryStore.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionHistoryStore.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import android.content.Context import android.net.Uri diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionPermissionRequestActivity.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionPermissionRequestActivity.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionPermissionRequestActivity.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionPermissionRequestActivity.kt index c1308c13f0..483876924b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionPermissionRequestActivity.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionPermissionRequestActivity.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import android.content.Context import android.content.Intent diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionWebViewHost.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionWebViewHost.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionWebViewHost.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionWebViewHost.kt index a5531f81b0..ecce49dedc 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionWebViewHost.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionWebViewHost.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import android.view.Gravity import android.view.View diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptCapabilityRegistry.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptCapabilityRegistry.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptCapabilityRegistry.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptCapabilityRegistry.kt index 655dcae7e4..bebc0abffa 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptCapabilityRegistry.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptCapabilityRegistry.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript import androidx.webkit.WebViewFeature diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMatcher.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMatcher.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMatcher.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMatcher.kt index fc442881be..54c6659359 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMatcher.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMatcher.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript import android.net.Uri import java.util.Locale diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMetadataParser.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMetadataParser.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMetadataParser.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMetadataParser.kt index 2b4ef86a3b..79c353577b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMetadataParser.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMetadataParser.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript internal object UserscriptMetadataParser { private val metadataBlockRegex = diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptModels.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptModels.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptModels.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptModels.kt index fdb8db6c50..b2fda1d2fb 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptModels.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptModels.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportCoordinator.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportCoordinator.kt similarity index 96% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportCoordinator.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportCoordinator.kt index 7a673471a6..2c9eed8b40 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportCoordinator.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportCoordinator.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.install +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.install import android.content.Context import android.content.Intent diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportPickerActivity.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportPickerActivity.kt similarity index 97% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportPickerActivity.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportPickerActivity.kt index 7172e9eb53..7199befe5e 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportPickerActivity.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportPickerActivity.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.install +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.install import android.content.Intent import android.database.Cursor diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptBootstrapScript.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptBootstrapScript.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptBootstrapScript.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptBootstrapScript.kt index 88aee41e72..03564cbf3d 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptBootstrapScript.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptBootstrapScript.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime internal object UserscriptBootstrapScript { const val BRIDGE_NAME = "OperitUserscriptBridge" diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptCookieService.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptCookieService.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptCookieService.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptCookieService.kt index 3f73d1103e..af4060108b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptCookieService.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptCookieService.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime import android.webkit.CookieManager import java.net.HttpCookie diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptStorageNotifier.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptStorageNotifier.kt similarity index 88% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptStorageNotifier.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptStorageNotifier.kt index f5691d4c06..4b82855a52 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptStorageNotifier.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptStorageNotifier.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime import org.json.JSONObject diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptTabStateStore.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptTabStateStore.kt similarity index 91% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptTabStateStore.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptTabStateStore.kt index 57bd81a114..1aacefd0e0 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptTabStateStore.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptTabStateStore.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime import java.util.concurrent.ConcurrentHashMap diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptWebRequestEngine.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptWebRequestEngine.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptWebRequestEngine.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptWebRequestEngine.kt index f7c6af1706..3538e21c8a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptWebRequestEngine.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptWebRequestEngine.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime import java.util.Locale import java.util.UUID diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/WebSessionUserscriptManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/WebSessionUserscriptManager.kt similarity index 97% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/WebSessionUserscriptManager.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/WebSessionUserscriptManager.kt index bcb5557e2f..0dee751499 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/WebSessionUserscriptManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/WebSessionUserscriptManager.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime import android.Manifest import android.app.NotificationChannel @@ -22,19 +22,19 @@ import androidx.webkit.WebMessageCompat import androidx.webkit.WebViewCompat import androidx.webkit.WebViewFeature import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ParsedUserscriptMetadata -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptCapabilityRegistry -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallPreview -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallSourceType -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptListItem -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptMatcher -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageMenuCommand -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageRuntimeState -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageRuntimeStatus -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptSupportState -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.install.UserscriptImportCoordinator -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage.UserscriptRepository -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ui.WebSessionUserscriptUiStateStore +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ParsedUserscriptMetadata +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptCapabilityRegistry +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallPreview +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallSourceType +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptListItem +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptMatcher +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageMenuCommand +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageRuntimeState +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageRuntimeStatus +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptSupportState +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.install.UserscriptImportCoordinator +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage.UserscriptRepository +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ui.WebSessionUserscriptUiStateStore import com.ai.assistance.operit.util.logging.AppLogger import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptEntities.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptEntities.kt similarity index 95% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptEntities.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptEntities.kt index 97c2ac59bb..789e9c0e03 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptEntities.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptEntities.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptJsonStore.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptJsonStore.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptJsonStore.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptJsonStore.kt index 6c80a7ff20..9daa1c530f 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptJsonStore.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptJsonStore.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage import android.content.Context import com.ai.assistance.operit.util.files.OperitPaths diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptRepository.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptRepository.kt similarity index 94% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptRepository.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptRepository.kt index 497f808b8f..206216451b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptRepository.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptRepository.kt @@ -1,22 +1,22 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage import android.content.Context import android.util.Base64 import android.webkit.MimeTypeMap -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ParsedUserscriptMetadata -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptCapabilityRegistry -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptBootstrapPayload -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptExecutionPayload -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallPreview -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallSourceType -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptListItem -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptLogItem -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptMatcher -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptMetadataParser -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptRequireEntry -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptResourceEntry -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptResourcePayload -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptRunAt +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ParsedUserscriptMetadata +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptCapabilityRegistry +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptBootstrapPayload +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptExecutionPayload +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallPreview +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallSourceType +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptListItem +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptLogItem +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptMatcher +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptMetadataParser +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptRequireEntry +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptResourceEntry +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptResourcePayload +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptRunAt import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.util.files.OperitPaths import java.io.File diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/ui/WebSessionUserscriptUiStateStore.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/ui/WebSessionUserscriptUiStateStore.kt similarity index 73% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/ui/WebSessionUserscriptUiStateStore.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/ui/WebSessionUserscriptUiStateStore.kt index b9a43c28c2..4511076bd5 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/ui/WebSessionUserscriptUiStateStore.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/ui/WebSessionUserscriptUiStateStore.kt @@ -1,10 +1,10 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ui +package com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ui -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallPreview -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptListItem -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptLogItem -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageRuntimeStatus -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptSupportState +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallPreview +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptListItem +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptLogItem +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageRuntimeStatus +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptSupportState import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWorkflowTools.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/workflow/StandardWorkflowTools.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWorkflowTools.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/builtin/workflow/StandardWorkflowTools.kt index 0dfeee29ae..dc9d803eed 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWorkflowTools.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/builtin/workflow/StandardWorkflowTools.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.workflow import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/climode/CliToolModeSupport.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/climode/CliToolModeSupport.kt index cf19e26f74..c74247bf28 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/climode/CliToolModeSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/climode/CliToolModeSupport.kt @@ -5,7 +5,7 @@ import com.ai.assistance.operit.core.config.SystemToolPrompts import com.ai.assistance.operit.core.tools.PackageTool import com.ai.assistance.operit.core.tools.PackageToolParameter import com.ai.assistance.operit.core.tools.ToolPackage -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.mcp.MCPLocalServer import com.ai.assistance.operit.data.model.ApiProviderType import com.ai.assistance.operit.data.model.SystemToolPromptCategory diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetention.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetention.kt index 9ae7b82aa3..3dc0ba5606 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetention.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetention.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.core.tools.javascript -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult import java.util.ArrayDeque internal fun collectComposeDslActionIds(result: ToolPkgComposeDslRenderResult): Set { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsEngine.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsEngine.kt index bcf471aaed..15e3d6e49b 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsEngine.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsEngine.kt @@ -11,13 +11,13 @@ import androidx.core.content.ContextCompat import com.ai.assistance.operit.core.application.ActivityLifecycleManager import com.ai.assistance.operit.core.chat.logMessageTiming import com.ai.assistance.operit.core.chat.messageTimingNow -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_MESSAGE_PROCESSING -import com.ai.assistance.operit.core.tools.packTool.ToolPkgApiCompatibility -import com.ai.assistance.operit.core.tools.packTool.ToolPkgApiVersion -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult -import com.ai.assistance.operit.core.tools.packTool.ToolPkgRuntimeMonitor +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_MESSAGE_PROCESSING +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgApiCompatibility +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgApiVersion +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.packTool.runtime.ToolPkgRuntimeMonitor import com.ai.assistance.operit.ui.main.navigation.AppRouteDiscoveryGateway import com.ai.assistance.operit.ui.main.navigation.AppRouterGateway import com.ai.assistance.operit.ui.main.navigation.RouteEntrySource diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsNativeInterfaceDelegates.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsNativeInterfaceDelegates.kt index 914ccdce21..ee26f5acb7 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsNativeInterfaceDelegates.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsNativeInterfaceDelegates.kt @@ -10,13 +10,13 @@ import android.text.StaticLayout import android.text.TextPaint import android.text.TextUtils import android.util.Base64 -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.BinaryResultData import com.ai.assistance.operit.core.tools.BooleanResultData import com.ai.assistance.operit.core.tools.IntResultData import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.ToolResultData -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolManager.kt index 4289ddf355..572e9d4eeb 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolManager.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.core.tools.javascript import android.content.Context import com.ai.assistance.operit.core.tools.ScriptExecutionTraceData import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.util.logging.AppLogger diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolPkgRegistration.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolPkgRegistration.kt index 0a4bef5661..1fa84abed9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolPkgRegistration.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolPkgRegistration.kt @@ -1,9 +1,9 @@ package com.ai.assistance.operit.core.tools.javascript -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_REGISTRATION_CHAT_MESSAGE_MENU_ITEM -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_REGISTRATION_CHAT_RUNTIME_HOOK -import com.ai.assistance.operit.core.tools.packTool.ToolPkgMarketOrigin -import com.ai.assistance.operit.core.tools.packTool.ToolPkgMarketOriginCodec +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_MESSAGE_MENU_ITEM +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_RUNTIME_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOrigin +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOriginCodec import org.json.JSONObject import org.json.JSONTokener diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/mcp/MCPToolExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/mcp/MCPToolExecutor.kt index 6e333a8382..8c184abbd9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/mcp/MCPToolExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/mcp/MCPToolExecutor.kt @@ -3,8 +3,8 @@ package com.ai.assistance.operit.core.tools.mcp import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutionLimits -import com.ai.assistance.operit.core.tools.ToolExecutor +import com.ai.assistance.operit.core.tools.runtime.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.runtime.ToolExecutor import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.data.model.ToolValidationResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt index 5aa8805b88..89b03e0c43 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt @@ -3,11 +3,12 @@ package com.ai.assistance.operit.core.tools.packTool import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.util.logging.AppLogger import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager class PackageDebugRefreshReceiver : BroadcastReceiver() { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt index be7f7f0b13..c883957b2e 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt @@ -3,11 +3,12 @@ package com.ai.assistance.operit.core.tools.packTool import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.util.logging.AppLogger import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager class ToolPkgDebugInstallReceiver : BroadcastReceiver() { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupport.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupport.kt similarity index 96% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupport.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupport.kt index fc440ed9ec..84f15045a1 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupport.kt @@ -1,10 +1,11 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.install import android.content.Context import android.net.Uri import android.provider.OpenableColumns import com.ai.assistance.operit.util.logging.AppLogger import java.io.File +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager /** 从分享或文件选择器导入外部包时的文件名判断与拷贝。 */ object PackageFileImportSupport { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletion.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletion.kt similarity index 90% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletion.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletion.kt index b1e11d80ad..d711137c71 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletion.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletion.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.install import java.io.File diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactory.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactory.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactory.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactory.kt index b1b2e8e0b5..85e472d31e 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactory.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactory.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.install import java.io.File import java.util.zip.ZipEntry diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoadOrder.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoadOrder.kt similarity index 96% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoadOrder.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoadOrder.kt index f25baf0941..23764fd08a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoadOrder.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoadOrder.kt @@ -1,6 +1,9 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.loader import com.ai.assistance.operit.core.tools.ToolPackage +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgManifestRequirement +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgSubpackageRuntime internal data class ToolPkgLoadOrderResult( val orderedContainers: List, diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoader.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoader.kt similarity index 89% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoader.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoader.kt index 8b1ddfcdc1..f9476608f0 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoader.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoader.kt @@ -1,10 +1,16 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.loader import android.content.Context import com.ai.assistance.operit.core.tools.ToolPackage import com.ai.assistance.operit.core.tools.javascript.JsEngine import java.io.File import java.util.zip.ZipFile +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgArchiveParser +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgLoadResult +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgMainRegistrationParseResult +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgMainRegistrationScriptParser +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgManifestPreview +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgSourceType internal object ToolPkgLoader { fun loadToolPkgFromExternalFile( diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/BuiltInPackageDefaults.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/BuiltInPackageDefaults.kt similarity index 85% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/BuiltInPackageDefaults.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/BuiltInPackageDefaults.kt index 9401211ee7..37f5459271 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/BuiltInPackageDefaults.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/BuiltInPackageDefaults.kt @@ -1,6 +1,7 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata import com.ai.assistance.operit.core.tools.ToolPackage +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgLoadResult /** 个人发行版的首次默认值;已保存的启停状态仍由包管理器持有。 */ internal object BuiltInPackageDefaults { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiVersion.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiVersion.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiVersion.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiVersion.kt index e595f07e96..9105937ac0 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiVersion.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiVersion.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata import com.ai.assistance.operit.BuildConfig diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgCommonPluginConstants.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgCommonPluginConstants.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgCommonPluginConstants.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgCommonPluginConstants.kt index 96081f5312..05c5f24d87 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgCommonPluginConstants.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgCommonPluginConstants.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata internal const val TOOLPKG_RUNTIME_COMPOSE_DSL = "compose_dsl" diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestRequirement.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgManifestRequirement.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestRequirement.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgManifestRequirement.kt index d9be8a8dbc..8054e01238 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestRequirement.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgManifestRequirement.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOrigin.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOrigin.kt similarity index 97% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOrigin.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOrigin.kt index 11714c1c82..eb6aeb2de6 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOrigin.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOrigin.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgTemplateModels.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgTemplateModels.kt similarity index 94% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgTemplateModels.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgTemplateModels.kt index ff780d8f33..0a5b0bdc46 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgTemplateModels.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgTemplateModels.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata import com.ai.assistance.operit.core.tools.LocalizedText import kotlinx.serialization.SerialName diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt index 9cbf15264c..5724182885 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt @@ -1,9 +1,9 @@ package com.ai.assistance.operit.core.tools.packTool.minify import android.content.Context -import com.ai.assistance.operit.core.tools.packTool.ToolPkgArchiveParser -import com.ai.assistance.operit.core.tools.packTool.ToolPkgMarketOrigin -import com.ai.assistance.operit.core.tools.packTool.ToolPkgMarketOriginCodec +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgArchiveParser +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOrigin +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOriginCodec import com.ai.assistance.operit.ui.features.extensions.packages.market.PUBLISH_LOGO_MAX_BYTES import com.ai.assistance.operit.ui.features.extensions.packages.market.ToolPkgLogoAsset import java.io.ByteArrayOutputStream diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMainRegistrationScriptParser.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt similarity index 93% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMainRegistrationScriptParser.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt index 37c1cb765e..c842002f6f 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMainRegistrationScriptParser.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt @@ -1,10 +1,31 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.parser import com.ai.assistance.operit.core.tools.LocalizedText import com.ai.assistance.operit.core.tools.javascript.JsEngine import com.ai.assistance.operit.util.logging.AppLogger import org.json.JSONArray import org.json.JSONObject +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_AI_PROVIDER +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_INPUT_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_MESSAGE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_MESSAGE_MENU_ITEM +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_RUNTIME_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_VIEW_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_INPUT_MENU_TOGGLE_PLUGIN +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_MESSAGE_PROCESSING_PLUGIN +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_ESTIMATE_FINALIZE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_ESTIMATE_HISTORY_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_FINALIZE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_HISTORY_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_INPUT_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_SUMMARY_GENERATE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_SYSTEM_PROMPT_COMPOSE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_TOOL_LIFECYCLE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_TOOL_PROMPT_COMPOSE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_XML_RENDER_PLUGIN +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_RUNTIME_COMPOSE_DSL +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOriginCodec +import com.ai.assistance.operit.core.tools.packTool.metadata.buildToolPkgRouteId internal object ToolPkgMainRegistrationScriptParser { private const val TAG = "ToolPkgMainRegParser" diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgParser.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgParser.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt index 02063e7312..fd31dfa42c 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgParser.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.parser import android.content.Context import android.provider.DocumentsContract @@ -16,6 +16,18 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive import org.hjson.JsonValue +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_NAV_SURFACE_MAIN_SIDEBAR_PLUGINS +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_NAV_SURFACE_PACKAGE_DETAILS +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_RUNTIME_COMPOSE_DSL +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgApiCompatibility +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgManifestRequirement +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgManifestWorkflowTemplate +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgManifestWorkspaceTemplate +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOrigin +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgPackageVersion +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgWorkflowTemplateRuntime +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgWorkspaceTemplateRuntime +import com.ai.assistance.operit.core.tools.packTool.metadata.buildToolPkgRouteId private val TOOLPKG_DIRECTORY_RESOURCE_MIME_TYPES = setOf( diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResult.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResult.kt similarity index 94% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResult.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResult.kt index ba3b3fab49..ff717f1ed7 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResult.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResult.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime import com.ai.assistance.operit.core.tools.PackageActivationErrorCode import com.ai.assistance.operit.core.tools.PackageActivationErrorData diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManager.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManager.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManager.kt index 5df5c519d5..b4c1e9710a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManager.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime import android.content.Context import com.ai.assistance.operit.core.tools.PackageActivationErrorCode @@ -10,7 +10,7 @@ import com.ai.assistance.operit.data.storage.LocalModelUsageHandle import com.ai.assistance.operit.core.chat.logMessageTiming import com.ai.assistance.operit.core.chat.messageTimingNow import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.PackageToolExecutor import com.ai.assistance.operit.core.tools.PackageTool @@ -27,7 +27,7 @@ import com.ai.assistance.operit.core.tools.skill.SkillManager import com.ai.assistance.operit.data.security.PluginDenylistRepository import com.ai.assistance.operit.data.preferences.SkillVisibilityPreferences import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.preferences.DisplayPreferencesManager import com.ai.assistance.operit.data.preferences.ApiPreferences @@ -56,6 +56,22 @@ import kotlinx.coroutines.launch import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import org.hjson.JsonValue +import com.ai.assistance.operit.core.tools.packTool.install.deleteInstalledPackageSources +import com.ai.assistance.operit.core.tools.packTool.loader.ToolPkgLoadOrderResolver +import com.ai.assistance.operit.core.tools.packTool.loader.ToolPkgLoader +import com.ai.assistance.operit.core.tools.packTool.metadata.BuiltInPackageDefaults +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_RUNTIME_COMPOSE_DSL +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgApiCompatibility +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgManifestRequirement +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOrigin +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOriginCodec +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgArchiveParser +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgLoadResult +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgManifestPreview +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgResourceRuntime +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgSourceType +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgSubpackageRuntime /** * Manages the loading, registration, and handling of tool packages diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManagerToolPkgFacade.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManagerToolPkgFacade.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManagerToolPkgFacade.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManagerToolPkgFacade.kt index 706d4a3a8d..0904e88a00 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManagerToolPkgFacade.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManagerToolPkgFacade.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime import android.content.Context import com.ai.assistance.operit.core.chat.logMessageTiming @@ -13,6 +13,13 @@ import java.util.UUID import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_MESSAGE_PROCESSING +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_NAVIGATION_ENTRY_ACTION +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_NAV_SURFACE_PACKAGE_DETAILS +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_RUNTIME_COMPOSE_DSL +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgArchiveParser +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgSourceType internal class PackageManagerToolPkgFacade( private val packageManager: PackageManager diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgHookModels.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgHookModels.kt similarity index 95% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgHookModels.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgHookModels.kt index f7c63d64d6..5ff9b68fe2 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgHookModels.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgHookModels.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime /** * Mirror of ToolPkg xml_render hook result shape used by JS toolpkg. diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManager.kt similarity index 97% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManager.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManager.kt index 3fc53279e8..29365c68dd 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManager.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime import android.content.Context import com.ai.assistance.operit.core.tools.ToolPackage @@ -8,6 +8,10 @@ import com.ai.assistance.operit.util.logging.AppLogger import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.atomic.AtomicBoolean +import com.ai.assistance.operit.core.tools.packTool.loader.ToolPkgLoadOrderResolver +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgLoadResult +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgSubpackageRuntime /** * 一个 ToolPkg 容器当前活跃执行引擎的运行信息。 diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgRuntimeMonitor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgRuntimeMonitor.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgRuntimeMonitor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgRuntimeMonitor.kt index 76f6118e17..2ef9a43251 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgRuntimeMonitor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgRuntimeMonitor.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime import android.os.SystemClock import java.util.ArrayDeque diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslParser.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/uidsl/ToolPkgComposeDslParser.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslParser.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/packTool/uidsl/ToolPkgComposeDslParser.kt index 1527a90ca5..5ca9a6a062 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslParser.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/uidsl/ToolPkgComposeDslParser.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.uidsl import org.json.JSONArray import org.json.JSONObject diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/AndroidPermissionLevel.kt similarity index 93% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/permissions/AndroidPermissionLevel.kt index f7038ac82b..62c9d9d6df 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/AndroidPermissionLevel.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.permissions import java.util.Locale diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilities.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilities.kt index 17d4d629a5..ef2220e4d8 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilities.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilities.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.core.tools.permissions -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity /** 执行后端与用户模式分开,新增授权来源不需要新增用户模式。 */ enum class PermissionBackend { STANDARD, ACCESSIBILITY, SHIZUKU, ROOT } diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilityResolver.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilityResolver.kt index b2e1d41d5a..84564ffef5 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilityResolver.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilityResolver.kt @@ -1,8 +1,8 @@ package com.ai.assistance.operit.core.tools.permissions import android.content.Context -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShizukuAuthorizer +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuAuthorizer import com.ai.assistance.operit.core.tools.system.shell.ShellExecutorFactory import com.ai.assistance.operit.data.preferences.androidPermissionPreferences import com.ai.assistance.operit.data.repository.UIHierarchyManager diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySession.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySession.kt index c30438146b..90dbf55ee4 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySession.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySession.kt @@ -1,6 +1,6 @@ package com.ai.assistance.operit.core.tools.permissions -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import kotlinx.coroutines.sync.Mutex /** 保存一次工具执行会话内的授权能力快照,避免每个工具重复探测系统授权。 */ diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AccessibilityProviderInstaller.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/AccessibilityProviderInstaller.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/AccessibilityProviderInstaller.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/AccessibilityProviderInstaller.kt index 57cdaadcf1..721092cf63 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AccessibilityProviderInstaller.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/AccessibilityProviderInstaller.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.permissions.authorization import android.content.Context import android.content.pm.PackageInfo diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/RootAuthorizer.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/RootAuthorizer.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/RootAuthorizer.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/RootAuthorizer.kt index beb6aeb1be..76d4652b8c 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/RootAuthorizer.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/RootAuthorizer.kt @@ -1,10 +1,10 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.permissions.authorization import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.R import com.ai.assistance.operit.core.tools.system.shell.RootShellExecutor -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity import com.ai.assistance.operit.data.preferences.RootCommandExecutionMode import com.ai.assistance.operit.data.preferences.androidPermissionPreferences import com.topjohnwu.superuser.Shell diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuAuthorizer.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuAuthorizer.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuAuthorizer.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuAuthorizer.kt index 32f0b3af95..44e45a352f 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuAuthorizer.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuAuthorizer.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.permissions.authorization import android.content.Context import android.content.pm.PackageManager diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuInstaller.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuInstaller.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuInstaller.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuInstaller.kt index d795a7f4be..ab52501bf9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuInstaller.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuInstaller.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.permissions.authorization import android.content.Context import android.content.Intent diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHandler.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHandler.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHandler.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHandler.kt index cdeee5cf6e..f5b4b471df 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHandler.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHandler.kt @@ -1,9 +1,9 @@ -package com.ai.assistance.operit.core.tools +package com.ai.assistance.operit.core.tools.runtime import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.core.tools.mcp.MCPManager -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilitySession import com.ai.assistance.operit.data.model.AITool @@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import com.ai.assistance.operit.core.tools.StringResultData /** * Handles the extraction and execution of AI tools from responses Supports real-time streaming diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHook.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHook.kt similarity index 96% rename from app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHook.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHook.kt index ef399df51c..b16a8646ce 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHook.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHook.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools +package com.ai.assistance.operit.core.tools.runtime import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolExecutionLimits.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolExecutionLimits.kt similarity index 86% rename from app/src/main/java/com/ai/assistance/operit/core/tools/ToolExecutionLimits.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolExecutionLimits.kt index 2fc2512a6c..95a300e25a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolExecutionLimits.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolExecutionLimits.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools +package com.ai.assistance.operit.core.tools.runtime object ToolExecutionLimits { const val MAX_FILE_READ_BYTES = 32_000 diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolProgressBus.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolProgressBus.kt similarity index 97% rename from app/src/main/java/com/ai/assistance/operit/core/tools/ToolProgressBus.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolProgressBus.kt index 2a8384d0a1..ea9fbe4064 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolProgressBus.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolProgressBus.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools +package com.ai.assistance.operit.core.tools.runtime import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt index 40f88ef94a..c483893265 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools +package com.ai.assistance.operit.core.tools.runtime import android.content.Context import com.ai.assistance.operit.R @@ -7,7 +7,7 @@ import com.ai.assistance.operit.core.performance.PerformanceMonitorManager import com.ai.assistance.operit.core.chat.tools.ToolExecutionManager import com.ai.assistance.operit.core.tools.climode.CliToolModeSupport import com.ai.assistance.operit.core.tools.climode.ToolExposureMode -import com.ai.assistance.operit.core.tools.defaultTool.ToolGetter +import com.ai.assistance.operit.core.tools.builtin.ToolGetter import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult @@ -24,6 +24,9 @@ import kotlinx.coroutines.flow.toList import kotlinx.coroutines.runBlocking import org.json.JSONArray import org.json.JSONObject +import com.ai.assistance.operit.core.tools.PerformanceMetricsResultData +import com.ai.assistance.operit.core.tools.SleepResultData +import com.ai.assistance.operit.core.tools.StringResultData /** * This file contains all tool registrations centralized for easier maintenance and integration It @@ -36,7 +39,7 @@ import org.json.JSONObject * @param context Application context for tools that need it */ fun registerAllTools(handler: AIToolHandler, context: Context) { - com.ai.assistance.operit.core.tools.defaultTool.a2ui.A2uiTools.register(handler, context) + com.ai.assistance.operit.core.tools.builtin.a2ui.A2uiTools.register(handler, context) // Helper function to wrap UI tool execution with visibility changes diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/AccessibilityActionListener.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/AccessibilityActionListener.kt index c2ebae0a34..1185f5d8ab 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/AccessibilityActionListener.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/AccessibilityActionListener.kt @@ -5,7 +5,7 @@ import android.content.Intent import android.provider.Settings import com.ai.assistance.operit.util.logging.AppLogger import android.view.accessibility.AccessibilityEvent -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.repository.UIHierarchyManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListener.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListener.kt index ac655ddff6..9e4dee3f71 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListener.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListener.kt @@ -1,6 +1,6 @@ package com.ai.assistance.operit.core.tools.system.action -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel /** 通用UI操作监听接口 定义了不同权限级别UI操作监听的统一接口 */ interface ActionListener { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt index 992aa1a263..38fe6826d3 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionListenerFactory.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.core.tools.system.action import android.content.Context import com.ai.assistance.operit.core.tools.permissions.PermissionBackend import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.preferences.androidPermissionPreferences /** 监听器实例按后端缓存,授权状态不随实例一起缓存。 */ diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionManager.kt index c6a9cb813c..24eff693e9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ActionManager.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.core.tools.system.action import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/RootActionListener.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/RootActionListener.kt index 274dd8d8ba..2af99a38f1 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/RootActionListener.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/RootActionListener.kt @@ -4,7 +4,7 @@ import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.core.tools.permissions.PermissionBackend -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.core.tools.system.shell.ShellExecutorFactory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ShizukuActionListener.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ShizukuActionListener.kt index 2d9b482e1d..3376fb5749 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ShizukuActionListener.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/ShizukuActionListener.kt @@ -4,8 +4,8 @@ import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.core.tools.permissions.PermissionBackend -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShizukuAuthorizer +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuAuthorizer import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.delay diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/StandardActionListener.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/StandardActionListener.kt index 7f04fa22a0..34e3450a80 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/StandardActionListener.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/action/StandardActionListener.kt @@ -4,7 +4,7 @@ import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.R import android.view.accessibility.AccessibilityEvent -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.util.concurrent.atomic.AtomicBoolean diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionCaptureManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionCaptureManager.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionCaptureManager.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionCaptureManager.kt index 80a61d03a4..4146d89982 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionCaptureManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionCaptureManager.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.system.capture import android.content.Context import android.graphics.Bitmap diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionHolder.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionHolder.kt similarity index 92% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionHolder.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionHolder.kt index 85aadd9a9d..c45f22a55a 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionHolder.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionHolder.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.system.capture import android.content.Context import android.media.projection.MediaProjection diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureActivity.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureActivity.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureActivity.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureActivity.kt index 4b5a7b51c6..4bc63abcec 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureActivity.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureActivity.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.system.capture import android.app.Activity import android.content.Context diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureService.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureService.kt similarity index 98% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureService.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureService.kt index 90d3cb1d1b..2d198fddf1 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureService.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureService.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.system.capture import android.app.Notification import android.app.NotificationChannel diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidShellExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/AndroidShellExecutor.kt similarity index 95% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidShellExecutor.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/AndroidShellExecutor.kt index da63e584ba..3a6e828723 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidShellExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/AndroidShellExecutor.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.system.shell import android.content.Context import com.ai.assistance.operit.core.tools.permissions.PermissionBackend @@ -7,6 +7,7 @@ import com.ai.assistance.operit.core.tools.system.shell.ShellExecutor import com.ai.assistance.operit.core.tools.system.shell.ShellExecutorFactory import com.ai.assistance.operit.core.tools.system.shell.ShellProcess import com.ai.assistance.operit.data.preferences.androidPermissionPreferences +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel /** 根据模式和当前授权选择 Shell 后端;命令提交后不自动重放。 */ class AndroidShellExecutor { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/RootShellExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/RootShellExecutor.kt index 100ad2ca73..094ddd993c 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/RootShellExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/RootShellExecutor.kt @@ -3,8 +3,8 @@ package com.ai.assistance.operit.core.tools.system.shell import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity import com.ai.assistance.operit.data.preferences.AndroidPermissionPreferences import com.ai.assistance.operit.data.preferences.RootCommandExecutionMode import com.ai.assistance.operit.data.preferences.androidPermissionPreferences diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutor.kt index c18b790eb4..aab3d45962 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutor.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.core.tools.system.shell -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity /** 通用Shell命令执行接口 定义了不同权限级别Shell操作的统一接口 */ interface ShellExecutor { diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt index cf010b35e9..a6764c90ca 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShellExecutorFactory.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.core.tools.system.shell import android.content.Context import com.ai.assistance.operit.core.tools.permissions.PermissionBackend import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.preferences.androidPermissionPreferences /** 实例按后端缓存,模式到后端的选择在每次操作前重新计算。 */ diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShizukuShellExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShizukuShellExecutor.kt index 8b70fdc431..4b9f0309b4 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShizukuShellExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/ShizukuShellExecutor.kt @@ -4,9 +4,9 @@ import android.content.Context import android.os.ParcelFileDescriptor import android.os.RemoteException import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShizukuAuthorizer -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuAuthorizer +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity import java.io.BufferedReader import java.io.IOException import java.io.InputStream diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/StandardShellExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/StandardShellExecutor.kt index 9c1d745ac3..0e96af7072 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/StandardShellExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/StandardShellExecutor.kt @@ -2,8 +2,8 @@ package com.ai.assistance.operit.core.tools.system.shell import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity import java.io.BufferedReader import java.io.InputStreamReader import java.util.concurrent.TimeUnit diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shower/OperitShowerShellRunner.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shower/OperitShowerShellRunner.kt index bf459f7fe3..13914bffe9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/shower/OperitShowerShellRunner.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/shower/OperitShowerShellRunner.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.core.tools.system.shower -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor -import com.ai.assistance.operit.core.tools.system.ShellIdentity as AppShellIdentity +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity as AppShellIdentity import com.ai.assistance.showerclient.ShellCommandResult import com.ai.assistance.showerclient.ShellIdentity import com.ai.assistance.showerclient.ShellRunner diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/OperitTerminalManager.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/OperitTerminalManager.kt similarity index 96% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/OperitTerminalManager.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/OperitTerminalManager.kt index a60a98ff55..cacddd8b20 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/OperitTerminalManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/OperitTerminalManager.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.system.terminal import android.content.Context import android.content.pm.PackageManager diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/Terminal.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/Terminal.kt similarity index 99% rename from app/src/main/java/com/ai/assistance/operit/core/tools/system/Terminal.kt rename to app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/Terminal.kt index 514d893f8e..2c2f188352 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/Terminal.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/Terminal.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.system +package com.ai.assistance.operit.core.tools.system.terminal import android.content.Context import android.os.Build diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuard.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuard.kt index 06996dc8dd..26a74595c9 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuard.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuard.kt @@ -1,6 +1,6 @@ package com.ai.assistance.operit.core.tools.system.uiautomator -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock diff --git a/app/src/main/java/com/ai/assistance/operit/core/workflow/WorkflowExecutor.kt b/app/src/main/java/com/ai/assistance/operit/core/workflow/WorkflowExecutor.kt index 099e5cbe5d..0cebdbc0da 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/workflow/WorkflowExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/workflow/WorkflowExecutor.kt @@ -4,7 +4,7 @@ import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.core.config.SystemToolPrompts import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ConditionNode import com.ai.assistance.operit.data.model.ConditionOperator diff --git a/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPLocalServer.kt b/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPLocalServer.kt index 1f6e2d9200..fa92b3d0d7 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPLocalServer.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPLocalServer.kt @@ -4,7 +4,7 @@ import android.content.Context import android.content.SharedPreferences import com.ai.assistance.operit.R import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.mcp.MCPManager import com.ai.assistance.operit.core.tools.DirectoryListingData import com.ai.assistance.operit.core.tools.FileExistsData diff --git a/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPRepository.kt b/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPRepository.kt index 2328d579cb..724b3ed82e 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPRepository.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/mcp/MCPRepository.kt @@ -7,7 +7,7 @@ import android.os.Environment import com.ai.assistance.operit.R import com.ai.assistance.operit.api.chat.EnhancedAIService import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.mcp.MCPManager import com.ai.assistance.operit.core.tools.mcp.MCPPackage import com.ai.assistance.operit.core.tools.mcp.McpRuntimeDescriptor diff --git a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPBridge.kt b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPBridge.kt index 1a727896ac..75ae440d85 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPBridge.kt @@ -5,8 +5,8 @@ import com.ai.assistance.operit.R import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.util.files.OperitPaths import com.ai.assistance.operit.util.network.PortProcessKiller -import com.ai.assistance.operit.core.tools.system.Terminal -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.system.terminal.Terminal +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import java.io.BufferedReader diff --git a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPDeployer.kt b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPDeployer.kt index 7736efcf9f..f086a1ff73 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPDeployer.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPDeployer.kt @@ -4,8 +4,8 @@ import android.content.Context import com.ai.assistance.operit.R import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.data.mcp.MCPLocalServer -import com.ai.assistance.operit.core.tools.system.Terminal -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.system.terminal.Terminal +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.google.gson.JsonParser diff --git a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPSharedSession.kt b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPSharedSession.kt index 2e898ab785..374db74eeb 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPSharedSession.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPSharedSession.kt @@ -2,7 +2,7 @@ package com.ai.assistance.operit.data.mcp.plugins import android.content.Context import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.system.Terminal +import com.ai.assistance.operit.core.tools.system.terminal.Terminal import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock diff --git a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPStarter.kt b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPStarter.kt index 1193a6fdb7..85af0c0131 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPStarter.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/mcp/plugins/MCPStarter.kt @@ -7,7 +7,7 @@ import com.ai.assistance.operit.core.tools.mcp.MCPManager import com.ai.assistance.operit.core.tools.mcp.McpRuntimeDescriptor import com.ai.assistance.operit.data.mcp.MCPLocalServer import com.ai.assistance.operit.data.mcp.MCPRepository -import com.ai.assistance.operit.core.tools.system.Terminal +import com.ai.assistance.operit.core.tools.system.terminal.Terminal import com.ai.assistance.operit.data.mcp.createMcpConfigGson import com.google.gson.JsonParser import kotlinx.coroutines.CancellationException diff --git a/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionModeMigration.kt b/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionModeMigration.kt index 39889ce6e2..45ee0ace14 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionModeMigration.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionModeMigration.kt @@ -4,7 +4,7 @@ import androidx.datastore.core.DataMigration import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.stringPreferencesKey -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import java.util.Locale /** 只更新旧模式名称,保留 Root 设置以及其他偏好。 */ diff --git a/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionPreferences.kt b/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionPreferences.kt index 2c84d32dd0..a53e1d7528 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionPreferences.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/preferences/AndroidPermissionPreferences.kt @@ -7,7 +7,7 @@ import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first diff --git a/app/src/main/java/com/ai/assistance/operit/data/preferences/CharacterCardToolAccessResolver.kt b/app/src/main/java/com/ai/assistance/operit/data/preferences/CharacterCardToolAccessResolver.kt index f12764d79a..e210be3de0 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/preferences/CharacterCardToolAccessResolver.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/preferences/CharacterCardToolAccessResolver.kt @@ -2,7 +2,7 @@ package com.ai.assistance.operit.data.preferences import android.content.Context import com.ai.assistance.operit.core.config.SystemToolPrompts -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.CharacterCardToolAccessConfig import com.ai.assistance.operit.data.skill.SkillRepository import kotlinx.coroutines.flow.first diff --git a/app/src/main/java/com/ai/assistance/operit/data/repository/UIHierarchyManager.kt b/app/src/main/java/com/ai/assistance/operit/data/repository/UIHierarchyManager.kt index 84f19b0d1d..5d2b062942 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/repository/UIHierarchyManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/repository/UIHierarchyManager.kt @@ -15,7 +15,7 @@ import android.os.RemoteException import com.ai.assistance.operit.util.logging.AppLogger import androidx.core.content.FileProvider import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.system.AccessibilityProviderInstaller +import com.ai.assistance.operit.core.tools.permissions.authorization.AccessibilityProviderInstaller import com.ai.assistance.operit.provider.IAccessibilityProvider import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/ai/assistance/operit/data/storage/PackageSkillInventory.kt b/app/src/main/java/com/ai/assistance/operit/data/storage/PackageSkillInventory.kt index ce6ddcd92a..52012eccb7 100644 --- a/app/src/main/java/com/ai/assistance/operit/data/storage/PackageSkillInventory.kt +++ b/app/src/main/java/com/ai/assistance/operit/data/storage/PackageSkillInventory.kt @@ -1,8 +1,8 @@ package com.ai.assistance.operit.data.storage import android.content.Context -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.core.tools.skill.SkillManager import com.ai.assistance.operit.data.mcp.MCPRepository import com.ai.assistance.operit.util.files.OperitPaths diff --git a/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetConfigActivity.kt b/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetConfigActivity.kt index f169e19bd2..f2376fc7c1 100644 --- a/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetConfigActivity.kt +++ b/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetConfigActivity.kt @@ -35,7 +35,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.foundation.layout.WindowInsets import androidx.lifecycle.lifecycleScope import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.ui.theme.OperitTheme import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay diff --git a/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetDslRenderer.kt b/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetDslRenderer.kt index 5d4ef5d0a6..44be4b5ae2 100644 --- a/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetDslRenderer.kt +++ b/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetDslRenderer.kt @@ -23,11 +23,11 @@ import androidx.glance.text.FontWeight import androidx.glance.text.Text import androidx.glance.text.TextStyle import androidx.glance.unit.ColorProvider -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslParser -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslParser +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult import com.ai.assistance.operit.ui.common.composedsl.normalizeToken import com.ai.assistance.operit.util.logging.AppLogger diff --git a/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetHost.kt b/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetHost.kt index 48b2873b4a..41a4e75dc4 100644 --- a/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetHost.kt +++ b/app/src/main/java/com/ai/assistance/operit/integrations/appwidget/ToolPkgDesktopWidgetHost.kt @@ -3,8 +3,8 @@ package com.ai.assistance.operit.integrations.appwidget import android.appwidget.AppWidgetManager import android.content.Context import android.content.Intent -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.ui.main.MainActivity import kotlinx.coroutines.runBlocking import androidx.glance.appwidget.updateAll diff --git a/app/src/main/java/com/ai/assistance/operit/integrations/externalchat/ExternalChatRequestExecutor.kt b/app/src/main/java/com/ai/assistance/operit/integrations/externalchat/ExternalChatRequestExecutor.kt index 8af97b087f..e01a84f680 100644 --- a/app/src/main/java/com/ai/assistance/operit/integrations/externalchat/ExternalChatRequestExecutor.kt +++ b/app/src/main/java/com/ai/assistance/operit/integrations/externalchat/ExternalChatRequestExecutor.kt @@ -3,9 +3,9 @@ package com.ai.assistance.operit.integrations.externalchat import android.content.Context import com.ai.assistance.operit.core.tools.ChatListResultData import com.ai.assistance.operit.core.tools.MessageSendResultData -import com.ai.assistance.operit.core.tools.defaultTool.standard.MessageSendStreamSession -import com.ai.assistance.operit.core.tools.defaultTool.standard.MessageSendStreamStartResult -import com.ai.assistance.operit.core.tools.defaultTool.standard.StandardChatManagerTool +import com.ai.assistance.operit.core.tools.builtin.chat.MessageSendStreamSession +import com.ai.assistance.operit.core.tools.builtin.chat.MessageSendStreamStartResult +import com.ai.assistance.operit.core.tools.builtin.chat.StandardChatManagerTool import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.data.model.ToolParameter diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/lifecycle/AppLifecycleHookPluginRegistry.kt b/app/src/main/java/com/ai/assistance/operit/plugins/lifecycle/AppLifecycleHookPluginRegistry.kt index 943b75f5cc..7a3280114e 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/lifecycle/AppLifecycleHookPluginRegistry.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/lifecycle/AppLifecycleHookPluginRegistry.kt @@ -7,18 +7,18 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_ACTIVITY_ON_CREATE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_ACTIVITY_ON_DESTROY -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_ACTIVITY_ON_PAUSE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_ACTIVITY_ON_RESUME -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_ACTIVITY_ON_START -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_ACTIVITY_ON_STOP -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_APPLICATION_ON_BACKGROUND -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_APPLICATION_ON_CREATE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_APPLICATION_ON_FOREGROUND -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_APPLICATION_ON_LOW_MEMORY -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_APPLICATION_ON_TERMINATE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_APPLICATION_ON_TRIM_MEMORY +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_ACTIVITY_ON_CREATE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_ACTIVITY_ON_DESTROY +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_ACTIVITY_ON_PAUSE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_ACTIVITY_ON_RESUME +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_ACTIVITY_ON_START +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_ACTIVITY_ON_STOP +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_APPLICATION_ON_BACKGROUND +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_APPLICATION_ON_CREATE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_APPLICATION_ON_FOREGROUND +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_APPLICATION_ON_LOW_MEMORY +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_APPLICATION_ON_TERMINATE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_APPLICATION_ON_TRIM_MEMORY enum class AppLifecycleEvent(val wireName: String) { APPLICATION_CREATE(TOOLPKG_EVENT_APPLICATION_ON_CREATE), diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgAiProviderRegistry.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgAiProviderRegistry.kt index 1638787c43..1568770623 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgAiProviderRegistry.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgAiProviderRegistry.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.plugins.toolpkg -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import java.util.concurrent.atomic.AtomicBoolean internal object ToolPkgAiProviderRegistry { diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatInputHookBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatInputHookBridge.kt index 3a91f93f67..392b794240 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatInputHookBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatInputHookBridge.kt @@ -1,8 +1,8 @@ package com.ai.assistance.operit.plugins.toolpkg -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_CHAT_INPUT -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_CHAT_INPUT +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import com.ai.assistance.operit.R import com.ai.assistance.operit.ui.features.conversation.chat.components.style.input.common.ChatInputEvents import com.ai.assistance.operit.ui.features.conversation.chat.components.style.input.common.ChatInputHook diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageHookBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageHookBridge.kt index e5b8fb10a5..4eddad97da 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageHookBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageHookBridge.kt @@ -1,8 +1,8 @@ package com.ai.assistance.operit.plugins.toolpkg -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_CHAT_MESSAGE -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_CHAT_MESSAGE +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import com.ai.assistance.operit.data.model.ChatMessage import com.ai.assistance.operit.util.logging.AppLogger import java.util.concurrent.atomic.AtomicBoolean diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageMenuItemBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageMenuItemBridge.kt index 0c27077234..e4016d42e3 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageMenuItemBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatMessageMenuItemBridge.kt @@ -1,10 +1,10 @@ package com.ai.assistance.operit.plugins.toolpkg import android.content.Context -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_CHAT_MESSAGE_MENU_ITEM -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_RUNTIME_COMPOSE_DSL -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_CHAT_MESSAGE_MENU_ITEM +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_RUNTIME_COMPOSE_DSL +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import com.ai.assistance.operit.data.model.ChatMessage import com.ai.assistance.operit.plugins.chatmessage.ChatMessageMenuDialogRequest import com.ai.assistance.operit.plugins.chatmessage.ChatMessageMenuItemClickResult diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatRuntimeHookBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatRuntimeHookBridge.kt index 43e68e0922..3a32d3d749 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatRuntimeHookBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatRuntimeHookBridge.kt @@ -4,9 +4,9 @@ import com.ai.assistance.operit.core.chat.hooks.ChatRuntimeHook import com.ai.assistance.operit.core.chat.hooks.ChatRuntimeHookContext import com.ai.assistance.operit.core.chat.hooks.ChatRuntimeHookEvent import com.ai.assistance.operit.core.chat.hooks.ChatRuntimeHookRegistry -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_CHAT_RUNTIME -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_CHAT_RUNTIME +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import com.ai.assistance.operit.data.model.InputProcessingState import com.ai.assistance.operit.util.logging.AppLogger import java.util.concurrent.atomic.AtomicBoolean diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatViewHookBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatViewHookBridge.kt index f9a3928960..8bfee67891 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatViewHookBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgChatViewHookBridge.kt @@ -1,8 +1,8 @@ package com.ai.assistance.operit.plugins.toolpkg -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_CHAT_VIEW -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_CHAT_VIEW +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import com.ai.assistance.operit.plugins.chatview.ChatViewEvent import com.ai.assistance.operit.plugins.chatview.ChatViewHookParams import com.ai.assistance.operit.plugins.chatview.ChatViewHookPlugin diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgCommonBridgePlugin.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgCommonBridgePlugin.kt index 0be989b6df..5d09760b47 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgCommonBridgePlugin.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgCommonBridgePlugin.kt @@ -11,12 +11,12 @@ import com.ai.assistance.operit.core.chat.plugins.MessageProcessingHookParams import com.ai.assistance.operit.core.chat.plugins.MessageProcessingPlugin import com.ai.assistance.operit.core.chat.plugins.MessageProcessingPluginRegistry import com.ai.assistance.operit.core.chat.hooks.PromptTurn -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_INPUT_MENU_TOGGLE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_MESSAGE_PROCESSING -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_XML_RENDER +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_INPUT_MENU_TOGGLE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_MESSAGE_PROCESSING +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_XML_RENDER import com.ai.assistance.operit.plugins.OperitPlugin import com.ai.assistance.operit.ui.common.markdown.XmlRenderPlugin import com.ai.assistance.operit.ui.common.markdown.XmlRenderPluginRegistry @@ -27,8 +27,8 @@ import com.ai.assistance.operit.ui.features.conversation.chat.components.style.i import com.ai.assistance.operit.ui.features.conversation.chat.components.style.input.common.InputMenuTogglePluginRegistry import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.util.stream.Stream -import com.ai.assistance.operit.core.tools.packTool.ToolPkgXmlRenderHookComposeDslResult -import com.ai.assistance.operit.core.tools.packTool.ToolPkgXmlRenderHookObjectResult +import com.ai.assistance.operit.core.tools.packTool.runtime.ToolPkgXmlRenderHookComposeDslResult +import com.ai.assistance.operit.core.tools.packTool.runtime.ToolPkgXmlRenderHookObjectResult import com.ai.assistance.operit.core.tools.javascript.extractJsExecutionErrorMessage import com.ai.assistance.operit.util.stream.stream import java.util.UUID diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgHookBridgeSupport.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgHookBridgeSupport.kt index dc4229bb37..0e934d4a5d 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgHookBridgeSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgHookBridgeSupport.kt @@ -1,12 +1,12 @@ package com.ai.assistance.operit.plugins.toolpkg import com.ai.assistance.operit.core.application.OperitApplication -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.LocalizedText import com.ai.assistance.operit.core.tools.javascript.JsJavaBridgeDelegates import com.ai.assistance.operit.core.tools.javascript.extractJsExecutionErrorMessage -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import org.json.JSONArray import org.json.JSONObject import org.json.JSONTokener diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgLifecyclePlugin.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgLifecyclePlugin.kt index b281c13c19..fe5ea4831a 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgLifecyclePlugin.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgLifecyclePlugin.kt @@ -1,9 +1,9 @@ package com.ai.assistance.operit.plugins.toolpkg import com.ai.assistance.operit.core.application.OperitApplication -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime import com.ai.assistance.operit.plugins.toolpkg.sortedByToolPkgLoadOrder import com.ai.assistance.operit.plugins.OperitPlugin import com.ai.assistance.operit.plugins.lifecycle.AppLifecycleEvent diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgPromptHookBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgPromptHookBridge.kt index 8b3140baa7..43da11e0d6 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgPromptHookBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgPromptHookBridge.kt @@ -12,15 +12,15 @@ import com.ai.assistance.operit.core.chat.hooks.PromptTurn import com.ai.assistance.operit.core.chat.hooks.PromptTurnKind import com.ai.assistance.operit.core.chat.hooks.SystemPromptComposeHook import com.ai.assistance.operit.core.chat.hooks.ToolPromptComposeHook -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_PROMPT_FINALIZE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_PROMPT_ESTIMATE_FINALIZE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_PROMPT_ESTIMATE_HISTORY -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_PROMPT_HISTORY -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_PROMPT_INPUT -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_SYSTEM_PROMPT_COMPOSE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_TOOL_PROMPT_COMPOSE +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_PROMPT_FINALIZE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_PROMPT_ESTIMATE_FINALIZE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_PROMPT_ESTIMATE_HISTORY +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_PROMPT_HISTORY +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_PROMPT_INPUT +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_SYSTEM_PROMPT_COMPOSE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_TOOL_PROMPT_COMPOSE import com.ai.assistance.operit.util.logging.AppLogger import java.util.concurrent.atomic.AtomicBoolean import org.json.JSONArray diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgSummaryHookBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgSummaryHookBridge.kt index 3793a0ad0f..9d8ae6cc0d 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgSummaryHookBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgSummaryHookBridge.kt @@ -6,9 +6,9 @@ import com.ai.assistance.operit.core.chat.hooks.SummaryGenerateHook import com.ai.assistance.operit.core.chat.hooks.SummaryHookContext import com.ai.assistance.operit.core.chat.hooks.SummaryHookMutation import com.ai.assistance.operit.core.chat.hooks.SummaryHookRegistry -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_SUMMARY_GENERATE +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_SUMMARY_GENERATE import com.ai.assistance.operit.data.model.FunctionType import com.ai.assistance.operit.util.logging.AppLogger import java.util.concurrent.atomic.AtomicBoolean diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgToolLifecycleBridge.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgToolLifecycleBridge.kt index f8f50cae40..86113306b2 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgToolLifecycleBridge.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ToolPkgToolLifecycleBridge.kt @@ -1,12 +1,12 @@ package com.ai.assistance.operit.plugins.toolpkg import com.ai.assistance.operit.core.application.OperitApplication -import com.ai.assistance.operit.core.tools.AIToolHook -import com.ai.assistance.operit.core.tools.AIToolHookDecision -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgContainerRuntime -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_TOOL_LIFECYCLE +import com.ai.assistance.operit.core.tools.runtime.AIToolHook +import com.ai.assistance.operit.core.tools.runtime.AIToolHookDecision +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.parser.ToolPkgContainerRuntime +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_TOOL_LIFECYCLE import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.util.logging.AppLogger diff --git a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ai/ToolPkgJsAiProviderService.kt b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ai/ToolPkgJsAiProviderService.kt index 7608034534..8154e89f95 100644 --- a/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ai/ToolPkgJsAiProviderService.kt +++ b/app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/ai/ToolPkgJsAiProviderService.kt @@ -2,10 +2,10 @@ package com.ai.assistance.operit.plugins.toolpkg.ai import android.content.Context import com.ai.assistance.operit.core.chat.hooks.PromptTurn -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_AI_PROVIDER_CALCULATE_INPUT_TOKENS -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_AI_PROVIDER_LIST_MODELS -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_AI_PROVIDER_SEND_MESSAGE -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_EVENT_AI_PROVIDER_TEST_CONNECTION +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_AI_PROVIDER_CALCULATE_INPUT_TOKENS +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_AI_PROVIDER_LIST_MODELS +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_AI_PROVIDER_SEND_MESSAGE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_EVENT_AI_PROVIDER_TEST_CONNECTION import com.ai.assistance.operit.data.model.ModelConfigData import com.ai.assistance.operit.data.model.ModelOption import com.ai.assistance.operit.data.model.ModelParameter diff --git a/app/src/main/java/com/ai/assistance/operit/services/ChatServiceCore.kt b/app/src/main/java/com/ai/assistance/operit/services/ChatServiceCore.kt index af44f95dbf..25d6dd8be7 100644 --- a/app/src/main/java/com/ai/assistance/operit/services/ChatServiceCore.kt +++ b/app/src/main/java/com/ai/assistance/operit/services/ChatServiceCore.kt @@ -16,7 +16,7 @@ import com.ai.assistance.operit.services.core.ChatHistoryDelegate import com.ai.assistance.operit.services.core.MessageCoordinationDelegate import com.ai.assistance.operit.services.core.MessageProcessingDelegate import com.ai.assistance.operit.services.core.TokenStatisticsDelegate -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.ui.features.conversation.chat.viewmodel.UiStateDelegate import com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace.process.WorkspaceChangeTracker import com.ai.assistance.operit.util.stream.SharedStream diff --git a/app/src/main/java/com/ai/assistance/operit/services/TermuxCommandResultService.kt b/app/src/main/java/com/ai/assistance/operit/services/TermuxCommandResultService.kt index d39d3218aa..a6354219a4 100644 --- a/app/src/main/java/com/ai/assistance/operit/services/TermuxCommandResultService.kt +++ b/app/src/main/java/com/ai/assistance/operit/services/TermuxCommandResultService.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.services import android.app.IntentService import android.content.Intent import com.ai.assistance.operit.util.logging.AppLogger -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor.CommandResult +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor.CommandResult import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob diff --git a/app/src/main/java/com/ai/assistance/operit/services/core/AttachmentDelegate.kt b/app/src/main/java/com/ai/assistance/operit/services/core/AttachmentDelegate.kt index 5ed0c7115f..3ce44d5b37 100644 --- a/app/src/main/java/com/ai/assistance/operit/services/core/AttachmentDelegate.kt +++ b/app/src/main/java/com/ai/assistance/operit/services/core/AttachmentDelegate.kt @@ -5,13 +5,13 @@ import android.content.Context import android.net.Uri import android.provider.OpenableColumns import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.util.logging.AppLogger import com.ai.assistance.operit.services.core.attachments.ImageAttachmentIndex import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import com.ai.assistance.operit.util.files.OperitPaths -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.DirectoryListingData import com.ai.assistance.operit.core.tools.FileContentData import com.ai.assistance.operit.core.tools.FileExistsData diff --git a/app/src/main/java/com/ai/assistance/operit/services/core/MessageCoordinationDelegate.kt b/app/src/main/java/com/ai/assistance/operit/services/core/MessageCoordinationDelegate.kt index 94298ad0a1..c1864cda86 100644 --- a/app/src/main/java/com/ai/assistance/operit/services/core/MessageCoordinationDelegate.kt +++ b/app/src/main/java/com/ai/assistance/operit/services/core/MessageCoordinationDelegate.kt @@ -26,7 +26,7 @@ import com.ai.assistance.operit.data.model.InputProcessingState import com.ai.assistance.operit.data.model.CharacterCardChatModelBindingMode import com.ai.assistance.operit.data.model.CharacterCardMemoryProfileBindingMode import com.ai.assistance.operit.data.model.ActivePrompt -import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus import com.ai.assistance.operit.ui.features.conversation.chat.viewmodel.UiStateDelegate import com.ai.assistance.operit.data.preferences.CharacterCardManager import com.ai.assistance.operit.data.preferences.CharacterGroupCardManager diff --git a/app/src/main/java/com/ai/assistance/operit/services/core/MessageProcessingDelegate.kt b/app/src/main/java/com/ai/assistance/operit/services/core/MessageProcessingDelegate.kt index a6ef2cafe7..f351fcb35c 100644 --- a/app/src/main/java/com/ai/assistance/operit/services/core/MessageProcessingDelegate.kt +++ b/app/src/main/java/com/ai/assistance/operit/services/core/MessageProcessingDelegate.kt @@ -15,7 +15,7 @@ import com.ai.assistance.operit.api.chat.EnhancedAIService import com.ai.assistance.operit.core.chat.AIMessageManager import com.ai.assistance.operit.core.chat.logMessageTiming import com.ai.assistance.operit.core.chat.messageTimingNow -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.agent.PhoneAgentJobRegistry import com.ai.assistance.operit.data.model.* import com.ai.assistance.operit.data.repository.ChatDraftRepository @@ -52,7 +52,7 @@ import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicLong import kotlin.coroutines.coroutineContext diff --git a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslActions.kt b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslActions.kt index 7bc6c14f4f..b724f5bd96 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslActions.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslActions.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.ui.common.composedsl import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import com.ai.assistance.operit.core.tools.javascript.JsEngine -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult import kotlinx.coroutines.yield @Composable diff --git a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslDebugSnapshotStore.kt b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslDebugSnapshotStore.kt index 95c4cb74ec..ae00808fb1 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslDebugSnapshotStore.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslDebugSnapshotStore.kt @@ -1,8 +1,8 @@ package com.ai.assistance.operit.ui.common.composedsl import android.content.Context -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult import org.json.JSONArray import org.json.JSONObject import org.json.JSONTokener diff --git a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslGeneratedRenderers.kt b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslGeneratedRenderers.kt index 68bedcdab6..62ba7a98f8 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslGeneratedRenderers.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslGeneratedRenderers.kt @@ -49,8 +49,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslParser +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslParser /** * AUTO-GENERATED from Compose Material3/Foundation component bindings. diff --git a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslScreen.kt index 7560157851..ecb50c52f2 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslScreen.kt @@ -162,14 +162,14 @@ import androidx.webkit.ScriptHandler import androidx.webkit.WebViewCompat import androidx.webkit.WebViewFeature import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.javascript.JsEngine import com.ai.assistance.operit.core.tools.javascript.JsJavaBridgeDelegates import com.ai.assistance.operit.core.tools.javascript.extractJsExecutionErrorMessage -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslParser -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslParser +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult import com.ai.assistance.operit.plugins.chatmessage.ChatMessageMenuDialogRequest import com.ai.assistance.operit.ui.common.displays.MarkdownTextComposable import com.ai.assistance.operit.ui.common.markdown.DefaultXmlRenderer diff --git a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebView.kt b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebView.kt index fdf4cfe1ae..e70041b5b2 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebView.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/common/composedsl/ToolPkgComposeDslWebView.kt @@ -44,8 +44,8 @@ import androidx.webkit.WebViewFeature import com.ai.assistance.operit.core.tools.javascript.JsEngine import com.ai.assistance.operit.core.tools.javascript.JsJavaBridgeDelegates import com.ai.assistance.operit.core.tools.javascript.extractJsExecutionErrorMessage -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslParser +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslParser import com.ai.assistance.operit.ui.features.models.token.webview.WebViewConfig import com.ai.assistance.operit.util.logging.AppLogger import org.json.JSONObject diff --git a/app/src/main/java/com/ai/assistance/operit/ui/common/markdown/XmlRenderPluginRegistry.kt b/app/src/main/java/com/ai/assistance/operit/ui/common/markdown/XmlRenderPluginRegistry.kt index 1fad1b4a23..736b48d401 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/common/markdown/XmlRenderPluginRegistry.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/common/markdown/XmlRenderPluginRegistry.kt @@ -24,10 +24,10 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.LinearProgressIndicator -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslParser -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslParser +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult import com.ai.assistance.operit.ui.common.composedsl.LocalComposeDslXmlStream import com.ai.assistance.operit.ui.common.composedsl.RenderToolPkgComposeDslNode import com.ai.assistance.operit.ui.common.composedsl.RetainToolPkgComposeDslActions diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBookmarkSheet.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBookmarkSheet.kt index 1c552771b6..977cb79026 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBookmarkSheet.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBookmarkSheet.kt @@ -25,7 +25,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionBookmark +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionBookmark @Composable internal fun WebSessionBookmarkSheet( diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBrowserScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBrowserScreen.kt index 3ddead823a..4ed03a1ab1 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBrowserScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionBrowserScreen.kt @@ -41,13 +41,13 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionBookmark -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionBrowserHostState -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionBrowserSheetRoute -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionHistoryEntry -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionPendingDialogState -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionWebViewHost -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ui.WebSessionUserscriptUiState +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionBookmark +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionBrowserHostState +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionBrowserSheetRoute +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionHistoryEntry +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionPendingDialogState +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionWebViewHost +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ui.WebSessionUserscriptUiState import java.util.Locale @Composable @@ -488,7 +488,7 @@ private fun PendingDialogOverlay( @Composable private fun WebSessionOverlaySheetContent( sheetRoute: WebSessionBrowserSheetRoute, - browserState: com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionBrowserState, + browserState: com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionBrowserState, bookmarks: List, globalHistory: List, userscriptUiState: WebSessionUserscriptUiState, diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionDownloadSheet.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionDownloadSheet.kt index 5098511c36..89085d4b19 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionDownloadSheet.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionDownloadSheet.kt @@ -25,10 +25,10 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.BrowserDownloadFilter -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.BrowserDownloadItem -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.BrowserDownloadUiState -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.formatBytes +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserDownloadFilter +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserDownloadItem +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.BrowserDownloadUiState +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.formatBytes @OptIn(ExperimentalLayoutApi::class) @Composable diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionHistorySheet.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionHistorySheet.kt index 7e4e42a08d..748db0b0a7 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionHistorySheet.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionHistorySheet.kt @@ -23,8 +23,8 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionHistoryEntry -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionSessionHistoryItem +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionHistoryEntry +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionSessionHistoryItem import java.text.DateFormat import java.util.Date diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMenuSheet.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMenuSheet.kt index 6e9bb1b515..0a3222027d 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMenuSheet.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMenuSheet.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageMenuCommand +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageMenuCommand @Composable internal fun WebSessionMenuSheet( diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMinimizedIndicator.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMinimizedIndicator.kt index b2791fd557..c4ad9e6889 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMinimizedIndicator.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionMinimizedIndicator.kt @@ -57,7 +57,7 @@ internal fun WebSessionMinimizedIndicator( contentDescription: String, activeDownloadCount: Int, hasFailedDownloads: Boolean, - externalOpenPrompt: com.ai.assistance.operit.core.tools.defaultTool.websession.browser.ExternalOpenPromptState?, + externalOpenPrompt: com.ai.assistance.operit.core.tools.builtin.web.session.browser.ExternalOpenPromptState?, onToggleFullscreen: () -> Unit, onDragBy: (dx: Int, dy: Int) -> Unit, onConfirmExternalOpen: (String) -> Unit, diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionTabSheet.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionTabSheet.kt index 8eec55e878..9e38d25eca 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionTabSheet.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionTabSheet.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.browser.WebSessionBrowserTab +import com.ai.assistance.operit.core.tools.builtin.web.session.browser.WebSessionBrowserTab @Composable internal fun WebSessionTabSheet( diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionUserscriptSheet.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionUserscriptSheet.kt index 7bc05b6f5b..4728e35e31 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionUserscriptSheet.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/websession/browser/WebSessionUserscriptSheet.kt @@ -40,12 +40,12 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptInstallPreview -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptListItem -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageMenuCommand -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageRuntimeState -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.UserscriptPageRuntimeStatus -import com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ui.WebSessionUserscriptUiState +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptInstallPreview +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptListItem +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageMenuCommand +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageRuntimeState +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.UserscriptPageRuntimeStatus +import com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ui.WebSessionUserscriptUiState @Composable internal fun WebSessionUserscriptSheet( diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowDetailScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowDetailScreen.kt index 9995d1fa7e..cc0449ba64 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowDetailScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowDetailScreen.kt @@ -31,7 +31,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.ai.assistance.operit.R import com.ai.assistance.operit.core.config.SystemToolPrompts -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.Workflow import com.ai.assistance.operit.data.model.WorkflowNode import com.ai.assistance.operit.data.model.TriggerNode diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowListScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowListScreen.kt index 2ead13578e..ec237d88a4 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowListScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/screens/WorkflowListScreen.kt @@ -81,7 +81,7 @@ import androidx.compose.ui.unit.sp import androidx.compose.ui.window.DialogProperties import androidx.lifecycle.viewmodel.compose.viewModel import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.ExecutionStatus import com.ai.assistance.operit.data.model.Workflow import com.ai.assistance.operit.ui.components.CustomScaffold diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/viewmodel/WorkflowViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/viewmodel/WorkflowViewModel.kt index 7a1626dfcd..9ea7c384c5 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/viewmodel/WorkflowViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/automation/workflow/viewmodel/WorkflowViewModel.kt @@ -8,8 +8,8 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.core.workflow.NodeExecutionState import com.ai.assistance.operit.data.model.ConditionNode import com.ai.assistance.operit.data.model.ConditionOperator diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/AttachmentSelector.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/AttachmentSelector.kt index 720d26bbf1..febf065b99 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/AttachmentSelector.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/AttachmentSelector.kt @@ -79,8 +79,8 @@ import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties import com.ai.assistance.operit.R import com.ai.assistance.operit.ui.features.conversation.chat.attachments.images.ChatImagePickerDialog -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager as ToolPackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager as ToolPackageManager import com.ai.assistance.operit.data.skill.SkillRepository import kotlinx.coroutines.launch import java.io.File diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/SharedFileTargetDialog.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/SharedFileTargetDialog.kt index e60fff9eb1..72e5fe9c5e 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/SharedFileTargetDialog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/SharedFileTargetDialog.kt @@ -35,9 +35,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageFileImportSupport -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.install.PackageFileImportSupport +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.ChatHistory import java.time.format.DateTimeFormatter import java.time.format.FormatStyle diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/agent/AgentChatInputSection.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/agent/AgentChatInputSection.kt index 4a89bbcdae..ee6c4943e9 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/agent/AgentChatInputSection.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/agent/AgentChatInputSection.kt @@ -115,7 +115,7 @@ import com.ai.assistance.operit.api.chat.EnhancedAIService import com.ai.assistance.operit.api.chat.model.ThinkingQualityMapping import com.ai.assistance.operit.api.chat.model.ThinkingQualityMappingRegistry import com.ai.assistance.operit.core.memory.extraction.MemoryAutoSaveScheduler -import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus import com.ai.assistance.operit.data.model.AttachmentInfo import com.ai.assistance.operit.data.model.ChatMessage import com.ai.assistance.operit.data.model.CharacterCardChatModelBindingMode diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/classic/ClassicChatInputSection.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/classic/ClassicChatInputSection.kt index 8dadbeedd7..a0120ffc1c 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/classic/ClassicChatInputSection.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/components/style/input/classic/ClassicChatInputSection.kt @@ -64,7 +64,7 @@ import androidx.compose.ui.tooling.preview.Preview import com.ai.assistance.operit.data.model.AttachmentInfo import com.ai.assistance.operit.data.model.InputProcessingState import com.ai.assistance.operit.data.model.ChatMessage -import com.ai.assistance.operit.core.tools.ToolProgressBus +import com.ai.assistance.operit.core.tools.runtime.ToolProgressBus import com.ai.assistance.operit.ui.common.animations.SimpleAnimatedVisibility import com.ai.assistance.operit.ui.features.conversation.chat.components.AttachmentChip import com.ai.assistance.operit.ui.features.conversation.chat.components.AttachmentSelectorPanel diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/export/htmlpackager/HtmlPackagerScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/export/htmlpackager/HtmlPackagerScreen.kt index fae329ef8a..ae04aad9bf 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/export/htmlpackager/HtmlPackagerScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/export/htmlpackager/HtmlPackagerScreen.kt @@ -22,7 +22,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.documentfile.provider.DocumentFile -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.ui.components.CustomScaffold diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/screens/AIChatScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/screens/AIChatScreen.kt index 9401c1322f..db167cb41b 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/screens/AIChatScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/screens/AIChatScreen.kt @@ -44,7 +44,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.ViewModel import androidx.lifecycle.viewmodel.compose.viewModel import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ApiProviderType import com.ai.assistance.operit.data.model.CharacterCardChatModelBindingMode diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/viewmodel/ChatViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/viewmodel/ChatViewModel.kt index 59dcc4a5f9..9d9eeb990c 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/viewmodel/ChatViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/viewmodel/ChatViewModel.kt @@ -30,7 +30,7 @@ import com.ai.assistance.operit.core.chat.runtime.ChatRuntimeSlot import com.ai.assistance.operit.api.chat.EnhancedAIService import com.ai.assistance.operit.core.chat.AIMessageManager import com.ai.assistance.operit.core.chat.context.ContextWindowBreakdown -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.FileOperationData import com.ai.assistance.operit.data.model.ApiProviderType import com.ai.assistance.operit.data.model.AttachmentInfo @@ -95,7 +95,7 @@ import com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace. import com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace.WorkspacePreviewRefreshBus import com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace.WorkspacePreviewRefreshEvent import com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace.toWorkspaceCommandOutputEntries -import com.ai.assistance.operit.core.tools.system.Terminal +import com.ai.assistance.operit.core.tools.system.terminal.Terminal import com.ai.assistance.operit.core.speech.text.TtsCleaner import com.ai.assistance.operit.core.speech.text.TtsSegmenter import com.ai.assistance.operit.ui.features.conversation.chat.util.findMentionTokens diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/LocalWebServer.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/LocalWebServer.kt index fbc4526202..96f9ea2286 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/LocalWebServer.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/LocalWebServer.kt @@ -7,7 +7,7 @@ import android.system.Os import android.system.OsConstants import android.util.Base64 import android.webkit.CookieManager -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.BinaryFileContentData import com.ai.assistance.operit.core.tools.DirectoryListingData import com.ai.assistance.operit.data.model.AITool diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/WorkspaceFileSelector.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/WorkspaceFileSelector.kt index b1d4325073..c9f63a4c45 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/WorkspaceFileSelector.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/WorkspaceFileSelector.kt @@ -41,8 +41,8 @@ import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager as ToolPackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager as ToolPackageManager import com.ai.assistance.operit.data.skill.SkillRepository import com.ai.assistance.operit.ui.features.conversation.chat.viewmodel.ChatViewModel import com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace.process.GitIgnoreFilter diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/FileManager.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/FileManager.kt index 3181112a10..cc473cc4f8 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/FileManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/FileManager.kt @@ -43,7 +43,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.res.stringResource import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.DirectoryListingData import com.ai.assistance.operit.core.tools.FileContentData import com.ai.assistance.operit.core.tools.FileExistsData diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceBackupManager.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceBackupManager.kt index 572512822d..c1535678f8 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceBackupManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceBackupManager.kt @@ -8,8 +8,8 @@ import com.ai.assistance.operit.core.tools.FileContentData import com.ai.assistance.operit.core.tools.FileExistsData import com.ai.assistance.operit.core.tools.FileInfoData import com.ai.assistance.operit.core.tools.FindFilesResultData -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.AIToolHook +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHook import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.util.logging.AppLogger import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceManager.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceManager.kt index 8b062c89eb..0693188880 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceManager.kt @@ -51,7 +51,7 @@ import androidx.compose.ui.zIndex import com.ai.assistance.operit.R import com.ai.assistance.operit.ui.features.conversation.chat.workspace.WorkspaceEntryAction import com.ai.assistance.operit.ui.features.conversation.chat.workspace.WorkspaceEntryRequest -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.FileContentData import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ChatHistory diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceReadOnlyDocumentPreview.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceReadOnlyDocumentPreview.kt index e1cf314baa..92d477019f 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceReadOnlyDocumentPreview.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceReadOnlyDocumentPreview.kt @@ -35,7 +35,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.BinaryFileContentData import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceSetup.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceSetup.kt index cff79dd443..f67fe030da 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceSetup.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/WorkspaceSetup.kt @@ -18,8 +18,8 @@ import com.ai.assistance.operit.ui.features.conversation.chat.webview.createAndG import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.ui.features.conversation.chat.webview.createAndResetWorkspaceDirectory import kotlinx.coroutines.* diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/browser/WorkspaceBrowserOperations.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/browser/WorkspaceBrowserOperations.kt index 40de9edb8d..54638573c6 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/browser/WorkspaceBrowserOperations.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/browser/WorkspaceBrowserOperations.kt @@ -5,7 +5,7 @@ import android.content.Intent import android.util.Base64 import androidx.core.content.FileProvider import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.BinaryFileContentData import com.ai.assistance.operit.core.tools.FileExistsData import com.ai.assistance.operit.data.model.AITool diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/links/WorkspaceFileLinkHost.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/links/WorkspaceFileLinkHost.kt index 29976bfb2b..4fe30721e9 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/links/WorkspaceFileLinkHost.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/links/WorkspaceFileLinkHost.kt @@ -17,7 +17,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.FileContentData import com.ai.assistance.operit.core.tools.FileExistsData import com.ai.assistance.operit.data.model.AITool diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/process/WorkspaceRuleFileReader.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/process/WorkspaceRuleFileReader.kt index 65cbfcf5ea..5db4f1f3dc 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/process/WorkspaceRuleFileReader.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/chat/webview/workspace/process/WorkspaceRuleFileReader.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.ui.features.conversation.chat.webview.workspace.process import android.content.Context -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.FileContentData import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/viewmodel/MemoryViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/viewmodel/MemoryViewModel.kt index 5c85fe149e..51b9145537 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/viewmodel/MemoryViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/viewmodel/MemoryViewModel.kt @@ -17,7 +17,7 @@ import com.ai.assistance.operit.data.repository.MemoryRepository import com.ai.assistance.operit.ui.features.conversation.memory.screens.graph.model.Edge import com.ai.assistance.operit.ui.features.conversation.memory.screens.graph.model.Graph import com.ai.assistance.operit.ui.features.conversation.memory.screens.graph.model.Node -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.R diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/workbench/MemoryDocumentImporter.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/workbench/MemoryDocumentImporter.kt index 1c03b76172..3bc00f6a52 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/workbench/MemoryDocumentImporter.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/conversation/memory/workbench/MemoryDocumentImporter.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.ui.features.conversation.memory.workbench import android.content.Context import android.net.Uri import android.provider.OpenableColumns -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/MCPPackageDetailsDialog.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/MCPPackageDetailsDialog.kt index 31d01f46e7..c1b276068c 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/MCPPackageDetailsDialog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/MCPPackageDetailsDialog.kt @@ -57,7 +57,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.LocalizedText import com.ai.assistance.operit.core.tools.PackageTool import com.ai.assistance.operit.core.tools.PackageToolParameter diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageAddActionDialog.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageAddActionDialog.kt index b29d5a5ebe..ce83cf0600 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageAddActionDialog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageAddActionDialog.kt @@ -32,7 +32,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.packTool.PackageTemplateKind +import com.ai.assistance.operit.core.tools.packTool.install.PackageTemplateKind /** * 包管理加号弹出的中心选择面板。 diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageDetailsDialog.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageDetailsDialog.kt index 10ac316e75..ec768b2429 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageDetailsDialog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageDetailsDialog.kt @@ -34,8 +34,8 @@ import com.ai.assistance.operit.ui.features.extensions.packages.components.dialo import com.ai.assistance.operit.ui.features.extensions.packages.components.dialogs.packageui.PackageEnvironmentSection import com.ai.assistance.operit.ui.features.extensions.packages.components.dialogs.packageui.PackageToolCard import com.ai.assistance.operit.core.tools.ToolPackage -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.ToolPkgRuntimeMonitor +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.ToolPkgRuntimeMonitor import com.ai.assistance.operit.ui.common.icons.rememberLogoPainter import java.text.SimpleDateFormat import java.util.Date diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageTemplateIdentityDialog.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageTemplateIdentityDialog.kt index d4a7371f74..43f2d9d556 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageTemplateIdentityDialog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/PackageTemplateIdentityDialog.kt @@ -18,8 +18,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.packTool.PackageTemplateFactory -import com.ai.assistance.operit.core.tools.packTool.PackageTemplateKind +import com.ai.assistance.operit.core.tools.packTool.install.PackageTemplateFactory +import com.ai.assistance.operit.core.tools.packTool.install.PackageTemplateKind /** 新建模板前填写显示名和包标识,避免落盘出未命名垃圾包。 */ @Composable diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/ScriptExecutionDialog.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/ScriptExecutionDialog.kt index 2aa74c0b5d..39a41d3c6d 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/ScriptExecutionDialog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/dialogs/ScriptExecutionDialog.kt @@ -25,7 +25,7 @@ import com.ai.assistance.operit.core.tools.PackageTool import com.ai.assistance.operit.core.tools.ScriptExecutionTraceData import com.ai.assistance.operit.core.tools.StringResultData import com.ai.assistance.operit.core.tools.javascript.JsToolManager -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/ArtifactLocalInstallSupport.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/ArtifactLocalInstallSupport.kt index eccad63694..c7da97b112 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/ArtifactLocalInstallSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/ArtifactLocalInstallSupport.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.ui.features.extensions.packages.market import android.content.Context -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.api.ArtifactProjectVersionResponse import com.ai.assistance.operit.data.api.MarketV2Entry import com.ai.assistance.operit.data.transfer.copyWithTransferProgress diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/GitHubForgePublishService.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/GitHubForgePublishService.kt index 2ae8808fef..901231ae5e 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/GitHubForgePublishService.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/GitHubForgePublishService.kt @@ -12,7 +12,7 @@ import com.ai.assistance.operit.data.api.MarketV2PublishRequest import com.ai.assistance.operit.data.api.MarketV2PublishVersion import com.ai.assistance.operit.data.api.MarketV2Version import com.ai.assistance.operit.data.preferences.GitHubAuthPreferences -import com.ai.assistance.operit.core.tools.packTool.ToolPkgMarketOrigin +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOrigin import com.ai.assistance.operit.core.tools.packTool.minify.ToolPkgArtifactMinifier import java.io.File import java.net.URI diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketEntryInstallController.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketEntryInstallController.kt index 0079a31ee4..e81a28eabe 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketEntryInstallController.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketEntryInstallController.kt @@ -4,8 +4,8 @@ import com.ai.assistance.operit.ui.common.oktoast.OKToast import android.content.Context import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.api.MarketStatsApiService import com.ai.assistance.operit.data.api.MarketV2Entry import com.ai.assistance.operit.data.mcp.InstallResult diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketInstallMarker.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketInstallMarker.kt index dea710080e..6923c50a5c 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketInstallMarker.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/market/MarketInstallMarker.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.ui.features.extensions.packages.market import android.content.Context -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.api.MarketV2Entry import com.ai.assistance.operit.data.mcp.MCPLocalServer import com.ai.assistance.operit.data.skill.SkillRepository diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerDialogs.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerDialogs.kt index 97a65f4662..f62cb2a505 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerDialogs.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerDialogs.kt @@ -54,7 +54,7 @@ import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R import com.ai.assistance.operit.core.tools.EnvVar import com.ai.assistance.operit.core.tools.ToolPackage -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager @Composable fun PackageLoadErrorsDialog( diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerScreen.kt index 89a7e5d7cc..23aa2c3742 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageManagerScreen.kt @@ -52,15 +52,15 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.PackageTool import com.ai.assistance.operit.core.tools.ToolPackage import com.ai.assistance.operit.core.tools.EnvVar -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.PackageTemplateCreateError -import com.ai.assistance.operit.core.tools.packTool.PackageTemplateFactory -import com.ai.assistance.operit.core.tools.packTool.PackageTemplateKind -import com.ai.assistance.operit.core.tools.packTool.ToolPkgMarketOrigin +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.install.PackageTemplateCreateError +import com.ai.assistance.operit.core.tools.packTool.install.PackageTemplateFactory +import com.ai.assistance.operit.core.tools.packTool.install.PackageTemplateKind +import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOrigin import com.ai.assistance.operit.data.mcp.MCPRepository import com.ai.assistance.operit.data.preferences.EnvPreferences import com.ai.assistance.operit.data.preferences.ApiPreferences diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageSearch.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageSearch.kt index 66c8086c17..ca77b21fc6 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageSearch.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PackageSearch.kt @@ -3,7 +3,7 @@ package com.ai.assistance.operit.ui.features.extensions.packages.screens import android.content.Context import com.ai.assistance.operit.core.tools.PackageTool import com.ai.assistance.operit.core.tools.ToolPackage -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager fun packageMatchesSearch( context: Context, diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PluginTabContent.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PluginTabContent.kt index 79252ddec4..0c580ec93c 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PluginTabContent.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/PluginTabContent.kt @@ -49,7 +49,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.core.tools.packTool.metadata.PluginActivity import com.ai.assistance.operit.ui.common.icons.rememberLogoPainter import com.ai.assistance.operit.ui.features.extensions.packages.components.EmptyState diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/QuickPluginCreatorSetupSupport.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/QuickPluginCreatorSetupSupport.kt index c0f2f5b0c0..08ad25bb0d 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/QuickPluginCreatorSetupSupport.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/QuickPluginCreatorSetupSupport.kt @@ -3,9 +3,9 @@ package com.ai.assistance.operit.ui.features.extensions.packages.screens import android.content.Context import android.os.Environment import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.ToolParameter import com.ai.assistance.operit.data.model.ToolResult diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/artifact/viewmodel/ArtifactMarketViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/artifact/viewmodel/ArtifactMarketViewModel.kt index aefd5a2b4f..67bc40a82e 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/artifact/viewmodel/ArtifactMarketViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/artifact/viewmodel/ArtifactMarketViewModel.kt @@ -8,8 +8,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.api.MarketStatsApiService import com.ai.assistance.operit.data.api.GitHubApiService import com.ai.assistance.operit.data.api.MarketV2EntryUpdateRequest diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketBrowseViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketBrowseViewModel.kt index 059d222c9e..1dfe096866 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketBrowseViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketBrowseViewModel.kt @@ -8,8 +8,8 @@ import com.ai.assistance.operit.data.api.MarketStatsApiService import com.ai.assistance.operit.data.api.MarketV2Entry import com.ai.assistance.operit.data.api.MarketV2ManifestCategory import com.ai.assistance.operit.data.api.MarketV2Notification -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.ui.features.extensions.packages.market.MarketEntryInstallController import com.ai.assistance.operit.ui.features.extensions.packages.market.MarketInstallProgress import com.ai.assistance.operit.ui.features.extensions.packages.market.MarketInstallStateStore diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketDetailViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketDetailViewModel.kt index 5e36f2b56d..8ec860b4d8 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketDetailViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/extensions/packages/screens/market/viewmodel/UnifiedMarketDetailViewModel.kt @@ -4,8 +4,8 @@ import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.R import com.ai.assistance.operit.data.api.GitHubApiService import com.ai.assistance.operit.data.api.MarketStatsApiService diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/management/resources/hub/ResourceHubViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/management/resources/hub/ResourceHubViewModel.kt index 952d0985f3..ab4142aa6f 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/management/resources/hub/ResourceHubViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/management/resources/hub/ResourceHubViewModel.kt @@ -2,7 +2,7 @@ package com.ai.assistance.operit.ui.features.management.resources.hub import android.app.Application import android.os.SystemClock -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import android.net.Uri import android.provider.DocumentsContract import android.provider.OpenableColumns diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/components/CharacterCardDialog.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/components/CharacterCardDialog.kt index a95d3ac899..383c9ad24f 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/components/CharacterCardDialog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/components/CharacterCardDialog.kt @@ -48,8 +48,8 @@ import com.ai.assistance.operit.data.model.getModelByIndex import com.ai.assistance.operit.data.model.getModelList import com.ai.assistance.operit.data.model.getValidModelIndex import com.ai.assistance.operit.core.config.SystemToolPrompts -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.preferences.ModelConfigManager import com.ai.assistance.operit.data.preferences.WaifuPreferences import com.ai.assistance.operit.data.preferences.WaifuSettings diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/display/DisplayBehaviorState.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/display/DisplayBehaviorState.kt index cb90f266f2..bfadbdf37b 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/display/DisplayBehaviorState.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/display/DisplayBehaviorState.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import com.ai.assistance.operit.api.chat.AIForegroundService -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.preferences.ApiPreferences import com.ai.assistance.operit.data.preferences.DisplayPreferencesManager import com.ai.assistance.operit.data.preferences.OrientationReloadPolicy diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/toolpermissions/ToolPermissionPage.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/toolpermissions/ToolPermissionPage.kt index 091326876e..eaf21a2fb7 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/toolpermissions/ToolPermissionPage.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/management/settings/toolpermissions/ToolPermissionPage.kt @@ -20,7 +20,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.ui.common.oktoast.OKToast import com.ai.assistance.operit.ui.main.LocalTopBarTitleContent import com.ai.assistance.operit.ui.main.TopBarTitleContent diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageScreen.kt index cc06a87562..65444907f5 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageScreen.kt @@ -28,7 +28,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.storage.ExtensionCategory import com.ai.assistance.operit.data.storage.ExtensionItem import com.ai.assistance.operit.data.storage.formatStorageSize diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageViewModel.kt index b97de966d3..8ce39846ad 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/ConfigurationResourceStorageViewModel.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.storage.ConfigurationResourceEntry import com.ai.assistance.operit.data.storage.ConfigurationResourceInventory import com.ai.assistance.operit.data.storage.ConfigurationResourceSnapshot diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/DataStorageScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/DataStorageScreen.kt index 74d880d1f6..a278d73951 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/DataStorageScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/management/storage/DataStorageScreen.kt @@ -75,7 +75,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.defaultTool.standard.CookiePrivacyManager +import com.ai.assistance.operit.core.tools.builtin.web.CookiePrivacyManager import com.ai.assistance.operit.data.storage.CleanupTarget import com.ai.assistance.operit.data.storage.CleanupTargetUsage import com.ai.assistance.operit.data.storage.DataStorageSnapshot diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/components/PermissionLevelCard.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/components/PermissionLevelCard.kt index da4113acce..e8ebaecfad 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/components/PermissionLevelCard.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/components/PermissionLevelCard.kt @@ -49,7 +49,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.ai.assistance.operit.R import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilities -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.preferences.androidPermissionPreferences import com.ai.assistance.operit.ui.features.support.demo.permissions.SystemPermission import com.ai.assistance.operit.ui.features.support.demo.permissions.SystemPermissionStatus @@ -861,7 +861,7 @@ private fun ShizukuPermissionSection( // 检查Shizuku是否需要更新 val isShizukuUpdateNeeded = remember(isShizukuInstalled, isShizukuRunning, hasShizukuPermission) { try { - com.ai.assistance.operit.core.tools.system.ShizukuInstaller.isShizukuUpdateNeeded( + com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuInstaller.isShizukuUpdateNeeded( context ) } catch (e: Exception) { diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/screens/ShizukuDemoScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/screens/ShizukuDemoScreen.kt index 0a41f47c99..4265b9adaf 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/screens/ShizukuDemoScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/screens/ShizukuDemoScreen.kt @@ -26,12 +26,12 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.viewmodel.compose.viewModel import com.ai.assistance.operit.R -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.ui.main.screens.Screen import com.ai.assistance.operit.ui.main.screens.ScreenNavigationHandler -import com.ai.assistance.operit.core.tools.system.AccessibilityProviderInstaller -import com.ai.assistance.operit.core.tools.system.ShizukuAuthorizer -import com.ai.assistance.operit.core.tools.system.ShizukuInstaller +import com.ai.assistance.operit.core.tools.permissions.authorization.AccessibilityProviderInstaller +import com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuAuthorizer +import com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuInstaller import com.ai.assistance.operit.data.repository.UIHierarchyManager import com.ai.assistance.operit.ui.features.support.demo.components.* import com.ai.assistance.operit.ui.features.support.demo.permissions.SystemPermissionSettings diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/state/DemoStateManager.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/state/DemoStateManager.kt index 2074cc8ceb..6b301ad23f 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/state/DemoStateManager.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/state/DemoStateManager.kt @@ -9,8 +9,8 @@ import android.provider.Settings import com.ai.assistance.operit.util.logging.AppLogger import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import com.ai.assistance.operit.core.tools.system.OperitTerminalManager -import com.ai.assistance.operit.core.tools.system.RootAuthorizer +import com.ai.assistance.operit.core.tools.system.terminal.OperitTerminalManager +import com.ai.assistance.operit.core.tools.permissions.authorization.RootAuthorizer import com.ai.assistance.operit.data.repository.UIHierarchyManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay @@ -23,9 +23,9 @@ import android.content.pm.PackageManager import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.ai.assistance.operit.core.tools.system.AccessibilityProviderInstaller -import com.ai.assistance.operit.core.tools.system.ShizukuAuthorizer -import com.ai.assistance.operit.core.tools.system.Terminal +import com.ai.assistance.operit.core.tools.permissions.authorization.AccessibilityProviderInstaller +import com.ai.assistance.operit.core.tools.permissions.authorization.ShizukuAuthorizer +import com.ai.assistance.operit.core.tools.system.terminal.Terminal import com.ai.assistance.operit.data.mcp.plugins.MCPSharedSession import com.ai.assistance.operit.R import com.ai.assistance.operit.ui.features.support.demo.permissions.SystemPermissionSettings diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/viewmodel/ShizukuDemoViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/viewmodel/ShizukuDemoViewModel.kt index de503bed4e..b62ecd3419 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/viewmodel/ShizukuDemoViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/support/demo/viewmodel/ShizukuDemoViewModel.kt @@ -9,8 +9,8 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.system.RootAuthorizer +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.permissions.authorization.RootAuthorizer import com.ai.assistance.operit.R import com.ai.assistance.operit.ui.features.support.demo.state.DemoStateManager import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/ai/assistance/operit/ui/features/support/diagnostics/uidebugger/UIDebuggerViewModel.kt b/app/src/main/java/com/ai/assistance/operit/ui/features/support/diagnostics/uidebugger/UIDebuggerViewModel.kt index 99409f3cd2..1c3ec92b02 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/features/support/diagnostics/uidebugger/UIDebuggerViewModel.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/features/support/diagnostics/uidebugger/UIDebuggerViewModel.kt @@ -4,7 +4,7 @@ import android.content.Context import android.graphics.Rect import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.core.tools.UIPageResultData import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.core.tools.system.action.ActionListener diff --git a/app/src/main/java/com/ai/assistance/operit/ui/floating/ui/screenocr/screen/FloatingScreenOcrScreen.kt b/app/src/main/java/com/ai/assistance/operit/ui/floating/ui/screenocr/screen/FloatingScreenOcrScreen.kt index d00842d996..51a6c7fbf3 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/floating/ui/screenocr/screen/FloatingScreenOcrScreen.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/floating/ui/screenocr/screen/FloatingScreenOcrScreen.kt @@ -69,7 +69,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.model.AITool import com.ai.assistance.operit.data.model.AttachmentInfo import com.ai.assistance.operit.ui.floating.FloatContext diff --git a/app/src/main/java/com/ai/assistance/operit/ui/main/MainActivity.kt b/app/src/main/java/com/ai/assistance/operit/ui/main/MainActivity.kt index 089e6b6a9d..999f5a4920 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/main/MainActivity.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/main/MainActivity.kt @@ -34,7 +34,7 @@ import androidx.lifecycle.lifecycleScope import com.ai.assistance.operit.R import com.ai.assistance.operit.api.chat.AIForegroundService import com.ai.assistance.operit.core.application.OperitApplication -import com.ai.assistance.operit.core.tools.AIToolHandler +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler import com.ai.assistance.operit.data.preferences.AgreementPreferences import com.ai.assistance.operit.data.preferences.DisplayPreferencesManager import com.ai.assistance.operit.data.preferences.OrientationReloadPolicy diff --git a/app/src/main/java/com/ai/assistance/operit/ui/main/OperitApp.kt b/app/src/main/java/com/ai/assistance/operit/ui/main/OperitApp.kt index 802f09088e..61543ce3d5 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/main/OperitApp.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/main/OperitApp.kt @@ -24,8 +24,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.compose.ui.res.stringResource import androidx.navigation.compose.rememberNavController -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.data.mcp.MCPRepository import com.ai.assistance.operit.data.security.PluginDenylistRepository import com.ai.assistance.operit.data.preferences.ApiPreferences diff --git a/app/src/main/java/com/ai/assistance/operit/ui/main/components/DrawerContent.kt b/app/src/main/java/com/ai/assistance/operit/ui/main/components/DrawerContent.kt index f356f98e62..15971e530d 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/main/components/DrawerContent.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/main/components/DrawerContent.kt @@ -66,10 +66,10 @@ import com.ai.assistance.operit.ui.features.conversation.chat.sidebar.LocalRunMa import com.ai.assistance.operit.ui.features.conversation.chat.sidebar.LocalMainChatViewModel import com.ai.assistance.operit.ui.features.conversation.chat.sidebar.LocalMainChatSidebarState import com.ai.assistance.operit.ui.theme.LocalThemePreferenceSnapshot -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager import com.ai.assistance.operit.core.tools.permissions.PermissionCapabilityResolver -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import com.ai.assistance.operit.data.preferences.UserPreferencesManager import com.ai.assistance.operit.data.preferences.androidPermissionPreferences diff --git a/app/src/main/java/com/ai/assistance/operit/ui/main/navigation/AppRouteCatalog.kt b/app/src/main/java/com/ai/assistance/operit/ui/main/navigation/AppRouteCatalog.kt index 85af5b1b3d..829198027c 100644 --- a/app/src/main/java/com/ai/assistance/operit/ui/main/navigation/AppRouteCatalog.kt +++ b/app/src/main/java/com/ai/assistance/operit/ui/main/navigation/AppRouteCatalog.kt @@ -3,9 +3,9 @@ package com.ai.assistance.operit.ui.main.navigation import android.content.Context import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Extension -import com.ai.assistance.operit.core.tools.AIToolHandler -import com.ai.assistance.operit.core.tools.packTool.PackageManager -import com.ai.assistance.operit.core.tools.packTool.TOOLPKG_NAV_SURFACE_MAIN_SIDEBAR_PLUGINS +import com.ai.assistance.operit.core.tools.runtime.AIToolHandler +import com.ai.assistance.operit.core.tools.packTool.runtime.PackageManager +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_NAV_SURFACE_MAIN_SIDEBAR_PLUGINS import com.ai.assistance.operit.ui.common.icons.MaterialIconNameResolver import com.ai.assistance.operit.ui.main.screens.Screen import com.ai.assistance.operit.ui.main.screens.ScreenRouteRegistry diff --git a/app/src/test/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManagerResultLimitTest.kt b/app/src/test/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManagerResultLimitTest.kt index 9558c23365..2040f4392b 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManagerResultLimitTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/chat/protocol/ConversationMarkupManagerResultLimitTest.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.core.chat.protocol import com.ai.assistance.operit.core.tools.StringResultData -import com.ai.assistance.operit.core.tools.ToolExecutionLimits +import com.ai.assistance.operit.core.tools.runtime.ToolExecutionLimits import com.ai.assistance.operit.data.model.ToolResult import com.ai.assistance.operit.core.chat.protocol.ChatMarkupRegex import org.junit.Assert.assertEquals diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolsTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolsTest.kt similarity index 99% rename from app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolsTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolsTest.kt index c6760ccdd6..d15a488c0e 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolsTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolsTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.a2ui +package com.ai.assistance.operit.core.tools.builtin.a2ui import com.ai.assistance.operit.core.chat.tools.ToolExecutionManager.ToolRuntimeContext import com.ai.assistance.operit.core.tools.StringResultData diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupportTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupportTest.kt similarity index 95% rename from app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupportTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupportTest.kt index e778d4597b..c97f772b36 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupportTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupportTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.settings import com.ai.assistance.operit.ui.permissions.PermissionLevel import org.junit.Assert.assertEquals diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafetyTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafetyTest.kt similarity index 98% rename from app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafetyTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafetyTest.kt index 171c3a1c21..59b12bbe11 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafetyTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafetyTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.standard +package com.ai.assistance.operit.core.tools.builtin.shell import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicyTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicyTest.kt similarity index 98% rename from app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicyTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicyTest.kt index 13e64bb888..e080f0701a 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicyTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicyTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.defaultTool.websession.browser +package com.ai.assistance.operit.core.tools.builtin.web.session.browser import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetentionTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetentionTest.kt index 3a0c7e1f15..6f8d9bdb9f 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetentionTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/javascript/ComposeDslActionRetentionTest.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.core.tools.javascript -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslNode -import com.ai.assistance.operit.core.tools.packTool.ToolPkgComposeDslRenderResult +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslNode +import com.ai.assistance.operit.core.tools.packTool.uidsl.ToolPkgComposeDslRenderResult import org.junit.Assert.assertEquals import org.junit.Test diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupportTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupportTest.kt similarity index 93% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupportTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupportTest.kt index d35cf46331..758a06c0d9 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupportTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupportTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.install import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletionTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletionTest.kt similarity index 97% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletionTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletionTest.kt index 0029e8141d..44142da237 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletionTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletionTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.install import java.io.File import org.junit.Assert.* diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactoryTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactoryTest.kt similarity index 98% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactoryTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactoryTest.kt index 21b9a260f0..b2e2dce0c4 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactoryTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactoryTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.install import java.io.File import java.util.zip.ZipFile diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiDeclarationTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiDeclarationTest.kt similarity index 94% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiDeclarationTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiDeclarationTest.kt index 4120602b8e..ea22409f93 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiDeclarationTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiDeclarationTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOriginCodecTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOriginCodecTest.kt similarity index 97% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOriginCodecTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOriginCodecTest.kt index 852d956d03..901b81b2ba 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOriginCodecTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOriginCodecTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.metadata import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestSelectionTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgManifestSelectionTest.kt similarity index 96% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestSelectionTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgManifestSelectionTest.kt index ad599bdbc0..0baf087163 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestSelectionTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgManifestSelectionTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.parser import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResultTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResultTest.kt similarity index 97% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResultTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResultTest.kt index cb08885360..0d021ab2fa 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResultTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResultTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime import com.ai.assistance.operit.core.tools.PackageActivationErrorCode import com.ai.assistance.operit.core.tools.PackageActivationErrorData diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManagerTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManagerTest.kt similarity index 98% rename from app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManagerTest.kt rename to app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManagerTest.kt index 07da7c22b6..4ef2f1134d 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManagerTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManagerTest.kt @@ -1,4 +1,4 @@ -package com.ai.assistance.operit.core.tools.packTool +package com.ai.assistance.operit.core.tools.packTool.runtime import android.content.Context import com.ai.assistance.operit.core.tools.javascript.JsEngine diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt index 6fb6590b6f..0159b753dd 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitiesTest.kt @@ -1,7 +1,7 @@ package com.ai.assistance.operit.core.tools.permissions -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel -import com.ai.assistance.operit.core.tools.system.ShellIdentity +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.system.shell.ShellIdentity import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Test diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySessionTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySessionTest.kt index 8d60cc3334..1ef141d541 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySessionTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionCapabilitySessionTest.kt @@ -1,6 +1,6 @@ package com.ai.assistance.operit.core.tools.permissions -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Test diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionOperationRouterTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionOperationRouterTest.kt index 3a9fcf4e80..9dd4d378e8 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionOperationRouterTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/permissions/PermissionOperationRouterTest.kt @@ -1,6 +1,6 @@ package com.ai.assistance.operit.core.tools.permissions -import com.ai.assistance.operit.core.tools.system.AndroidPermissionLevel +import com.ai.assistance.operit.core.tools.permissions.AndroidPermissionLevel import kotlinx.coroutines.CancellationException import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals diff --git a/app/src/test/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuardTest.kt b/app/src/test/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuardTest.kt index e2bf47f33c..e1219bb19b 100644 --- a/app/src/test/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuardTest.kt +++ b/app/src/test/java/com/ai/assistance/operit/core/tools/system/uiautomator/UiAutomatorDumpGuardTest.kt @@ -1,6 +1,6 @@ package com.ai.assistance.operit.core.tools.system.uiautomator -import com.ai.assistance.operit.core.tools.system.AndroidShellExecutor +import com.ai.assistance.operit.core.tools.system.shell.AndroidShellExecutor import java.io.File import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicInteger diff --git a/docs/TODO/chore/README.md b/docs/TODO/chore/README.md index 86074d4ee5..3139c84750 100644 --- a/docs/TODO/chore/README.md +++ b/docs/TODO/chore/README.md @@ -6,6 +6,8 @@ ## 计划索引 +- [工具权限收口与目录整理](tools-permissions-layout/index.md) + - [1.12.2+15 分仓与布局修复发行](release-1.12.2-plus-15/index.md) - [正式版、补丁与离线资源分仓](release-repositories/index.md) diff --git a/docs/TODO/chore/tools-permissions-layout/01-permissions.md b/docs/TODO/chore/tools-permissions-layout/01-permissions.md index 9e793884e5..48621d0dcb 100644 --- a/docs/TODO/chore/tools-permissions-layout/01-permissions.md +++ b/docs/TODO/chore/tools-permissions-layout/01-permissions.md @@ -20,6 +20,6 @@ - [x] 管理员包含原无障碍和 Shell 操作,Root 保留原操作行为 - [x] 运行时模式只有标准、管理员、Root,旧偏好可迁移 - [x] 工具名称、参数和结果格式保持现有契约 -- [x] 静态引用与语法检查完成,操作体迁移逐项对比;仓库验证尚未派发 +- [x] 静态引用与语法检查完成,操作体迁移逐项对比;仓库编译与运行验证结果在 PR 中记录 [DONE] 权限收口代码及静态核对完成,运行验证以工作流结果为准。 diff --git a/docs/TODO/chore/tools-permissions-layout/02-layout.md b/docs/TODO/chore/tools-permissions-layout/02-layout.md new file mode 100644 index 0000000000..f7ab80bf3d --- /dev/null +++ b/docs/TODO/chore/tools-permissions-layout/02-layout.md @@ -0,0 +1,303 @@ +# 02 工具目录迁移 + +权限收口提交完成后读取工具源码,再以 [files.json](files.json) 作为本批逐文件迁移依据。清单记录当前路径、目标路径、源包名、目标包名和源文件摘要;执行前核对摘要,执行后核对文件与包名。 + +## 目标结构 + +以下仅展示本批涉及的目录,其余已有职责目录保持原有归属。 + +```text +core/tools/ + builtin/ + filesystem/ + ui/ + device/ + system/ + shell/ + terminal/ + web/ + session/ + calculator/ + workflow/ + chat/ + settings/ + media/ + memory/ + a2ui/ + packTool/ + PackageDebugRefreshReceiver.kt + ToolPkgDebugInstallReceiver.kt + ToolPkgComposeDslDebugDumpReceiver.kt + parser/ + loader/ + runtime/ + install/ + minify/ + uidsl/ + metadata/ + runtime/ + permissions/ + authorization/ + system/ + shell/ + capture/ + terminal/ +``` + +## 迁移规则 + +- 内置工具按功能组织,标准、管理员、Root 实现放在同一功能目录 +- 插件包按解析、加载、运行、安装、压缩、UI DSL 和元数据归类 +- 工具执行与注册入口集中到 runtime,授权安装与检测集中到 permissions/authorization +- 同步 Kotlin 引用、同包隐式依赖、Manifest 组件、脚本显式组件及测试资源路径 +- 目录迁移保持具体操作体,既有逻辑完善分别记录在权限收口提交中 + +- 安装、刷新与 UI DSL 调试广播接收器保留既有公开组件名,现有 ADB 与编辑器调用继续使用原入口 + +## 文件清单 + +共 117 个文件,迁移 111 个,保留已合理分区或已有公开入口的文件 6 个。以下路径均相对于仓库根目录。 + +- 迁移:`app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/ffmpeg/ffmpeg_probe.js` + - 目标:`app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/media/ffmpeg/ffmpeg_probe.js` +- 迁移:`app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/main.js` + - 目标:`app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/main.js` +- 迁移:`app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/probe.js` + - 目标:`app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/probe.js` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ToolGetter.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolDefinitions.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolDefinitions.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolRuntime.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolRuntime.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardCalculator.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/calculator/StandardCalculator.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardChatManagerTool.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/chat/StandardChatManagerTool.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardDeviceInfoToolExecutor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/device/StandardDeviceInfoToolExecutor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/PathValidator.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/PathValidator.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/AdminFileSystemTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/LinuxFileSystemTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/LinuxFileSystemTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/SafFileSystemTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/SafFileSystemTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFileSystemTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/StandardFileSystemTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/BluetoothSessionManager.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/BluetoothSessionManager.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFFmpegTool.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardFFmpegTool.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardMusicPlaybackTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardMusicPlaybackTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/MemoryQueryToolExecutor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/memory/MemoryQueryToolExecutor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSoftwareSettingsModifyTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/StandardSoftwareSettingsModifyTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupport.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupport.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafety.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafety.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardShellToolExecutor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/StandardShellToolExecutor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/AdminSystemOperationTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardIntentToolExecutor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardIntentToolExecutor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSendBroadcastToolExecutor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSendBroadcastToolExecutor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSystemOperationTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSystemOperationTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardTerminalCommandExecutor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/terminal/StandardTerminalCommandExecutor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/AdminUITools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/RootUITools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/StandardUITools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/CookiePrivacyManager.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/CookiePrivacyManager.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardBrowserSessionTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardBrowserSessionTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardHttpTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardHttpTools.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWebVisitTool.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardWebVisitTool.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserDownloadSupport.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserDownloadSupport.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicy.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicy.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserPageExecutionSupport.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserPageExecutionSupport.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserToolSupport.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserToolSupport.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserWebViewSupport.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserWebViewSupport.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHost.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHost.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHostState.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHostState.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionHistoryStore.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionHistoryStore.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionPermissionRequestActivity.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionPermissionRequestActivity.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionWebViewHost.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionWebViewHost.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptCapabilityRegistry.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptCapabilityRegistry.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMatcher.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMatcher.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMetadataParser.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMetadataParser.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptModels.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptModels.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportCoordinator.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportCoordinator.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportPickerActivity.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportPickerActivity.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptBootstrapScript.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptBootstrapScript.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptCookieService.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptCookieService.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptStorageNotifier.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptStorageNotifier.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptTabStateStore.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptTabStateStore.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptWebRequestEngine.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptWebRequestEngine.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/WebSessionUserscriptManager.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/WebSessionUserscriptManager.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptEntities.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptEntities.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptJsonStore.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptJsonStore.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptRepository.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptRepository.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/ui/WebSessionUserscriptUiStateStore.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/ui/WebSessionUserscriptUiStateStore.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWorkflowTools.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/builtin/workflow/StandardWorkflowTools.kt` +- 保留:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt` +- 保留:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslDebugDumpReceiver.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslDebugDumpReceiver.kt` +- 保留:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupport.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupport.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletion.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletion.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactory.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactory.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoadOrder.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoadOrder.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoader.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoader.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/BuiltInPackageDefaults.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/BuiltInPackageDefaults.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiVersion.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiVersion.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgCommonPluginConstants.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgCommonPluginConstants.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestRequirement.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgManifestRequirement.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOrigin.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOrigin.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgTemplateModels.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgTemplateModels.kt` +- 保留:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/PluginActivityStore.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/PluginActivityStore.kt` +- 保留:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt` +- 保留:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgJsAstMinifier.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgJsAstMinifier.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMainRegistrationScriptParser.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgParser.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResult.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResult.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManager.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManager.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManagerToolPkgFacade.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManagerToolPkgFacade.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgHookModels.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgHookModels.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManager.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManager.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgRuntimeMonitor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgRuntimeMonitor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslParser.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/uidsl/ToolPkgComposeDslParser.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/permissions/AndroidPermissionLevel.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/AccessibilityProviderInstaller.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/AccessibilityProviderInstaller.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/RootAuthorizer.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/RootAuthorizer.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuAuthorizer.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuAuthorizer.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuInstaller.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuInstaller.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHandler.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHandler.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHook.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHook.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/ToolExecutionLimits.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolExecutionLimits.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/ToolProgressBus.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolProgressBus.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionCaptureManager.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionCaptureManager.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionHolder.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionHolder.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureActivity.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureActivity.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureService.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureService.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidShellExecutor.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/AndroidShellExecutor.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/OperitTerminalManager.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/OperitTerminalManager.kt` +- 迁移:`app/src/main/java/com/ai/assistance/operit/core/tools/system/Terminal.kt` + - 目标:`app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/Terminal.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolsTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolsTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupportTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupportTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafetyTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafetyTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicyTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicyTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupportTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupportTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletionTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletionTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactoryTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactoryTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiDeclarationTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiDeclarationTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOriginCodecTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOriginCodecTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestSelectionTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgManifestSelectionTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResultTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResultTest.kt` +- 迁移:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManagerTest.kt` + - 目标:`app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManagerTest.kt` + +## 验收 + +- [x] 清单中所有目标路径及包名一致 +- [x] 旧引用、同包隐式依赖和显式组件调用已同步 +- [x] 移动文件的操作体保持,静态语法与差异检查完成 +- [x] 仓库验证入口与交付方式已记录,实际运行结果见 PR + +[DONE] 清单中的目录迁移及静态核对完成,编译与 JVM 单测结果由仓库工作流确认。 diff --git a/docs/TODO/chore/tools-permissions-layout/files.json b/docs/TODO/chore/tools-permissions-layout/files.json new file mode 100644 index 0000000000..1a8dcc4801 --- /dev/null +++ b/docs/TODO/chore/tools-permissions-layout/files.json @@ -0,0 +1,1060 @@ +{ + "schemaVersion": 1, + "baseCommit": "718707fd19ab7c27e38c8807055c80809d25e6dc", + "scope": "工具权限收口后的目录迁移", + "files": [ + { + "source": "app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/ffmpeg/ffmpeg_probe.js", + "target": "app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/media/ffmpeg/ffmpeg_probe.js", + "sourcePackage": null, + "targetPackage": null, + "group": "android-js/builtin/media/ffmpeg", + "operation": "move", + "sourceSha256": "1fa1a507372b221f4f2d81617edc482afed954e2130a7f27479b42a0c86fc93c" + }, + { + "source": "app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/main.js", + "target": "app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/main.js", + "sourcePackage": null, + "targetPackage": null, + "group": "android-js/builtin/web/browser", + "operation": "move", + "sourceSha256": "29befc725e9bb7872a7b5e68ae55e5ddfe0d731b07d870944687f0ca3b9f32a9" + }, + { + "source": "app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/probe.js", + "target": "app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/probe.js", + "sourcePackage": null, + "targetPackage": null, + "group": "android-js/builtin/web/browser", + "operation": "move", + "sourceSha256": "4e9a9170e4f9714b6bac55b72f45e15c429312d254e53f4526b9dfbd6c64313d" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ToolGetter.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin", + "group": "builtin", + "operation": "move", + "sourceSha256": "a68f991a7d7dcab3efc983fb5999847e236426bcb7e37f79eb981c5fafef691a" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolDefinitions.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolDefinitions.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.a2ui", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.a2ui", + "group": "builtin/a2ui", + "operation": "move", + "sourceSha256": "5336bc3f49a03912712f14588ac630a719cedc626c7f9e6c6d6b2143e7006c96" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolRuntime.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolRuntime.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.a2ui", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.a2ui", + "group": "builtin/a2ui", + "operation": "move", + "sourceSha256": "ff01825f817b7c0fbe1fe7c3ff93b0ce8c1f842c80871f667d59b8699db743da" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.a2ui", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.a2ui", + "group": "builtin/a2ui", + "operation": "move", + "sourceSha256": "25e4ccb6b94570ffd06e32649399e3b10bb5be425e671075965e01e2182dc513" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardCalculator.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/calculator/StandardCalculator.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.calculator", + "group": "builtin/calculator", + "operation": "move", + "sourceSha256": "79bcdcb659c1391b575854e47d6cec56b9f1c0bb3728223355055660ae93f894" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardChatManagerTool.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/chat/StandardChatManagerTool.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.chat", + "group": "builtin/chat", + "operation": "move", + "sourceSha256": "ec054348c9996be0c507c134bc5078d20fcfccf0ba9925b4f54a3e4c0e11456e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardDeviceInfoToolExecutor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/device/StandardDeviceInfoToolExecutor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.device", + "group": "builtin/device", + "operation": "move", + "sourceSha256": "4ec9a994a0dda069b7ef05428241f87e5cc1cdec0845354286dbaa7f3c16fb8a" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminFileSystemTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/AdminFileSystemTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.admin", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.filesystem", + "group": "builtin/filesystem", + "operation": "move", + "sourceSha256": "9e92411bd6fd6d094889792eacd6f1e25ce3839d6f80e81dbafc29cc70e05b06" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/LinuxFileSystemTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/LinuxFileSystemTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.filesystem", + "group": "builtin/filesystem", + "operation": "move", + "sourceSha256": "90d9f5b4cfd6c4e6a211d560b9734484003bd2dfb9ea27bc4a115959108fabc6" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/PathValidator.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/PathValidator.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.filesystem", + "group": "builtin/filesystem", + "operation": "move", + "sourceSha256": "666052a44cc6b747a6e309f2eabd34a7985cad9d0c2beeb0fcc79a1202f66868" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/SafFileSystemTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/SafFileSystemTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.filesystem", + "group": "builtin/filesystem", + "operation": "move", + "sourceSha256": "2a5d727822768e073d7ec59f4a9defb66d1dfe5a54b91ad0d1f6c1c10ef245b9" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFileSystemTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/StandardFileSystemTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.filesystem", + "group": "builtin/filesystem", + "operation": "move", + "sourceSha256": "c91d4761af374e11c124e2d84dbb8ad115027406d76244e251bdb202ed5759fa" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/BluetoothSessionManager.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/BluetoothSessionManager.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.media", + "group": "builtin/media", + "operation": "move", + "sourceSha256": "a90c17d7f7393097ec8bb087a19f0595651109b342d5c0d7c04b6408f66edb53" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFFmpegTool.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardFFmpegTool.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.media", + "group": "builtin/media", + "operation": "move", + "sourceSha256": "2f8cf167a5c2e530ce6f8fa65dda91715c0a0bad6fe2f507e32e4af32c538018" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardMusicPlaybackTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardMusicPlaybackTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.media", + "group": "builtin/media", + "operation": "move", + "sourceSha256": "8ee46026a26b5cf9b3d46a9930f341ece9d8aa35bf4b5a9d64968c7a4cccbeeb" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/MemoryQueryToolExecutor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/memory/MemoryQueryToolExecutor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.memory", + "group": "builtin/memory", + "operation": "move", + "sourceSha256": "bd3ec607ee528c0874761658d25f6721da6df2614c3261f7a8227b2c7770b11e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSoftwareSettingsModifyTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/StandardSoftwareSettingsModifyTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.settings", + "group": "builtin/settings", + "operation": "move", + "sourceSha256": "7be8c2bf6842c4204fe215f82bcf0bb54f85b0d361ccba6aa4a33bbdcb060b2a" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupport.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupport.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.settings", + "group": "builtin/settings", + "operation": "move", + "sourceSha256": "5ca4b53b37c7ec51b1c99afe76beeeaf0ccbb077daa2c17fa9ec68ca8a5ba6ef" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafety.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafety.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.shell", + "group": "builtin/shell", + "operation": "move", + "sourceSha256": "ed8dbbe94e9e7392f92e3925c8567e9f2fd439a37205b4d48c27d95dfd815128" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardShellToolExecutor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/shell/StandardShellToolExecutor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.shell", + "group": "builtin/shell", + "operation": "move", + "sourceSha256": "bbc33d60d4ff81ee4545510431ebad946b1adc6e2e10adbcc4594a97e6b844af" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminSystemOperationTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/AdminSystemOperationTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.admin", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.system", + "group": "builtin/system", + "operation": "move", + "sourceSha256": "2905543b02cfd2e69381d84f10e886fcc1c44f04a89b3f00c2eed70648dfa423" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardIntentToolExecutor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardIntentToolExecutor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.system", + "group": "builtin/system", + "operation": "move", + "sourceSha256": "f734bf44f9d63c5c605fb0eb45252e1fa8a258340b918ce59d04a38817eab229" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSendBroadcastToolExecutor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSendBroadcastToolExecutor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.system", + "group": "builtin/system", + "operation": "move", + "sourceSha256": "586b2f4b275f8c80014b0b2af462ad294e512760551e34c08b30ea3fdfc2c317" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSystemOperationTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSystemOperationTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.system", + "group": "builtin/system", + "operation": "move", + "sourceSha256": "3b5445ba9b2c384a9d37c0ae36bad92f7a5afa9e52014eb7e54190d5ea722b0e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardTerminalCommandExecutor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/terminal/StandardTerminalCommandExecutor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.terminal", + "group": "builtin/terminal", + "operation": "move", + "sourceSha256": "1f24869e00d0a1f2f72ee71132499b313bb7bc53be57dfd62fc3e18be8c89ce4" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/AdminUITools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/AdminUITools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.admin", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.ui", + "group": "builtin/ui", + "operation": "move", + "sourceSha256": "00484a4936ebb5d26c269480a7d439773b7a77c2ba8f81a5208827f960ab9e87" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/RootUITools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/RootUITools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.root", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.ui", + "group": "builtin/ui", + "operation": "move", + "sourceSha256": "01df2c3548d66af6a772013af9614e9bbada3184f7faa446bcae05a944c59e22" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/StandardUITools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.ui", + "group": "builtin/ui", + "operation": "move", + "sourceSha256": "ce013a4d5c295ab04d71c5f0cc442b8ce97391384772b680c836ca9cf7741532" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/CookiePrivacyManager.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/CookiePrivacyManager.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web", + "group": "builtin/web", + "operation": "move", + "sourceSha256": "96f3b8544756e0aa14e8f13e819916fd5972dcd0e2da4e1bb4b0bfe418c47515" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardBrowserSessionTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardBrowserSessionTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web", + "group": "builtin/web", + "operation": "move", + "sourceSha256": "c62dc5e41efe3e9e4b1300a856c04cfff9e99dda826068e45d3185da1ef22992" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardHttpTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardHttpTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web", + "group": "builtin/web", + "operation": "move", + "sourceSha256": "49403df45a4ed708dd93bef1478f445fd6aa0d034f7cca10ddee32a19aa0ea7e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWebVisitTool.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardWebVisitTool.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web", + "group": "builtin/web", + "operation": "move", + "sourceSha256": "09a85bab17fd04a915f7c037998589c4a130936c52f9b735ea5f747a742fe3b3" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserDownloadSupport.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserDownloadSupport.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "5967edebda6dca56448928740f9a1aa0543927e71aac63fa01e22e08f5bc60a6" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicy.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicy.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "adfc6cbbe604381db73cdab6ea71d6c655fbdeee69cff7ad7170b0de768a98ca" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserPageExecutionSupport.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserPageExecutionSupport.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "f0e6f0797ee3ea32b99425ecec7bd099033d072a22117d0f811dc6910868c2c2" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserToolSupport.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserToolSupport.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "030977e04709519a935acdb47861545942088f9d8408bd91cd249d407d652294" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserWebViewSupport.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserWebViewSupport.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "9205b2ab66bd49ac83f55b57812b84c651a73e4750e2d83bb5da00370d59eabc" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHost.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHost.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "7ff7e74727f41c7fcc642deaee7a38e97b44967948dfc7c085431b6a38a7f77e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionBrowserHostState.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionBrowserHostState.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "1e88fa02a47d45a7a1493c7a012de89687be28d3b23498fa71ac29a5ee240d6e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionHistoryStore.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionHistoryStore.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "75669d76a0c1383a9302ee6e92b5e4c5b23661da4d8f6d9fb3c87da739509c80" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionPermissionRequestActivity.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionPermissionRequestActivity.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "410e33dc6cc2e35920694af3001643dae05ca030a81defcdd26a0f014f6a4a13" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/WebSessionWebViewHost.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/WebSessionWebViewHost.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "e712246b317bbf58e82daf13ae259b668e7d51c3d48b6d10924488d94af2da6a" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptCapabilityRegistry.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptCapabilityRegistry.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "b019a3852ad7518c7d913f88f52a0bc9eacfebbbc44de78c33911094f4d2f86f" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMatcher.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMatcher.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "4dc8728f983f447f9387c877d4d4719781186f810ad9dc1ce62cb31e73d3b3c6" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptMetadataParser.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptMetadataParser.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "61b10ffe14c148b71438f3e6f1e76fb3880255a83e52d8887d9169468fbf69c2" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/UserscriptModels.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/UserscriptModels.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "e7a21b310f70dbc28bd9524067959ffe0a8fbf0c1abe2545954b031b3e668b3a" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportCoordinator.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportCoordinator.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.install", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.install", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "7a6a1b511c4a3be25410b1530580bdca421ab929f8e072cd60abe15a9c991f38" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/install/UserscriptImportPickerActivity.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/install/UserscriptImportPickerActivity.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.install", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.install", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "61ffdbbd288462d933a93ef9328e63fd543a4a98961249d628f880ff2acefd4c" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptBootstrapScript.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptBootstrapScript.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "6758b1a711108961479560eeafe43bbe8994c98aa531a93d4678601cda0249c5" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptCookieService.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptCookieService.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "d6a464a71d9ea7b9defd9ebae36ea7aa843f320307c49dad7b9f1d8ac5bc46bd" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptStorageNotifier.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptStorageNotifier.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "997da1faf8ef4f8c87a93a94bcb9f1e72a69236e41a415be865ea71ba7d621e0" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptTabStateStore.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptTabStateStore.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "d5b0ab291d79aca089d5be30697d12bcf58581ba0dc72f3eb3923a0cae042e14" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/UserscriptWebRequestEngine.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/UserscriptWebRequestEngine.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "b07612abbc090f08ab5c524cd958cc4a5bd2d6ff9802cabcab355879e6d7c963" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/runtime/WebSessionUserscriptManager.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/runtime/WebSessionUserscriptManager.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.runtime", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.runtime", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "9e786ffb6f20163cbf85514c38c334ebf3d9dc736fd20a2fd7e2a5618bdb0aeb" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptEntities.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptEntities.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "f1df9f8a0b4733ce6cfcaab0e37a464c1ba44edddc355d097fe1950328ef8594" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptJsonStore.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptJsonStore.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "e9d2907f1c7386357e4b4a7056202428ff33c7dca74e7a6cfb8b744ef16f825e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/storage/UserscriptRepository.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/storage/UserscriptRepository.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.storage", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.storage", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "1e61186ebc622fa8f92d76c52b7ebcf520642d0841e920ab708b4862f5896cda" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/websession/userscript/ui/WebSessionUserscriptUiStateStore.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/session/userscript/ui/WebSessionUserscriptUiStateStore.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.userscript.ui", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.userscript.ui", + "group": "builtin/web/session", + "operation": "move", + "sourceSha256": "47bc1e6d52bb122a246c6911b807c8aaac73d3d25ddcf314f82ab3e8c3b4513e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWorkflowTools.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/builtin/workflow/StandardWorkflowTools.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.workflow", + "group": "builtin/workflow", + "operation": "move", + "sourceSha256": "373e12784000553bc6675f1fa97e974391cf1750abd25e7111a254741da8080c" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageDebugRefreshReceiver.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool", + "group": "packTool", + "operation": "keep", + "sourceSha256": "52ecb7abe0804ab14e0d52cae26e8d86050b36c3aee480c637ff2216d96d1298" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslDebugDumpReceiver.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslDebugDumpReceiver.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool", + "group": "packTool", + "operation": "keep", + "sourceSha256": "d8697d409ae36d9717af512aa626d0cc37222ccb17ccbec2585a60beec505272" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool", + "group": "packTool", + "operation": "keep", + "sourceSha256": "64b7a06d29f761e0ddc30d3af7e44ca03c8aa9dca2c901b4f2c78a8494d2d52a" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupport.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupport.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.install", + "group": "packTool/install", + "operation": "move", + "sourceSha256": "90b1c892d4fbb8d0e46e5ade9b96c3b351ea59edf9a425422ac01e254729c374" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletion.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletion.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.install", + "group": "packTool/install", + "operation": "move", + "sourceSha256": "0d814bdc07218ce2bd3dcfc0e5846efa1a65fed52283d51958c79e2e154e1b3e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactory.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactory.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.install", + "group": "packTool/install", + "operation": "move", + "sourceSha256": "1ad69beee67364b4e3e1609f9ec79c21089451a69f4f1cd940e56d2819dcb549" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoadOrder.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoadOrder.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.loader", + "group": "packTool/loader", + "operation": "move", + "sourceSha256": "ec146016ab2252e215aeb5194560b0356401471d000eef2b85509e9a15a0ead5" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgLoader.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/loader/ToolPkgLoader.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.loader", + "group": "packTool/loader", + "operation": "move", + "sourceSha256": "772918135e21bdc11214adb25763d0cd0bec98ca822394749e34e5909f72568d" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/BuiltInPackageDefaults.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/BuiltInPackageDefaults.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "packTool/metadata", + "operation": "move", + "sourceSha256": "bf72c6bb35ead143ce98e3a547a68c3b88c0d9034e362fb252302b229c7d9164" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/PluginActivityStore.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/PluginActivityStore.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "packTool/metadata", + "operation": "keep", + "sourceSha256": "abaabd71f03e52746368ef550c4bf7ba88a73de7d2def22bed8b22cb90b0a74e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiVersion.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiVersion.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "packTool/metadata", + "operation": "move", + "sourceSha256": "bb032bc49a9ec11d86d044af71d344bba1c86c98cad1eadade211e7de0a6bab6" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgCommonPluginConstants.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgCommonPluginConstants.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "packTool/metadata", + "operation": "move", + "sourceSha256": "43e54dd3a4bbd173aa7910b5a3f7fe0824495b00c7daeabe92888590470eb01b" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestRequirement.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgManifestRequirement.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "packTool/metadata", + "operation": "move", + "sourceSha256": "207a40a4f36b648bdf8b512f744bec00330184e4ec56c183a74d0509558863e2" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOrigin.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOrigin.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "packTool/metadata", + "operation": "move", + "sourceSha256": "2f53cd45a6cb65683186f9856ac568361f57ece70e2393b68d4a8f29737609b3" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgTemplateModels.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgTemplateModels.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "packTool/metadata", + "operation": "move", + "sourceSha256": "8a0554909f06c342677fd77823a693620055e76338612b1d34daf8e0df3351cb" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgArtifactMinifier.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool.minify", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.minify", + "group": "packTool/minify", + "operation": "keep", + "sourceSha256": "717867cd2823353f83cbd57e9a612c82008159598c586f61396206b9ea84f50e" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgJsAstMinifier.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/minify/ToolPkgJsAstMinifier.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool.minify", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.minify", + "group": "packTool/minify", + "operation": "keep", + "sourceSha256": "8ae17659255fb28f636398e92b424decb75336bfd61de2734866fae539228a9d" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMainRegistrationScriptParser.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.parser", + "group": "packTool/parser", + "operation": "move", + "sourceSha256": "d9481fe46c859ea3dd5ddacb705cd02af2ac1604d0220b53787d0ad11597c415" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgParser.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.parser", + "group": "packTool/parser", + "operation": "move", + "sourceSha256": "d3fb8f689da940852e923c357408fa459a688dd232ff371e93c957698cd4f9b0" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResult.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResult.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "packTool/runtime", + "operation": "move", + "sourceSha256": "43043dc603fcd7c2d7feadcdd76d118ecbca353b31ce5374254f6785d2fcf62c" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManager.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManager.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "packTool/runtime", + "operation": "move", + "sourceSha256": "281b64ae3fafb4da46d473e241408f60d49a131775408f1f6abf2a4bcd905ef4" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/PackageManagerToolPkgFacade.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageManagerToolPkgFacade.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "packTool/runtime", + "operation": "move", + "sourceSha256": "e129b9e9735ccb23f8ae6843f15878b7d064bf7d0b5adb414deb795ebe685103" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgHookModels.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgHookModels.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "packTool/runtime", + "operation": "move", + "sourceSha256": "1a426bd351bea56d13718ca437321df689fff60dbcc5e2b286bf2b3071672f50" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManager.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManager.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "packTool/runtime", + "operation": "move", + "sourceSha256": "51ab8e4f41ad47fe36d246143591b34d9707b60746bf6148212ac02d5e0a9ff6" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgRuntimeMonitor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgRuntimeMonitor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "packTool/runtime", + "operation": "move", + "sourceSha256": "bc9ab08144cb8fc5ccf9682425ecbbea81eab7918ea6529409b548f57414d6b3" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgComposeDslParser.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/packTool/uidsl/ToolPkgComposeDslParser.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.uidsl", + "group": "packTool/uidsl", + "operation": "move", + "sourceSha256": "8d33ab0f27409c6df3334331a66920118f61a8b24e87ebe3cbbc501ccd0b3fac" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidPermissionLevel.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/permissions/AndroidPermissionLevel.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.permissions", + "group": "permissions", + "operation": "move", + "sourceSha256": "d22443b90ca90002883556824c1144036f080e0d0e67f1c54d7cc78d3d40a642" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/AccessibilityProviderInstaller.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/AccessibilityProviderInstaller.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.permissions.authorization", + "group": "permissions/authorization", + "operation": "move", + "sourceSha256": "b912919a645c74561f560adfffd4130bca10e7c1a557202a8157f547586f63bb" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/RootAuthorizer.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/RootAuthorizer.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.permissions.authorization", + "group": "permissions/authorization", + "operation": "move", + "sourceSha256": "899a11eb57ea093f148bfe42b9eb5a4e1d37a62c8bee6f0a30327b636b0b0cd0" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuAuthorizer.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuAuthorizer.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.permissions.authorization", + "group": "permissions/authorization", + "operation": "move", + "sourceSha256": "47be3245a57b6d22be40fe97b146fcada81791a753c07317ac05dd230351652b" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/ShizukuInstaller.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/permissions/authorization/ShizukuInstaller.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.permissions.authorization", + "group": "permissions/authorization", + "operation": "move", + "sourceSha256": "85942359b635a9704e50d074b7338b05f080e290e49c8404976f9297971af40c" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHandler.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHandler.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools", + "targetPackage": "com.ai.assistance.operit.core.tools.runtime", + "group": "runtime", + "operation": "move", + "sourceSha256": "169a8a24283b29a1a8e4c0b1418442ba416ca992d37494cb185a00e96c31577b" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/AIToolHook.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/runtime/AIToolHook.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools", + "targetPackage": "com.ai.assistance.operit.core.tools.runtime", + "group": "runtime", + "operation": "move", + "sourceSha256": "3e4913e96095fe38051786992842d48cc9cd0823540ad9845f07793c1905f412" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/ToolExecutionLimits.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolExecutionLimits.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools", + "targetPackage": "com.ai.assistance.operit.core.tools.runtime", + "group": "runtime", + "operation": "move", + "sourceSha256": "14dcd24cb56dbec6c76327b1842739966b55e24bf39f25b9ccff11abb9c97d4d" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/ToolProgressBus.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolProgressBus.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools", + "targetPackage": "com.ai.assistance.operit.core.tools.runtime", + "group": "runtime", + "operation": "move", + "sourceSha256": "8cef67b48a465c515c2f2ef7d97b253c900eac3e07fef3aade2d8532037217d0" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools", + "targetPackage": "com.ai.assistance.operit.core.tools.runtime", + "group": "runtime", + "operation": "move", + "sourceSha256": "9f6fbd82f24b3c865a9d270640e233063bad87b434381864585bd3b08715cba0" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionCaptureManager.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionCaptureManager.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.system.capture", + "group": "system/capture", + "operation": "move", + "sourceSha256": "4716293bd0fb4457e068cbc88aefad77630d431a376dc172e0e6fb53284f7c2f" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/MediaProjectionHolder.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/MediaProjectionHolder.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.system.capture", + "group": "system/capture", + "operation": "move", + "sourceSha256": "25a5452b759b206dbbf09810e96940583b121e01e08867fa798fc01b1bebd9b6" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureActivity.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureActivity.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.system.capture", + "group": "system/capture", + "operation": "move", + "sourceSha256": "b81234d7f27ffe5fdd17ac9848251d37eb04f98c3650442bc60816fdca037769" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/ScreenCaptureService.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/system/capture/ScreenCaptureService.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.system.capture", + "group": "system/capture", + "operation": "move", + "sourceSha256": "39de34c1dd487169c68d511a228cbd986a134b3a4b4c6ad2b6e8d9c1665e74d7" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/AndroidShellExecutor.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/system/shell/AndroidShellExecutor.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.system.shell", + "group": "system/shell", + "operation": "move", + "sourceSha256": "cdca5059498e1b37e079d72a650d22b93424411626654e144edde03c2837f246" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/OperitTerminalManager.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/OperitTerminalManager.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.system.terminal", + "group": "system/terminal", + "operation": "move", + "sourceSha256": "a3c477aaa53a61773a2cd1049cda6179cbfc13b61f4cb34330bd1296a49747f2" + }, + { + "source": "app/src/main/java/com/ai/assistance/operit/core/tools/system/Terminal.kt", + "target": "app/src/main/java/com/ai/assistance/operit/core/tools/system/terminal/Terminal.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.system", + "targetPackage": "com.ai.assistance.operit.core.tools.system.terminal", + "group": "system/terminal", + "operation": "move", + "sourceSha256": "45a22a4932c2af47b5db3311f5e43966b1e76cfddb2aa543d52faf7e87228a10" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/a2ui/A2uiToolsTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/builtin/a2ui/A2uiToolsTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.a2ui", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.a2ui", + "group": "tests/builtin/a2ui", + "operation": "move", + "sourceSha256": "a83003debdc5de0ea0d036c749dc4ce6411484006de3965508dfa37c5bd355d0" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ToolPermissionModeSupportTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/builtin/settings/ToolPermissionModeSupportTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.settings", + "group": "tests/builtin/settings", + "operation": "move", + "sourceSha256": "dcfda6fc6fe18b27b6d6b8d41cdfbbec74c3f1572318c8a74bded90de3ceffe3" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/standard/ShellCommandSafetyTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/builtin/shell/ShellCommandSafetyTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.standard", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.shell", + "group": "tests/builtin/shell", + "operation": "move", + "sourceSha256": "3b2017bb1684fd2944d9b27dcaadfccb58d89147610c43d459bbea08af92049f" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/defaultTool/websession/browser/BrowserNavigationPolicyTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/builtin/web/session/browser/BrowserNavigationPolicyTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.defaultTool.websession.browser", + "targetPackage": "com.ai.assistance.operit.core.tools.builtin.web.session.browser", + "group": "tests/builtin/web/session/browser", + "operation": "move", + "sourceSha256": "ea47f6a2bd3017de431c3a836cc7bbd3909e5c55feb250973668e37cf0a6a377" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageFileImportSupportTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageFileImportSupportTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.install", + "group": "tests/packTool/install", + "operation": "move", + "sourceSha256": "e3d2784fd4a2cf4a4031433d5e192ca63e962eab1727357515ad6625eecf080c" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageSourceDeletionTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageSourceDeletionTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.install", + "group": "tests/packTool/install", + "operation": "move", + "sourceSha256": "d80e4119332e0c939867331e7e7f33ba30e1cfa58bc432d76c53a2711cfb2bd3" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageTemplateFactoryTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/install/PackageTemplateFactoryTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.install", + "group": "tests/packTool/install", + "operation": "move", + "sourceSha256": "ece1af8d1ca93308a36aac08251dea5e95db3c201cf44403a579457d939e5ab7" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiDeclarationTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiDeclarationTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "tests/packTool/metadata", + "operation": "move", + "sourceSha256": "de21af2f58f85d67659fe7e2659085a40b17afc144ef528c75b9b9a1dc638334" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMarketOriginCodecTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgMarketOriginCodecTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.metadata", + "group": "tests/packTool/metadata", + "operation": "move", + "sourceSha256": "ac68a386de7dab0b8dfb2758230acc6b6e3ff3f0e9461b9f0e5594e9bc9f59ec" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManifestSelectionTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgManifestSelectionTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.parser", + "group": "tests/packTool/parser", + "operation": "move", + "sourceSha256": "68442d9fa53207bec8e609a47a6e30a8331d620c05fd3cc17343d5c7268e356d" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/PackageActivationResultTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/PackageActivationResultTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "tests/packTool/runtime", + "operation": "move", + "sourceSha256": "e951755e4839bbaadbf1eb164c8936e11684ba15d63e5c23fc9893d1864a2a03" + }, + { + "source": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgManagerTest.kt", + "target": "app/src/test/java/com/ai/assistance/operit/core/tools/packTool/runtime/ToolPkgManagerTest.kt", + "sourcePackage": "com.ai.assistance.operit.core.tools.packTool", + "targetPackage": "com.ai.assistance.operit.core.tools.packTool.runtime", + "group": "tests/packTool/runtime", + "operation": "move", + "sourceSha256": "81ffb753a0aa956bc0082690a1102c2f6b72b1bd0b9632b856a86de37638f1ec" + } + ] +} diff --git a/docs/TODO/chore/tools-permissions-layout/index.md b/docs/TODO/chore/tools-permissions-layout/index.md index 2f225ef9a8..1f448399d7 100644 --- a/docs/TODO/chore/tools-permissions-layout/index.md +++ b/docs/TODO/chore/tools-permissions-layout/index.md @@ -1,6 +1,6 @@ --- fork: https://github.com/3316891527/Operit -status: in-progress +status: implemented --- # 工具权限收口与目录整理 @@ -13,17 +13,20 @@ status: in-progress ## 执行顺序 1. [权限实现收口](01-permissions.md):删除旧工具等级和无行为的中间层,管理员按实际授权使用无障碍、Shizuku,Root 复用管理员能力。 -2. 目录迁移:读取权限收口后的工具源码,先记录逐文件当前路径、目标路径及目标包名,再按清单迁移并同步引用。 +2. [目录迁移](02-layout.md):读取权限收口后的工具源码,先记录逐文件当前路径、目标路径及目标包名,再按清单迁移并同步引用。 迁移清单只记录本次实际迁移的文件。目录整理以保持工具调用接口及现有行为为目标。 ## 验证与交付 -记录静态引用、路径、配置及差异检查;本地不执行编译、构建或测试。推送工作分支后先派发仓库工作流,再创建以 `dev` 为目标的 PR。工作流受理与实际运行结果分别记录。 +记录静态引用、路径、配置及差异检查,编译与 JVM 单测通过仓库工作流验证。推送工作分支后先派发仓库工作流,再创建以 `dev` 为目标的 PR。工作流受理与实际运行结果分别记录。 + +详见[验证记录](verification.md)。 ## 进度 - [x] 权限实现统一为三档,旧配置只在迁移入口识别 -- [ ] 形成逐文件目标路径清单 -- [ ] 完成清单中全部迁移及调用方同步 -- [ ] 完成静态核对、提交、工作流派发与 PR +- [x] 形成逐文件目标路径清单 +- [x] 完成清单中全部迁移及调用方同步 +- [x] 完成静态核对并准备工作分支交付 +- [ ] 远端构建与 JVM 单测结果确认 diff --git a/docs/TODO/chore/tools-permissions-layout/verification.md b/docs/TODO/chore/tools-permissions-layout/verification.md new file mode 100644 index 0000000000..fe438ca2da --- /dev/null +++ b/docs/TODO/chore/tools-permissions-layout/verification.md @@ -0,0 +1,27 @@ +# 验证记录 + +本次交付分为权限实现收口和工具目录迁移两个提交。目录迁移以 [files.json](files.json) 为依据,当前共 117 个文件,其中迁移 111 个,保留 6 个。 + +## 静态核对 + +- 权限收口逐项比较 61 个原操作体及辅助方法,以及 17 个管理员文件操作路由,保留原操作实现和只读标记 +- 目录迁移比较 264 份受影响 Kotlin 文件的声明内容,除包名、导入和清单对应的显式路径引用外未发现其他变化 +- 核对清单全部目标文件、目标包名、迁移符号导入及工具导入名称冲突 +- 静态语法扫描未发现新增问题;最终类型检查与编译结果以仓库工作流为准 +- 核对变更 XML、Python 语法、Markdown 本地链接与 Git 差异空白 +- 安装、刷新与 UI DSL 调试广播保持原公开组件名,现有 ADB 和编辑器调用仍使用原入口 + +## 仓库验证 + +- [Build](../../../../.github/workflows/build.yml):工作分支执行 `assembleDebug` +- [Android Tests](../../../../.github/workflows/android-tests.yml):工作分支执行 Android JVM 单测 +- PR 的 Candidate checks 根据实际差异选择技术检查 + +本地未执行编译、构建或测试。工作流派发受理与最终运行结果分别记录在 PR 中,派发成功不代表构建或测试已经通过。 + +## 对应回归范围 + +- `PermissionCapabilitiesTest` 覆盖三档用户模式与 16 种授权状态组合,共 48 组能力选择,以及显式显示器和 Shell 身份选择 +- `PermissionOperationRouterTest` 与 `PermissionCapabilitySessionTest` 覆盖原有操作路由及会话能力缓存 +- `AndroidPermissionModeMigrationTest` 覆盖旧偏好转换为管理员,以及 Root 和其他偏好的保留 +- 插件包、内置工具和 JS 测试随目录迁移同步包名、引用和资源路径,具体运行结果以仓库工作流为准 \ No newline at end of file diff --git a/docs/doc-src/architecture/DEFAULT_TOOLS_ARCH.md b/docs/doc-src/architecture/DEFAULT_TOOLS_ARCH.md index 1f1c896205..89f15c781b 100644 --- a/docs/doc-src/architecture/DEFAULT_TOOLS_ARCH.md +++ b/docs/doc-src/architecture/DEFAULT_TOOLS_ARCH.md @@ -40,7 +40,7 @@ ### 2.2 必改:工具注册(toolName -> executor) -- **文件**:`app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` +- **文件**:`app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` - **你要做的事**: - 确认工具名不变时,一般无需改注册,但要确认调用到的 executor 没变 - 若工具名/分组变更,需要同步调整注册项 @@ -52,15 +52,19 @@ ### 2.3 必改:Kotlin 执行实现(参数读取与校验) - **常见目录**: - - `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/*` - - `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/debugger/*` - - `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/admin/*` - - `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/root/*` - - `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/*` - - `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/ToolGetter.kt`(按权限级别选择具体实现) + - `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/` + - `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/` + - `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/` + - `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/` + - `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ToolGetter.kt`(按三档模式取得工具) +- **权限模型**: + - 用户模式只有 `STANDARD`、`ADMIN`、`ROOT` + - 管理员工具直接包含无障碍与 Shell 操作,按实际授权选择执行能力 + - Root 复用管理员公共能力,并保留专有 UI 实现 + - 无障碍、Shizuku 是执行后端,历史无障碍、调试模式仅由偏好迁移入口转换为管理员 - **你要做的事**: - 将旧参数的读取逻辑替换为新参数(`tool.parameters.find { it.name == "..." }`) - - 如果某个工具在 `debugger/root/admin/accessibility` 目录下有 override / 替代实现:这些实现里同样要同步更新参数读取与校验 + - 同一功能目录中的标准、管理员、Root 实现有 override 时,同步更新参数读取与校验 - 新增参数合法性校验:必填、互斥、默认值、兼容性策略 - 更新错误消息(要能引导正确用法) diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/android.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/android.md index af9546679f..ded8c98465 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/android.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/android.md @@ -152,5 +152,5 @@ console.log(result.action, result.result); - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsLibraries.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsInitRuntimeScriptBuilder.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardIntentToolExecutor.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardIntentToolExecutor.kt` - `docs/doc-src/toolpkg_developer_documentation/04_modules/system.md` diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/ffmpeg.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/ffmpeg.md index 1d544dd3c7..c2e5e976aa 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/ffmpeg.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/ffmpeg.md @@ -255,5 +255,5 @@ interface RuntimeStreamInfo { - `examples/types/tool-types.d.ts` - `app/src/main/assets/packages/ffmpeg.js` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFFmpegTool.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardFFmpegTool.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/ToolResultDataClasses.kt` diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/files.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/files.md index 037aa7e81f..9a7ecd8203 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/files.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/files.md @@ -457,7 +457,7 @@ await Tools.Files.download({ - `examples/types/files.d.ts` - `examples/types/results.d.ts` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardFileSystemTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/LinuxFileSystemTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/SafFileSystemTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/StandardFileSystemTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/LinuxFileSystemTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/filesystem/SafFileSystemTools.kt` diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/memory.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/memory.md index 494709a0a6..70c2051876 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/memory.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/memory.md @@ -395,8 +395,8 @@ console.log(link.linkType, link.weight); - `examples/types/memory.d.ts` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/MemoryQueryToolExecutor.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/memory/MemoryQueryToolExecutor.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/ToolResultDataClasses.kt` - [结果类型参考](./results.md) - [全局运行时 API](../03_runtime/global_api.md) diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/network.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/network.md index 2a6da43f17..022897582f 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/network.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/network.md @@ -500,7 +500,7 @@ await Tools.Net.browserClick({ - `examples/types/network.d.ts` - `examples/types/results.d.ts` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardHttpTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardWebVisitTool.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardBrowserSessionTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardHttpTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardWebVisitTool.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardBrowserSessionTools.kt` diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/okhttp.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/okhttp.md index 9a6e254be6..47cee8b1b0 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/okhttp.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/okhttp.md @@ -254,8 +254,8 @@ console.log(response.text()); - `app/src/main/assets/js/OkHttp3.js` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsAssetLoader.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsLibraries.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardHttpTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/web/StandardHttpTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/ToolResultDataClasses.kt` - [网络模块参考](./network.md) - [结果类型参考](./results.md) diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/system.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/system.md index f540c61e50..077bc41c15 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/system.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/system.md @@ -596,11 +596,11 @@ await Tools.System.music.play({ - `examples/types/system.d.ts` - `examples/types/results.d.ts` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSystemOperationTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardTerminalCommandExecutor.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/BluetoothSessionManager.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardMusicPlaybackTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardIntentToolExecutor.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardSendBroadcastToolExecutor.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSystemOperationTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/terminal/StandardTerminalCommandExecutor.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/BluetoothSessionManager.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/media/StandardMusicPlaybackTools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardIntentToolExecutor.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/system/StandardSendBroadcastToolExecutor.kt` - [公共结果类型](results.md) diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/tasker.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/tasker.md index 98ed4abba2..7d25af7e20 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/tasker.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/tasker.md @@ -19,7 +19,7 @@ triggerEvent: (params) => toolCall('trigger_tasker_event', params || {}) 相关实现位于: - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` - `app/src/main/java/com/ai/assistance/operit/integrations/tasker/AIAgentTasker.kt` ## `Tasker.TriggerTaskerEventParams` @@ -155,6 +155,6 @@ await Tools.Tasker.triggerEvent({ - `examples/types/tasker.d.ts` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` - `app/src/main/java/com/ai/assistance/operit/integrations/tasker/AIAgentTasker.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsInitRuntimeScriptBuilder.kt` diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/tool-types.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/tool-types.md index d67d720b3b..30b046b3b1 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/tool-types.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/tool-types.md @@ -312,7 +312,7 @@ disable_workflow - `examples/types/core.d.ts` - `examples/types/results.d.ts` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` - [公共结果类型](results.md) - [Files 参考](files.md) - [Network 参考](network.md) diff --git a/docs/doc-src/toolpkg_developer_documentation/04_modules/ui.md b/docs/doc-src/toolpkg_developer_documentation/04_modules/ui.md index 8f44e3243d..7cf31a9a16 100644 --- a/docs/doc-src/toolpkg_developer_documentation/04_modules/ui.md +++ b/docs/doc-src/toolpkg_developer_documentation/04_modules/ui.md @@ -262,7 +262,8 @@ await Tools.UI.clickElement({ - `examples/types/results.d.ts` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsTools.kt` - `app/src/main/assets/js/UINode.js` -- `app/src/main/java/com/ai/assistance/operit/core/tools/ToolRegistration.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/standard/StandardUITools.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/defaultTool/accessbility/AccessibilityUITools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/runtime/ToolRegistration.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/StandardUITools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/AdminUITools.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/builtin/ui/RootUITools.kt` - `docs/doc-src/toolpkg_developer_documentation/04_modules/results.md` diff --git a/docs/doc-src/toolpkg_developer_documentation/05_hooks/render_and_toggle.md b/docs/doc-src/toolpkg_developer_documentation/05_hooks/render_and_toggle.md index 8f9741ee31..06941a881e 100644 --- a/docs/doc-src/toolpkg_developer_documentation/05_hooks/render_and_toggle.md +++ b/docs/doc-src/toolpkg_developer_documentation/05_hooks/render_and_toggle.md @@ -102,7 +102,7 @@ ToolPkg.registerInputMenuTogglePlugin({ ## 权威实现 - `plugins/toolpkg/ToolPkgCommonBridgePlugin.kt`:tag 匹配、渲染结果消费、输入 toggle 缓存和 create/toggle 调度。 -- `core/tools/packTool/ToolPkgParser.kt`、`ToolPkgMainRegistrationScriptParser.kt`:注册定义解析。 +- `core/tools/packTool/parser/ToolPkgParser.kt`、`ToolPkgMainRegistrationScriptParser.kt`:注册定义解析。 - `examples/types/toolpkg.d.ts`:公开 payload、定义和返回类型。 相关页面:[ToolPkg 注册 API](../03_runtime/registry.md)、[Compose DSL](../06_ui_and_compose/compose_dsl.md)、[Hook 总索引](./index.md)。 \ No newline at end of file diff --git a/docs/doc-src/toolpkg_developer_documentation/05_hooks/tool_lifecycle.md b/docs/doc-src/toolpkg_developer_documentation/05_hooks/tool_lifecycle.md index 94f705b97c..d81fb91e3e 100644 --- a/docs/doc-src/toolpkg_developer_documentation/05_hooks/tool_lifecycle.md +++ b/docs/doc-src/toolpkg_developer_documentation/05_hooks/tool_lifecycle.md @@ -104,7 +104,7 @@ ToolPkg.registerToolLifecycleHook({ ## 实现依据 - `plugins/toolpkg/ToolPkgToolLifecycleBridge.kt`:事件构造、队列投递、拦截返回解析和 fail-closed 行为。 -- `core/tools/AIToolHook.kt`、`AIToolHandler.kt`:拦截发生在权限检查与 executor 激活前。 +- `core/tools/runtime/AIToolHook.kt`、`AIToolHandler.kt`:拦截发生在权限检查与 executor 激活前。 - `examples/types/toolpkg.d.ts`:当前声明形状。 相关页面:[ToolPkg 注册 API](../03_runtime/registry.md)、[Hook 总索引](./index.md)、[接口覆盖索引](../09_compatibility/coverage.md)。 diff --git a/docs/doc-src/toolpkg_developer_documentation/09_compatibility/api_versions.md b/docs/doc-src/toolpkg_developer_documentation/09_compatibility/api_versions.md index 166400779f..8e25e982a1 100644 --- a/docs/doc-src/toolpkg_developer_documentation/09_compatibility/api_versions.md +++ b/docs/doc-src/toolpkg_developer_documentation/09_compatibility/api_versions.md @@ -74,8 +74,8 @@ status: complete ## 权威实现 -- `app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiVersion.kt` -- `app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgParser.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiVersion.kt` +- `app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsEngine.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolPkgApiRuntime.kt` - `app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolPkgRegistration.kt` diff --git a/docs/doc-src/toolpkg_developer_documentation/index.md b/docs/doc-src/toolpkg_developer_documentation/index.md index d6287da3c9..9fecb80a5c 100644 --- a/docs/doc-src/toolpkg_developer_documentation/index.md +++ b/docs/doc-src/toolpkg_developer_documentation/index.md @@ -75,8 +75,8 @@ ToolPkg API 版本表示包所依赖的宿主接口契约,独立于包自身 - 全局声明与导出入口:[`examples/types/index.d.ts`](../../../examples/types/index.d.ts) - ToolPkg 注册、Hook、IPC 和 WASM 类型:[`examples/types/toolpkg.d.ts`](../../../examples/types/toolpkg.d.ts) - 各模块声明:[`examples/types/`](../../../examples/types/) -- 包 Manifest 与解析行为:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgParser.kt` -- API 版本支持策略:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgApiVersion.kt` +- 包 Manifest 与解析行为:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt` +- API 版本支持策略:`app/src/main/java/com/ai/assistance/operit/core/tools/packTool/metadata/ToolPkgApiVersion.kt` - JS 侧版本门禁与 ToolPkg facade:`app/src/main/java/com/ai/assistance/operit/core/tools/javascript/JsToolPkgApiRuntime.kt`、`JsToolPkgRegistration.kt` - Hook 触发及结果消费:`app/src/main/java/com/ai/assistance/operit/plugins/toolpkg/` diff --git a/tools/adb/JS_ADB_README.md b/tools/adb/JS_ADB_README.md index 3bd22c348b..ac6d8b909c 100644 --- a/tools/adb/JS_ADB_README.md +++ b/tools/adb/JS_ADB_README.md @@ -51,7 +51,7 @@ This makes them suitable for: ## JS Test Suites In This Repo -The directory [app/src/androidTest/js](/d:/Code/prog/assistance/app/src/androidTest/js) contains real JS runtime tests and probes, including: +The directory [app/src/androidTest/js](../../app/src/androidTest/js) contains real JS runtime tests and probes, including: - bridge contract tests - bridge edge-case tests @@ -61,11 +61,11 @@ The directory [app/src/androidTest/js](/d:/Code/prog/assistance/app/src/androidT Representative locations: -- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract) -- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_edges](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_edges) -- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/script_mode_contract](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/script_mode_contract) -- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/main.js](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/main.js) -- [app/src/androidTest/js/com/ai/assistance/operit/util/ttscleaner/ttscleaner.js](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/util/ttscleaner/ttscleaner.js) +- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract) +- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_edges](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_edges) +- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/script_mode_contract](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/script_mode_contract) +- [app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/main.js](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/main.js) +- [app/src/androidTest/js/com/ai/assistance/operit/util/ttscleaner/ttscleaner.js](../../app/src/androidTest/js/com/ai/assistance/operit/util/ttscleaner/ttscleaner.js) ## Quick Choice @@ -134,7 +134,7 @@ More realistic examples: ```cmd tools\adb\execute_js_dir.bat app\src\androidTest\js com\ai\assistance\operit\core\tools\javascript\bridge_contract\bridge_contract_runner.js run @params.json -tools\adb\execute_js_dir.bat app\src\androidTest\js com\ai\assistance\operit\core\tools\defaultTool\standard\browser\main.js run "{}" +tools\adb\execute_js_dir.bat app\src\androidTest\js com\ai\assistance\operit\core\tools\builtin\web\browser\main.js run "{}" ``` You can still pass inline JSON directly. The scripts now write that JSON into a temporary file and push it to the device, which avoids the old `adb shell am broadcast --es params ...` quoting breakage. On PowerShell, prefer single-quoted JSON like `'{"param1":"value1"}'` or use `@params.json`. @@ -400,7 +400,7 @@ This is best for: ### 2. Add a directory-based runtime test -If the test needs multiple local modules, put it under [app/src/androidTest/js](/d:/Code/prog/assistance/app/src/androidTest/js) and organize it as a small directory-based suite. +If the test needs multiple local modules, put it under [app/src/androidTest/js](../../app/src/androidTest/js) and organize it as a small directory-based suite. Recommended shape: diff --git a/tools/adb/JS_ADB_README_zh.md b/tools/adb/JS_ADB_README_zh.md index 6239f145a0..94f7d2083c 100644 --- a/tools/adb/JS_ADB_README_zh.md +++ b/tools/adb/JS_ADB_README_zh.md @@ -66,7 +66,7 @@ ## 真实测试资产 -仓库里的 [app/src/androidTest/js](/d:/Code/prog/assistance/app/src/androidTest/js) 不是普通示例目录,而是这套工具的重要使用场景之一。 +仓库里的 [app/src/androidTest/js](../../app/src/androidTest/js) 不是普通示例目录,而是这套工具的重要使用场景之一。 其中包括: @@ -78,11 +78,11 @@ 典型目录: -- [bridge_contract](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract) -- [bridge_edges](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_edges) -- [script_mode_contract](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/script_mode_contract) -- [browser main.js](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/core/tools/defaultTool/standard/browser/main.js) -- [ttscleaner.js](/d:/Code/prog/assistance/app/src/androidTest/js/com/ai/assistance/operit/util/ttscleaner/ttscleaner.js) +- [bridge_contract](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_contract) +- [bridge_edges](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/bridge_edges) +- [script_mode_contract](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/javascript/script_mode_contract) +- [browser main.js](../../app/src/androidTest/js/com/ai/assistance/operit/core/tools/builtin/web/browser/main.js) +- [ttscleaner.js](../../app/src/androidTest/js/com/ai/assistance/operit/util/ttscleaner/ttscleaner.js) ## 先记结论 @@ -120,7 +120,7 @@ Windows: ```cmd tools\adb\execute_js_dir.bat app\src\androidTest\js com\ai\assistance\operit\core\tools\javascript\bridge_contract\bridge_contract_runner.js run @params.json -tools\adb\execute_js_dir.bat app\src\androidTest\js com\ai\assistance\operit\core\tools\defaultTool\standard\browser\main.js run "{}" +tools\adb\execute_js_dir.bat app\src\androidTest\js com\ai\assistance\operit\core\tools\builtin\web\browser\main.js run "{}" ``` Linux/macOS: @@ -338,7 +338,7 @@ d:\Code\prog\assistance\.venv\Scripts\python.exe d:\Code\prog\assistance\tools\e ### 2. 加目录化运行时测试 -如果你的测试会引用多个本地模块,建议直接放到 [app/src/androidTest/js](/d:/Code/prog/assistance/app/src/androidTest/js) 下面,按一个小目录来组织。 +如果你的测试会引用多个本地模块,建议直接放到 [app/src/androidTest/js](../../app/src/androidTest/js) 下面,按一个小目录来组织。 推荐组织方式: @@ -555,8 +555,8 @@ exports.myFunction = myFunction; 相关接收器: -- [ScriptExecutionReceiver.kt](/d:/Code/prog/assistance/app/src/main/java/com/ai/assistance/operit/core/tools/javascript/ScriptExecutionReceiver.kt) -- [ToolPkgDebugInstallReceiver.kt](/d:/Code/prog/assistance/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt) +- [ScriptExecutionReceiver.kt](../../app/src/main/java/com/ai/assistance/operit/core/tools/javascript/ScriptExecutionReceiver.kt) +- [ToolPkgDebugInstallReceiver.kt](../../app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgDebugInstallReceiver.kt) ## 故障排查 diff --git a/tools/package_layout/verify_layout_completion.py b/tools/package_layout/verify_layout_completion.py index 4557eba51a..cdf6b9a0c7 100644 --- a/tools/package_layout/verify_layout_completion.py +++ b/tools/package_layout/verify_layout_completion.py @@ -133,7 +133,7 @@ def main(): native_files = [path for path in tree if path.endswith(('.aidl', '.cpp', '.h', '.rs'))] for path in native_files: require(blob_hash((ROOT / path).read_bytes()) == tree[path][1], 'JNI 或 Binder 协议文件发生变化:' + path) - parser_text = (ROOT / 'app/src/main/java/com/ai/assistance/operit/core/tools/packTool/ToolPkgMainRegistrationScriptParser.kt').read_text() + parser_text = (ROOT / 'app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt').read_text() require(parser_text.count('item.optString("runtime").trim().ifBlank { TOOLPKG_RUNTIME_COMPOSE_DSL }') == 2, '界面模块或路由的默认 Compose DSL 被修改') require('return@forEachIndexed' in parser_text, '旧导航声明未忽略') result = { diff --git a/tools/string/count_ui_strings.py b/tools/string/count_ui_strings.py index 38071d38bc..03379a3ec1 100644 --- a/tools/string/count_ui_strings.py +++ b/tools/string/count_ui_strings.py @@ -38,7 +38,7 @@ '\\ui\\features\\settings\\screens\\TagMarketBilingualData.kt', '\\data\\preferences\\CharacterCardBilingualData.kt', '\\data\\preferences\\PromptBilingualData.kt', - '\\core\\tools\\defaultTool\\standard\\StandardUITools.kt' + '\\core\\tools\\builtin\\ui\\StandardUITools.kt' ] def _should_skip_file(file_path: Path) -> bool: From cf31c7c74c255cd1d314d95ef7d7b9b43a23cfaa Mon Sep 17 00:00:00 2001 From: kong <135376906+3316891527@users.noreply.github.com> Date: Thu, 29 Oct 2026 12:51:17 +0000 Subject: [PATCH 3/4] =?UTF-8?q?fix(tools):=20=E8=A1=A5=E9=BD=90=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E5=99=A8=E5=AD=97=E7=AC=A6=E4=B8=B2=E6=8F=92=E5=80=BC?= =?UTF-8?q?=E5=B8=B8=E9=87=8F=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ToolPkgMainRegistrationScriptParser.kt | 5 +++++ .../tools/packTool/parser/ToolPkgParser.kt | 22 +++++++++++++++++++ .../tools-permissions-layout/verification.md | 3 ++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt index c842002f6f..dc18a0f981 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgMainRegistrationScriptParser.kt @@ -6,13 +6,16 @@ import com.ai.assistance.operit.util.logging.AppLogger import org.json.JSONArray import org.json.JSONObject import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_AI_PROVIDER +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_APP_LIFECYCLE_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_INPUT_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_MESSAGE_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_MESSAGE_MENU_ITEM import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_RUNTIME_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_VIEW_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_DESKTOP_WIDGET import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_INPUT_MENU_TOGGLE_PLUGIN import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_MESSAGE_PROCESSING_PLUGIN +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_NAVIGATION_ENTRY import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_ESTIMATE_FINALIZE_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_ESTIMATE_HISTORY_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_FINALIZE_HOOK @@ -22,6 +25,8 @@ import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATIO import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_SYSTEM_PROMPT_COMPOSE_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_TOOL_LIFECYCLE_HOOK import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_TOOL_PROMPT_COMPOSE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_UI_MODULE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_UI_ROUTE import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_XML_RENDER_PLUGIN import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_RUNTIME_COMPOSE_DSL import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgMarketOriginCodec diff --git a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt index fd31dfa42c..2c191fd16d 100644 --- a/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt +++ b/app/src/main/java/com/ai/assistance/operit/core/tools/packTool/parser/ToolPkgParser.kt @@ -18,6 +18,28 @@ import kotlinx.serialization.json.JsonPrimitive import org.hjson.JsonValue import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_NAV_SURFACE_MAIN_SIDEBAR_PLUGINS import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_NAV_SURFACE_PACKAGE_DETAILS +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_AI_PROVIDER +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_APP_LIFECYCLE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_INPUT_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_MESSAGE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_MESSAGE_MENU_ITEM +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_RUNTIME_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_CHAT_VIEW_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_DESKTOP_WIDGET +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_INPUT_MENU_TOGGLE_PLUGIN +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_MESSAGE_PROCESSING_PLUGIN +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_NAVIGATION_ENTRY +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_ESTIMATE_FINALIZE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_ESTIMATE_HISTORY_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_FINALIZE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_HISTORY_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_PROMPT_INPUT_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_SUMMARY_GENERATE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_SYSTEM_PROMPT_COMPOSE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_TOOL_LIFECYCLE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_TOOL_PROMPT_COMPOSE_HOOK +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_UI_ROUTE +import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_REGISTRATION_XML_RENDER_PLUGIN import com.ai.assistance.operit.core.tools.packTool.metadata.TOOLPKG_RUNTIME_COMPOSE_DSL import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgApiCompatibility import com.ai.assistance.operit.core.tools.packTool.metadata.ToolPkgManifestRequirement diff --git a/docs/TODO/chore/tools-permissions-layout/verification.md b/docs/TODO/chore/tools-permissions-layout/verification.md index fe438ca2da..13a02bf7cb 100644 --- a/docs/TODO/chore/tools-permissions-layout/verification.md +++ b/docs/TODO/chore/tools-permissions-layout/verification.md @@ -1,12 +1,13 @@ # 验证记录 -本次交付分为权限实现收口和工具目录迁移两个提交。目录迁移以 [files.json](files.json) 为依据,当前共 117 个文件,其中迁移 111 个,保留 6 个。 +本次交付分为权限实现收口和工具目录迁移两部分。目录迁移以 [files.json](files.json) 为依据,当前共 117 个文件,其中迁移 111 个,保留 6 个。 ## 静态核对 - 权限收口逐项比较 61 个原操作体及辅助方法,以及 17 个管理员文件操作路由,保留原操作实现和只读标记 - 目录迁移比较 264 份受影响 Kotlin 文件的声明内容,除包名、导入和清单对应的显式路径引用外未发现其他变化 - 核对清单全部目标文件、目标包名、迁移符号导入及工具导入名称冲突 +- 共享注册常量的跨包导入同时覆盖普通引用和字符串插值,保留注册校验及错误提示的现有内容 - 静态语法扫描未发现新增问题;最终类型检查与编译结果以仓库工作流为准 - 核对变更 XML、Python 语法、Markdown 本地链接与 Git 差异空白 - 安装、刷新与 UI DSL 调试广播保持原公开组件名,现有 ADB 和编辑器调用仍使用原入口 From 528a8070cb29774133234c353949943b79e640a5 Mon Sep 17 00:00:00 2001 From: kong <135376906+3316891527@users.noreply.github.com> Date: Thu, 29 Oct 2026 13:26:47 +0000 Subject: [PATCH 4/4] =?UTF-8?q?fix(tests):=20=E4=BF=AE=E5=A4=8D=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E5=8D=A1=E7=89=87=E6=B5=8B=E8=AF=95=20XML=20=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E5=BC=95=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/markdown/ToolCardStreamBoundaryAndroidTest.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/androidTest/java/com/ai/assistance/operit/ui/common/markdown/ToolCardStreamBoundaryAndroidTest.kt b/app/src/androidTest/java/com/ai/assistance/operit/ui/common/markdown/ToolCardStreamBoundaryAndroidTest.kt index 164e8cba38..be8e2e9389 100644 --- a/app/src/androidTest/java/com/ai/assistance/operit/ui/common/markdown/ToolCardStreamBoundaryAndroidTest.kt +++ b/app/src/androidTest/java/com/ai/assistance/operit/ui/common/markdown/ToolCardStreamBoundaryAndroidTest.kt @@ -24,8 +24,9 @@ class ToolCardStreamBoundaryAndroidTest { @get:Rule val composeRule = createComposeRule() private fun chars(text: String): Stream = stream { text.forEach { emit(it) } } + // XML 属性含双引号,使用原始字符串避免测试样例被误解析为 Kotlin 代码。 private fun tool(value: String): String = - "$value" + """$value""" private fun render(prefix: String?, tail: String): StreamMarkdownRendererState { val state = StreamMarkdownRendererState() @@ -52,13 +53,13 @@ class ToolCardStreamBoundaryAndroidTest { @Test fun closedToolPrefixKeepsFollowingRequestAndResultSeparate() { val first = tool("首次") - val result = "已创建" + val result = """已创建""" val next = tool("第二次") assertBlocks(render(first, result + next), listOf(first, result, next)) } @Test fun unfinishedToolContinuesOnceAndNewToolsStartNewCards() { - val prefix = "开始" + val prefix = """开始""" val close = "继续" val next = listOf(tool("第二次"), tool("第三次")) assertBlocks(render(prefix, close + next.joinToString("")), listOf(prefix + close) + next) @@ -96,7 +97,7 @@ class ToolCardStreamBoundaryAndroidTest { } @Test fun xmlReplayIncludesRestoredPrefixAndEndsBeforeMessageCompletion() { - val prefix = "开始" + val prefix = """开始""" val body = "继续" val end = "" val source = MutableSharedStreamImpl(replay = Int.MAX_VALUE)