@xopcai/xopc 0.0.413 → 0.0.414
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BT6oqCMD.js → agent-avatar-dicebear-ClobpdW3.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-BFmRRD_4.js → agent-defaults-settings-panel-mf0jgEPE.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CKhZ4UYQ.js +77 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BdCgtTfT.js → app-management-settings-panel-CLunLNGp.js} +1 -1
- package/dist/gateway/static/root/assets/app-window-DXFNqt_0.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-C3-hCFlF.js → appearance-settings-DBEgoE9g.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BZ_MaQJf.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BviFGCy4.js → archive-plugin-JElK4Goq.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-CfzazXE5.js → automations-page-CZ0UqwyU.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-CHUDHNVL.js +8 -0
- package/dist/gateway/static/root/assets/{binary-plugins-Dp-gtJEk.js → binary-plugins-CXFawow6.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-D-DEPdpi.js → block-editor-BoduwSYI.js} +30 -30
- package/dist/gateway/static/root/assets/browser-automations-page-DStDm9y1.js +3 -0
- package/dist/gateway/static/root/assets/browser-settings-page-6I4oetKt.js +3 -0
- package/dist/gateway/static/root/assets/capabilities-page-C-EecWbS.js +2 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BQoCPk3x.js +8 -0
- package/dist/gateway/static/root/assets/{capability-header-actions-CP2fI9Fe.js → capability-header-actions-BasrAWA0.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-DWlrUKBr.js → channels-BKf_-Mdt.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-BL3tFntQ.js → chat-terminal-dock-CwQbzcZ_.js} +1 -1
- package/dist/gateway/static/root/assets/chevron-down-ccbiQQz_.js +1 -0
- package/dist/gateway/static/root/assets/{computer-settings-page-DEQ5GYfC.js → computer-settings-page-DNWeJKfF.js} +1 -1
- package/dist/gateway/static/root/assets/{connector-service-page-CecwMnC5.js → connector-service-page-CxHgC5RM.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-CUBg8spT.js +1 -0
- package/dist/gateway/static/root/assets/{date-picker-N5jnlvPs.js → date-picker-CXxLbLJb.js} +1 -1
- package/dist/gateway/static/root/assets/dependency-picker-DVuWMrSj.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-KbVLtAlO.js +1 -0
- package/dist/gateway/static/root/assets/desktop-pet-settings-BDlg9g4s.js +1 -0
- package/dist/gateway/static/root/assets/device-pairing-wizard-PmP_vGem.js +1 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-CbMbPimD.js → directory-picker-path-field-a7xEodzo.js} +1 -1
- package/dist/gateway/static/root/assets/ellipsis-0k4rZLoy.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-OE1nJMQ8.js → extension-debug-page-CHelH5u_.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BEomiKhy.js → extension-page-CrVHmS9-.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BFOjQeSX.js → extension-settings-page-CiMybi0r.js} +1 -1
- package/dist/gateway/static/root/assets/eye-CABVeTq0.js +1 -0
- package/dist/gateway/static/root/assets/folder-open-CyzJ19I9.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-settings-CR4CsfNN.js → gateway-settings-DnrQ28E2.js} +1 -1
- package/dist/gateway/static/root/assets/{highlight-code-6ONPRH5r.js → highlight-code-AMjU04kR.js} +1 -1
- package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-EJ9Kg4iQ.js → highlighted-body-KQOG7T2V-8ACAVktj.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-pTwVME-g.js +2 -0
- package/dist/gateway/static/root/assets/{image-generation-api-D0HNic89.js → image-generation-api-CVBaWmrV.js} +1 -1
- package/dist/gateway/static/root/assets/imports-page-C5IP3e6d.js +1 -0
- package/dist/gateway/static/root/assets/{index-D_7q1UkI.css → index-BLL0wKRZ.css} +1 -1
- package/dist/gateway/static/root/assets/index-ygkHNYyo.js +710 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Cmi-2SIh.js → keyboard-shortcuts-settings-BhU6VYvd.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-Cwl6EvuX.js +1 -0
- package/dist/gateway/static/root/assets/{local-apps-page-jgaogH9Z.js → local-apps-page-DcP1Bdlk.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CS3hcTOq.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-Dc1opXVr.js → management-settings-DC-Y_-GP.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BRS9puQV.js → media-plugins-BnPpcJ2J.js} +1 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-vckgHpON.js +1 -0
- package/dist/gateway/static/root/assets/note-detail-panel-C7u4dxEk.js +5 -0
- package/dist/gateway/static/root/assets/note-image-lightbox-jvqYtySx.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-Bs7F5Hpf.js +8 -0
- package/dist/gateway/static/root/assets/page-context-capture-button-DO_yhXS1.js +1 -0
- package/dist/gateway/static/root/assets/personal-page-BexL2-PQ.js +1 -0
- package/dist/gateway/static/root/assets/{phone-dependencies-card-DhEsfEUN.js → phone-dependencies-card-ChFtdFhA.js} +1 -1
- package/dist/gateway/static/root/assets/phone-model-picker-CZoIAQ1j.js +1 -0
- package/dist/gateway/static/root/assets/phone-settings-page-DRyK0nHH.js +1 -0
- package/dist/gateway/static/root/assets/{plugin-details-dialog-1BwvmKZi.js → plugin-details-dialog-B-N61jJH.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DaTaSKox.js → preview-open-alternatives-FGqN-mQx.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-wYlC0IVZ.js → product-open-page-CwnHLfdL.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-Bxur-p6S.js → product-preview-content-BD6k5hF9.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DtKmFBml.js +7 -0
- package/dist/gateway/static/root/assets/projects-page-CFZIz9mc.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CWEc7W0m.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-DXNidliV.js → runtime-tools-settings-panel-q_oswAdV.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-DeSZ7SiO.js → schema-form-DoVn5jJK.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BuPqNxpd.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-QTVDCGJG.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-BNYQjZU4.js → settings-form-section-Ce8vVv-9.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-29Ix0jSQ.js → settings-page-DP2w3ejC.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-COQZgKX9.js → setup-status-panel-ZmlE8jIE.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CwMRULXc.js → share-preview-page-DV4dKrmG.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CtNxWqW-.js +1 -0
- package/dist/gateway/static/root/assets/{skill-api-xfB5fUAh.js → skill-api-DTdejInH.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-Bq-3_MCt.js → skill-reload-api-Egaf8PqZ.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page-C6FKxf4J.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DRJu1ehM.js → system-settings-panel-Baxkhov7.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-C77-rpkt.js +2 -0
- package/dist/gateway/static/root/assets/{task-result-evidence-C4o_Yue_.js → task-result-evidence-DIGSC4qF.js} +1 -1
- package/dist/gateway/static/root/assets/{tracing-settings-page-CYslh-Pu.js → tracing-settings-page-BaU8frtc.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-Bi_kw6bv.js → tunnel-api-BCcOUsqu.js} +1 -1
- package/dist/gateway/static/root/assets/usage-page-BFeIbpbi.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-BkB9uD93.js → use-autosave-C1X47WVb.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-u8zY5jea.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-bt8_Agih.js → voice-api-key-field-Bk4DQMTw.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-D3NG14dX.js → work-discovery-overlay-B7_NmTB5.js} +1 -1
- package/dist/gateway/static/root/assets/{xopc-cloud-account-card-B2OUKOQi.js → xopc-cloud-account-card-CJ_akAvc.js} +1 -1
- package/dist/gateway/static/root/index.html +7 -2
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +1 -1
- package/dist/src/agent/background-review/run-background-review.js +1 -1
- package/dist/src/agent/external-tools/cliProvider.js +2 -2
- package/dist/src/agent/external-tools/composio-provider.js +2 -2
- package/dist/src/agent/external-tools/endpoint-provider.js +2 -2
- package/dist/src/agent/service.js +1 -1
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/tool-manuals/phone.d.ts +1 -1
- package/dist/src/agent/tool-manuals/phone.js +2 -2
- package/dist/src/agent/tools/personal-read-tool.js +1 -1
- package/dist/src/agent/tools/phone-use-tool.js +2 -2
- package/dist/src/agent/tools/xopc-use-tool.js +2 -2
- package/dist/src/agent-catalog/capabilities.js +2 -2
- package/dist/src/agent-catalog/repository.js +1 -1
- package/dist/src/automations/capabilities/drafts.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +1 -1
- package/dist/src/capabilities/runtime/dispatcher.js +1 -1
- package/dist/src/capabilities/runtime/product.js +1 -1
- package/dist/src/cli/commands/agents.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension.js +2 -2
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard/model.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/execution-environments/local-worktree-manager.js +1 -1
- package/dist/src/extensions/agent-plugins/skill-catalog.js +1 -1
- package/dist/src/extensions/agent-plugins/validation.js +1 -1
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/global-defaults-admin.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/notes.js +2 -2
- package/dist/src/gateway/hono/routes/phone.js +25 -4
- package/dist/src/gateway/hono/routes/projects.js +2 -2
- package/dist/src/gateway/hono/routes/session-input-handler.js +1 -1
- package/dist/src/gateway/hono/routes/tasks.js +1 -1
- package/dist/src/gateway/image-generation-setup.js +1 -1
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service.js +2 -2
- package/dist/src/gateway/xopc-cloud-capability-setup.js +1 -1
- package/dist/src/imports/importService.js +1 -1
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/local-apps/service.js +1 -1
- package/dist/src/personal-agent/service.js +1 -1
- package/dist/src/phone/adb-driver.d.ts +5 -2
- package/dist/src/phone/adb-driver.js +25 -1
- package/dist/src/phone/app-access.d.ts +10 -0
- package/dist/src/phone/app-access.js +21 -0
- package/dist/src/phone/applications.d.ts +4 -0
- package/dist/src/phone/applications.js +49 -0
- package/dist/src/phone/cloud-adb.d.ts +1 -0
- package/dist/src/phone/cloud-adb.js +52 -2
- package/dist/src/phone/cloud-phones.js +2 -1
- package/dist/src/phone/cloud-scrcpy.js +2 -1
- package/dist/src/phone/contracts.d.ts +9 -1
- package/dist/src/phone/contracts.js +2 -1
- package/dist/src/phone/model-adapter.d.ts +8 -2
- package/dist/src/phone/model-adapter.js +14 -4
- package/dist/src/phone/repository.js +4 -3
- package/dist/src/phone/runtime.d.ts +6 -1
- package/dist/src/phone/runtime.js +36 -8
- package/dist/src/phone/scrcpy-assets.d.ts +4 -0
- package/dist/src/phone/scrcpy-assets.js +16 -0
- package/dist/src/phone/scrcpy.d.ts +1 -4
- package/dist/src/phone/scrcpy.js +3 -11
- package/dist/src/runtime-tools/archive.js +1 -1
- package/dist/src/tasks/capabilities/read.js +2 -2
- package/dist/src/tasks/capabilities/write.js +1 -1
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/voice/realtime/persona-context.js +1 -1
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/agents-Clwskw2J.js +0 -77
- package/dist/gateway/static/root/assets/apps-page-DJbKg3va.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-D_X0_1X3.js +0 -8
- package/dist/gateway/static/root/assets/browser-automations-page-BI-ep6uM.js +0 -3
- package/dist/gateway/static/root/assets/browser-settings-page-BTyQ4-vN.js +0 -3
- package/dist/gateway/static/root/assets/capabilities-page-GNS95mG9.js +0 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-DBiv1HN-.js +0 -8
- package/dist/gateway/static/root/assets/connectors-page-BcpUvrtl.js +0 -1
- package/dist/gateway/static/root/assets/dependency-picker-C4jddxFl.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-BCbiUNQG.js +0 -1
- package/dist/gateway/static/root/assets/desktop-pet-settings-CkKU0JMY.js +0 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard--E2GQoY1.js +0 -1
- package/dist/gateway/static/root/assets/home-page-B9w3a6r2.js +0 -2
- package/dist/gateway/static/root/assets/imports-page-bxTINe-2.js +0 -1
- package/dist/gateway/static/root/assets/index-D1oivYvN.js +0 -710
- package/dist/gateway/static/root/assets/local-app-workbench-page-NGCmXpa_.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-drrr-c2W.js +0 -2
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-B--edI1I.js +0 -1
- package/dist/gateway/static/root/assets/note-detail-panel-C3s4-ytB.js +0 -5
- package/dist/gateway/static/root/assets/note-image-lightbox-D7q5-KuS.js +0 -1
- package/dist/gateway/static/root/assets/notes-page-qVxoErUS.js +0 -8
- package/dist/gateway/static/root/assets/page-context-capture-button-D_VOB2_C.js +0 -1
- package/dist/gateway/static/root/assets/personal-page-B-T8NzQo.js +0 -1
- package/dist/gateway/static/root/assets/phone-model-picker-J4mFDk21.js +0 -1
- package/dist/gateway/static/root/assets/phone-settings-page-BLflz8CQ.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-DwowzxzD.js +0 -7
- package/dist/gateway/static/root/assets/projects-page-Bwvn4i_e.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DrHisOUe.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-seP7t0kv.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-VqBu7gHu.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-BWaykw9E.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-C3LfWsAZ.js +0 -2
- package/dist/gateway/static/root/assets/task-detail-page-XCJFP-Aa.js +0 -2
- package/dist/gateway/static/root/assets/usage-page-CTTmklCs.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-BDqguzRE.js +0 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { PhoneError, init_contracts } from "./contracts.js";
|
|
2
|
+
import { SCRCPY_VERSION } from "../runtime-tools/phone-dependency-catalog.js";
|
|
3
|
+
//#region src/phone/applications.ts
|
|
4
|
+
init_contracts();
|
|
5
|
+
const packageName = /^[a-zA-Z]\w*(?:\.\w+)+$/;
|
|
6
|
+
function phoneApplicationsCommand(remote) {
|
|
7
|
+
return [
|
|
8
|
+
"env",
|
|
9
|
+
`CLASSPATH=${remote}`,
|
|
10
|
+
"app_process",
|
|
11
|
+
"/",
|
|
12
|
+
"com.genymobile.scrcpy.Server",
|
|
13
|
+
SCRCPY_VERSION,
|
|
14
|
+
"list_apps=true",
|
|
15
|
+
"video=false",
|
|
16
|
+
"audio=false",
|
|
17
|
+
"control=false"
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
/** Parse the pinned scrcpy server's app list, including wrapped long labels. */
|
|
21
|
+
function parsePhoneApplications(raw) {
|
|
22
|
+
const text = raw.replace(/\u001b\[[\d;]*m/g, "");
|
|
23
|
+
if (text.length > 1024 * 1024 || !text.includes("List of apps:")) throw new PhoneError("PHONE_APPS_UNAVAILABLE", "Unable to read the phone application list. Check the phone connection and scrcpy dependency.");
|
|
24
|
+
const apps = /* @__PURE__ */ new Map();
|
|
25
|
+
let pending;
|
|
26
|
+
for (const line of text.split(/\r?\n/)) {
|
|
27
|
+
const entry = /^\s*[*-]\s+(.+)$/.exec(line);
|
|
28
|
+
if (entry) {
|
|
29
|
+
const match = /^(.*?)\s+([a-zA-Z]\w*(?:\.\w+)+)$/.exec(entry[1].trim());
|
|
30
|
+
if (match) {
|
|
31
|
+
pending = void 0;
|
|
32
|
+
apps.set(match[2], {
|
|
33
|
+
packageName: match[2],
|
|
34
|
+
label: match[1].trim().slice(0, 120) || match[2]
|
|
35
|
+
});
|
|
36
|
+
} else pending = entry[1].trim().slice(0, 120);
|
|
37
|
+
} else if (pending && packageName.test(line.trim())) {
|
|
38
|
+
apps.set(line.trim(), {
|
|
39
|
+
packageName: line.trim(),
|
|
40
|
+
label: pending
|
|
41
|
+
});
|
|
42
|
+
pending = void 0;
|
|
43
|
+
}
|
|
44
|
+
if (apps.size > 500) throw new PhoneError("PHONE_APPS_LIMIT", "Phone application list exceeds 500 entries");
|
|
45
|
+
}
|
|
46
|
+
return [...apps.values()].sort((a, b) => a.label.localeCompare(b.label));
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { parsePhoneApplications, phoneApplicationsCommand };
|
|
@@ -30,5 +30,6 @@ export declare class CloudAdbConnection {
|
|
|
30
30
|
client(): Promise<Adb>;
|
|
31
31
|
private open;
|
|
32
32
|
command(_path: string, args: string[], signal?: AbortSignal, timeout?: number): Promise<Buffer>;
|
|
33
|
+
applications(signal: AbortSignal): Promise<import("./contracts.js").PhoneApplication[]>;
|
|
33
34
|
driver(): AdbPhoneDriver;
|
|
34
35
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { init_paths, resolveCredentialsDir } from "../config/paths.js";
|
|
2
2
|
import { PhoneError, init_contracts } from "./contracts.js";
|
|
3
|
+
import { readScrcpyServer } from "./scrcpy-assets.js";
|
|
4
|
+
import { parsePhoneApplications, phoneApplicationsCommand } from "./applications.js";
|
|
3
5
|
import { AdbPhoneDriver } from "./adb-driver.js";
|
|
4
6
|
import { join } from "node:path";
|
|
5
7
|
import { createPrivateKey, randomUUID } from "node:crypto";
|
|
@@ -66,7 +68,7 @@ var PhoneCloudKeyStore = class {
|
|
|
66
68
|
}
|
|
67
69
|
};
|
|
68
70
|
/** Direct daemon transport never starts or modifies the host ADB server. */
|
|
69
|
-
var CloudAdbConnection = class {
|
|
71
|
+
var CloudAdbConnection = class CloudAdbConnection {
|
|
70
72
|
socket;
|
|
71
73
|
adb;
|
|
72
74
|
pending;
|
|
@@ -215,8 +217,56 @@ var CloudAdbConnection = class {
|
|
|
215
217
|
this.idle.unref();
|
|
216
218
|
}
|
|
217
219
|
}
|
|
220
|
+
async applications(signal) {
|
|
221
|
+
const combined = AbortSignal.any([signal, AbortSignal.timeout(3e4)]);
|
|
222
|
+
const abort = () => this.close();
|
|
223
|
+
combined.addEventListener("abort", abort, { once: true });
|
|
224
|
+
const remote = `/data/local/tmp/xopc-apps-${randomUUID()}.jar`;
|
|
225
|
+
try {
|
|
226
|
+
combined.throwIfAborted();
|
|
227
|
+
const binary = await readScrcpyServer();
|
|
228
|
+
const adb = await this.client();
|
|
229
|
+
combined.throwIfAborted();
|
|
230
|
+
const sync = await adb.sync();
|
|
231
|
+
try {
|
|
232
|
+
await sync.write({
|
|
233
|
+
filename: remote,
|
|
234
|
+
permission: 384,
|
|
235
|
+
file: new ReadableStream({ start(controller) {
|
|
236
|
+
controller.enqueue(binary);
|
|
237
|
+
controller.close();
|
|
238
|
+
} })
|
|
239
|
+
});
|
|
240
|
+
} finally {
|
|
241
|
+
await sync.dispose();
|
|
242
|
+
}
|
|
243
|
+
return parsePhoneApplications((await this.command("", [
|
|
244
|
+
"-s",
|
|
245
|
+
this.endpoint,
|
|
246
|
+
"shell",
|
|
247
|
+
...phoneApplicationsCommand(remote)
|
|
248
|
+
], combined)).toString());
|
|
249
|
+
} finally {
|
|
250
|
+
combined.removeEventListener("abort", abort);
|
|
251
|
+
await this.command("", [
|
|
252
|
+
"-s",
|
|
253
|
+
this.endpoint,
|
|
254
|
+
"shell",
|
|
255
|
+
"rm",
|
|
256
|
+
"-f",
|
|
257
|
+
remote
|
|
258
|
+
], void 0, 3e3).catch(() => {});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
218
261
|
driver() {
|
|
219
|
-
return new AdbPhoneDriver("", this.command.bind(this), false)
|
|
262
|
+
return new AdbPhoneDriver("", this.command.bind(this), false, async (signal) => {
|
|
263
|
+
const listing = new CloudAdbConnection(this.endpoint, Buffer.from(this.key));
|
|
264
|
+
try {
|
|
265
|
+
return await listing.applications(signal);
|
|
266
|
+
} finally {
|
|
267
|
+
listing.dispose();
|
|
268
|
+
}
|
|
269
|
+
});
|
|
220
270
|
}
|
|
221
271
|
};
|
|
222
272
|
//#endregion
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PhoneError, init_contracts } from "./contracts.js";
|
|
2
2
|
import { SCRCPY_VERSION } from "../runtime-tools/phone-dependency-catalog.js";
|
|
3
|
-
import {
|
|
3
|
+
import { readScrcpyServer } from "./scrcpy-assets.js";
|
|
4
|
+
import { ScrcpyProvider, ScrcpyVideoParser } from "./scrcpy.js";
|
|
4
5
|
import { CloudAdbConnection } from "./cloud-adb.js";
|
|
5
6
|
import { randomBytes } from "node:crypto";
|
|
6
7
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
@@ -25,7 +25,11 @@ export declare const PhoneDeviceSchema: z.ZodObject<{
|
|
|
25
25
|
serial: z.ZodString;
|
|
26
26
|
name: z.ZodString;
|
|
27
27
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
28
|
-
|
|
28
|
+
appAccess: z.ZodOptional<z.ZodEnum<{
|
|
29
|
+
all: "all";
|
|
30
|
+
selected: "selected";
|
|
31
|
+
}>>;
|
|
32
|
+
allowedApps: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
29
33
|
connection: z.ZodOptional<z.ZodObject<{
|
|
30
34
|
kind: z.ZodLiteral<"aliyun-adb">;
|
|
31
35
|
endpoint: z.ZodString;
|
|
@@ -35,6 +39,10 @@ export declare const PhoneDeviceSchema: z.ZodObject<{
|
|
|
35
39
|
revision: z.ZodNumber;
|
|
36
40
|
}, z.core.$strict>;
|
|
37
41
|
export type PhoneDevice = z.infer<typeof PhoneDeviceSchema>;
|
|
42
|
+
export type PhoneApplication = {
|
|
43
|
+
packageName: string;
|
|
44
|
+
label: string;
|
|
45
|
+
};
|
|
38
46
|
export type DiscoveredPhone = {
|
|
39
47
|
serial: string;
|
|
40
48
|
state: string;
|
|
@@ -20,7 +20,8 @@ var init_contracts = __esmMin((() => {
|
|
|
20
20
|
serial: z.string().min(1).max(200),
|
|
21
21
|
name: z.string().trim().min(1).max(100),
|
|
22
22
|
enabled: z.boolean().default(true),
|
|
23
|
-
|
|
23
|
+
appAccess: z.enum(["all", "selected"]).optional(),
|
|
24
|
+
allowedApps: z.array(z.string().regex(/^[a-zA-Z][\w]*(?:\.[\w]+)+$/)).max(500).default([]),
|
|
24
25
|
connection: z.object({
|
|
25
26
|
kind: z.literal("aliyun-adb"),
|
|
26
27
|
endpoint: z.string().max(200),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type PhoneAppAccess } from './app-access.js';
|
|
1
2
|
import type { Config } from '../config/schema.js';
|
|
2
|
-
import { type PhoneAction, type PhoneDecision, type PhoneObservation } from './contracts.js';
|
|
3
|
+
import { type PhoneAction, type PhoneApplication, type PhoneDecision, type PhoneObservation } from './contracts.js';
|
|
3
4
|
export declare function phoneModelProfile(model: unknown): "autoglm-phone-v1" | "structured-phone-v1";
|
|
4
5
|
export declare function validatePhoneModelChange(next: {
|
|
5
6
|
primary: string;
|
|
@@ -7,11 +8,16 @@ export declare function validatePhoneModelChange(next: {
|
|
|
7
8
|
primary: string;
|
|
8
9
|
} | null): void;
|
|
9
10
|
/** Parse only a function name and literal keyword arguments; model text is never executable code. */
|
|
10
|
-
export declare function parseAutoGlmResponse(raw: string, allowedApps: string[]
|
|
11
|
+
export declare function parseAutoGlmResponse(raw: string, allowedApps: string[], options?: {
|
|
12
|
+
appAccess?: PhoneAppAccess['appAccess'];
|
|
13
|
+
applications?: PhoneApplication[];
|
|
14
|
+
}): PhoneDecision;
|
|
11
15
|
export interface PhonePrediction {
|
|
12
16
|
goal: string;
|
|
13
17
|
observation: PhoneObservation;
|
|
14
18
|
allowedApps: string[];
|
|
19
|
+
appAccess?: PhoneAppAccess['appAccess'];
|
|
20
|
+
applications?: PhoneApplication[];
|
|
15
21
|
history: PhoneAction['type'][];
|
|
16
22
|
scenario?: 'settings-about';
|
|
17
23
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PhoneDecisionSchema, PhoneError, PhoneModelMetadataSchema, init_contracts } from "./contracts.js";
|
|
2
2
|
import { getApiKey, init_providers, resolveModel } from "../providers/index.js";
|
|
3
|
+
import { phoneAllowsApp } from "./app-access.js";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
//#region src/phone/model-adapter.ts
|
|
5
6
|
init_providers();
|
|
@@ -17,7 +18,7 @@ function validatePhoneModelChange(next, previous) {
|
|
|
17
18
|
throw new PhoneError("PHONE_MODEL_INCOMPATIBLE", "Select a model with a supported Phone Use profile");
|
|
18
19
|
}
|
|
19
20
|
/** Parse only a function name and literal keyword arguments; model text is never executable code. */
|
|
20
|
-
function parseAutoGlmResponse(raw, allowedApps) {
|
|
21
|
+
function parseAutoGlmResponse(raw, allowedApps, options) {
|
|
21
22
|
let text = raw.trim();
|
|
22
23
|
if (text.includes("<answer>")) text = text.split("<answer>").at(-1).replace(/<\/answer>[\s\S]*$/, "").trim();
|
|
23
24
|
else {
|
|
@@ -133,8 +134,15 @@ function parseAutoGlmResponse(raw, allowedApps) {
|
|
|
133
134
|
let action;
|
|
134
135
|
switch (args.action) {
|
|
135
136
|
case "Launch": {
|
|
136
|
-
|
|
137
|
-
if (typeof app
|
|
137
|
+
let app = args.app === "设置" || args.app === "Settings" ? "com.android.settings" : args.app;
|
|
138
|
+
if (typeof app === "string" && !/^[a-zA-Z]\w*(?:\.\w+)+$/.test(app)) {
|
|
139
|
+
const matches = options?.applications?.filter((candidate) => candidate.label.toLocaleLowerCase() === String(app).toLocaleLowerCase()) ?? [];
|
|
140
|
+
if (matches.length === 1) app = matches[0].packageName;
|
|
141
|
+
}
|
|
142
|
+
if (typeof app !== "string" || !/^[a-zA-Z]\w*(?:\.\w+)+$/.test(app) || !phoneAllowsApp({
|
|
143
|
+
allowedApps,
|
|
144
|
+
appAccess: options?.appAccess ?? "selected"
|
|
145
|
+
}, app)) throw new PhoneError("PHONE_APP_DENIED", "Model requested an application outside the device allowlist");
|
|
138
146
|
action = {
|
|
139
147
|
type: "launch",
|
|
140
148
|
package: app
|
|
@@ -314,7 +322,9 @@ async function createPhoneModel(modelRef, config, agentId) {
|
|
|
314
322
|
type: "text",
|
|
315
323
|
text: JSON.stringify({
|
|
316
324
|
goal: input.goal,
|
|
325
|
+
appAccess: input.appAccess ?? "selected",
|
|
317
326
|
allowedApps: input.allowedApps,
|
|
327
|
+
applications: input.applications?.slice(0, 100),
|
|
318
328
|
currentApp: input.observation.package,
|
|
319
329
|
recentActions: input.history.slice(-6)
|
|
320
330
|
})
|
|
@@ -328,7 +338,7 @@ async function createPhoneModel(modelRef, config, agentId) {
|
|
|
328
338
|
const payload = z.object({ choices: z.array(z.object({ message: z.object({ content: z.string() }) })).min(1) }).safeParse(await boundedJson(response));
|
|
329
339
|
if (!payload.success) throw new PhoneError("PHONE_MODEL_PROTOCOL", "Phone model returned no action");
|
|
330
340
|
const text = payload.data.choices[0].message.content;
|
|
331
|
-
if (profile === "autoglm-phone-v1") return parseAutoGlmResponse(text, input.allowedApps);
|
|
341
|
+
if (profile === "autoglm-phone-v1") return parseAutoGlmResponse(text, input.allowedApps, input);
|
|
332
342
|
try {
|
|
333
343
|
return PhoneDecisionSchema.parse(JSON.parse(text));
|
|
334
344
|
} catch {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { PhoneDeviceSchema, PhoneError, init_contracts } from "./contracts.js";
|
|
2
|
+
import { normalizePhoneAppAccess } from "./app-access.js";
|
|
2
3
|
import { DurableState } from "../storage/sqlite/durable-state.js";
|
|
3
4
|
import { randomUUID } from "node:crypto";
|
|
4
5
|
//#region src/phone/repository.ts
|
|
5
6
|
init_contracts();
|
|
6
7
|
function parseDevice(value) {
|
|
7
8
|
const { agentIds: _removed, ...device } = value;
|
|
8
|
-
return PhoneDeviceSchema.parse(device);
|
|
9
|
+
return normalizePhoneAppAccess(PhoneDeviceSchema.parse(device));
|
|
9
10
|
}
|
|
10
11
|
/** Small settings and latest metadata-only reports; pixels and input text are never stored. */
|
|
11
12
|
var PhoneRepository = class {
|
|
@@ -24,12 +25,12 @@ var PhoneRepository = class {
|
|
|
24
25
|
save(input, id) {
|
|
25
26
|
const previous = id ? this.get(id) : void 0;
|
|
26
27
|
if (this.list().some((device) => device.serial === input.serial && device.id !== id)) throw new PhoneError("PHONE_DEVICE_DUPLICATE", "This ADB device is already registered");
|
|
27
|
-
const next = PhoneDeviceSchema.parse({
|
|
28
|
+
const next = normalizePhoneAppAccess(PhoneDeviceSchema.parse({
|
|
28
29
|
...input,
|
|
29
30
|
id: id ?? randomUUID(),
|
|
30
31
|
createdAt: previous?.createdAt ?? Date.now(),
|
|
31
32
|
revision: (previous?.revision ?? 0) + 1
|
|
32
|
-
});
|
|
33
|
+
}));
|
|
33
34
|
this.devices.set(next.id, next);
|
|
34
35
|
return next;
|
|
35
36
|
}
|
|
@@ -5,7 +5,7 @@ import { CloudPhones } from './cloud-phones.js';
|
|
|
5
5
|
import { type PhoneDriver } from './adb-driver.js';
|
|
6
6
|
import { createPhoneModel } from './model-adapter.js';
|
|
7
7
|
import { PhoneRepository } from './repository.js';
|
|
8
|
-
import { type PhoneAction, type PhoneDevice, type PhoneInput, type PhoneObservation, type PhoneReport } from './contracts.js';
|
|
8
|
+
import { type PhoneAction, type PhoneDevice, type PhoneInput, type PhoneApplication, type PhoneObservation, type PhoneReport } from './contracts.js';
|
|
9
9
|
type ExecutionContext = {
|
|
10
10
|
config: Config;
|
|
11
11
|
agentId: string;
|
|
@@ -26,6 +26,10 @@ export declare class PhoneRuntime {
|
|
|
26
26
|
constructor(repository?: PhoneRepository, driverFactory?: (path: string) => PhoneDriver, modelFactory?: typeof createPhoneModel, interactiveFactory?: (adb: string, serial: string, failed: () => void) => PhoneInteractiveProvider);
|
|
27
27
|
driverFor(device: PhoneDevice, config: Config): Promise<PhoneDriver>;
|
|
28
28
|
discover(config: Config, signal?: AbortSignal): Promise<import("./contracts.js").DiscoveredPhone[]>;
|
|
29
|
+
applications(input: {
|
|
30
|
+
deviceId?: string;
|
|
31
|
+
serial?: string;
|
|
32
|
+
}, config: Config, signal: AbortSignal): Promise<PhoneApplication[]>;
|
|
29
33
|
preview(id: string, config: Config, signal: AbortSignal): Promise<PhoneObservation>;
|
|
30
34
|
previewSession(owner: string, context: ExecutionContext, signal: AbortSignal): Promise<PhoneObservation>;
|
|
31
35
|
reports(): PhoneReport[];
|
|
@@ -50,6 +54,7 @@ export declare class PhoneRuntime {
|
|
|
50
54
|
report: PhoneReport;
|
|
51
55
|
ownControl: boolean;
|
|
52
56
|
allowedApps: string[];
|
|
57
|
+
appAccess: "all" | "selected";
|
|
53
58
|
frame: {
|
|
54
59
|
seq: number;
|
|
55
60
|
capturedAt: number;
|
|
@@ -2,6 +2,7 @@ import { createLogger } from "../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { MOCK_PHONE_MODEL, PhoneError, PhoneInputSchema, init_contracts } from "./contracts.js";
|
|
4
4
|
import { resolveEffectiveAgentConfigForAgent } from "../config/agent-profile.js";
|
|
5
|
+
import { phoneAllowsApp, phoneAppAccess } from "./app-access.js";
|
|
5
6
|
import { PhoneFrameCache, PhoneOperationBudget } from "./live-state.js";
|
|
6
7
|
import { PhoneInteractiveSession } from "./interactive-session.js";
|
|
7
8
|
import { AdbPhoneDriver, resolveAdbPath } from "./adb-driver.js";
|
|
@@ -40,13 +41,30 @@ var PhoneRuntime = class {
|
|
|
40
41
|
async discover(config, signal) {
|
|
41
42
|
return this.driverFactory(resolveAdbPath(config.phone.adbPath)).discover(signal);
|
|
42
43
|
}
|
|
44
|
+
async applications(input, config, signal) {
|
|
45
|
+
let driver;
|
|
46
|
+
let serial;
|
|
47
|
+
if (input.deviceId) {
|
|
48
|
+
const device = this.repository.get(input.deviceId);
|
|
49
|
+
if (!device.enabled) throw new PhoneError("PHONE_DEVICE_DENIED", "Phone access is disabled", 403);
|
|
50
|
+
driver = await this.driverFor(device, config);
|
|
51
|
+
serial = device.serial;
|
|
52
|
+
} else {
|
|
53
|
+
const found = (await this.discover(config, signal)).find((device) => device.serial === input.serial && device.state === "device");
|
|
54
|
+
if (!found) throw new PhoneError("PHONE_DEVICE_OFFLINE", "Choose a connected and authorized phone");
|
|
55
|
+
driver = this.driverFactory(resolveAdbPath(config.phone.adbPath));
|
|
56
|
+
serial = found.serial;
|
|
57
|
+
}
|
|
58
|
+
if (!driver.applications) throw new PhoneError("PHONE_APPS_UNAVAILABLE", "The phone provider cannot list applications");
|
|
59
|
+
return driver.applications(serial, signal);
|
|
60
|
+
}
|
|
43
61
|
async preview(id, config, signal) {
|
|
44
62
|
const device = this.repository.get(id);
|
|
45
63
|
if (!device.enabled) throw new PhoneError("PHONE_DEVICE_DENIED", "Phone access is disabled", 403);
|
|
46
64
|
const lease = this.repository.acquire(device.serial);
|
|
47
65
|
try {
|
|
48
66
|
const observation = await (await this.driverFor(device, config)).observe(device.serial, signal);
|
|
49
|
-
if (!device
|
|
67
|
+
if (!phoneAllowsApp(device, observation.package)) {
|
|
50
68
|
observation.frame.fill(0);
|
|
51
69
|
throw new PhoneError("PHONE_APP_DENIED", "Open an allowed app before previewing the screen");
|
|
52
70
|
}
|
|
@@ -91,7 +109,7 @@ var PhoneRuntime = class {
|
|
|
91
109
|
this.repository.renew(session.device.serial, session.lease);
|
|
92
110
|
}
|
|
93
111
|
allowedScreen(session, observation) {
|
|
94
|
-
if (!session.device
|
|
112
|
+
if (!phoneAllowsApp(session.device, observation.package)) throw new PhoneError("PHONE_APP_DENIED", "The foreground application is outside this phone session allowlist. Open an allowed app or reopen with appPackage.");
|
|
95
113
|
}
|
|
96
114
|
async execute(owner, raw, context, signal = new AbortController().signal) {
|
|
97
115
|
const input = PhoneInputSchema.parse(raw);
|
|
@@ -132,6 +150,12 @@ var PhoneRuntime = class {
|
|
|
132
150
|
try {
|
|
133
151
|
const adapter = await this.modelFactory(modelRef, context.config, context.agentId);
|
|
134
152
|
signal.throwIfAborted();
|
|
153
|
+
let applications = [];
|
|
154
|
+
if (input.mode === "control" && modelRef !== "phone-mock/settings-about" && driver.applications) try {
|
|
155
|
+
applications = await driver.applications(device.serial, signal);
|
|
156
|
+
} catch {
|
|
157
|
+
signal.throwIfAborted();
|
|
158
|
+
}
|
|
135
159
|
const now = Date.now();
|
|
136
160
|
const session = {
|
|
137
161
|
device,
|
|
@@ -143,6 +167,7 @@ var PhoneRuntime = class {
|
|
|
143
167
|
modelRef,
|
|
144
168
|
adbPath,
|
|
145
169
|
context,
|
|
170
|
+
applications,
|
|
146
171
|
frames: new PhoneFrameCache(),
|
|
147
172
|
io: Promise.resolve(),
|
|
148
173
|
ioBusy: false,
|
|
@@ -174,7 +199,7 @@ var PhoneRuntime = class {
|
|
|
174
199
|
};
|
|
175
200
|
this.sessions.set(owner, session);
|
|
176
201
|
if (input.appPackage) {
|
|
177
|
-
if (input.mode !== "control" || !device
|
|
202
|
+
if (input.mode !== "control" || !phoneAllowsApp(device, input.appPackage)) throw new PhoneError("PHONE_APP_DENIED", "Launching requires control mode and an allowed application");
|
|
178
203
|
const epoch = session.report.controlEpoch;
|
|
179
204
|
const observation = await this.observe(session, signal);
|
|
180
205
|
try {
|
|
@@ -291,6 +316,8 @@ var PhoneRuntime = class {
|
|
|
291
316
|
goal: input.goal,
|
|
292
317
|
observation,
|
|
293
318
|
allowedApps: session.device.allowedApps,
|
|
319
|
+
appAccess: phoneAppAccess(session.device),
|
|
320
|
+
applications: session.applications.filter((app) => phoneAllowsApp(session.device, app.packageName)),
|
|
294
321
|
history: session.report.steps.map((step) => step.action),
|
|
295
322
|
scenario: input.scenario
|
|
296
323
|
}, AbortSignal.any([signal, session.prediction.signal]));
|
|
@@ -416,8 +443,8 @@ var PhoneRuntime = class {
|
|
|
416
443
|
if (session.human && Date.now() > (session.humanExpiresAt ?? 0)) throw new PhoneError("PHONE_CONTROL_REQUIRED", "Manual control expired", 409);
|
|
417
444
|
if (!session.human && session.report.actions - (session.report.humanActions ?? 0) >= context.config.phone.maxActionsPerSession) throw new PhoneError("PHONE_ACTION_LIMIT", "Phone action limit reached");
|
|
418
445
|
if (session.human && (session.report.humanActions ?? 0) >= 1200) throw new PhoneError("PHONE_ACTION_LIMIT", "Manual input limit reached; reopen the session");
|
|
419
|
-
if (action.type === "launch" && !session.device
|
|
420
|
-
if (action.type === "home") throw new PhoneError("PHONE_APP_DENIED", "Home leaves the app allowlist");
|
|
446
|
+
if (action.type === "launch" && !phoneAllowsApp(session.device, action.package)) throw new PhoneError("PHONE_APP_DENIED", "Application is not authorized");
|
|
447
|
+
if (action.type === "home" && phoneAppAccess(session.device) !== "all") throw new PhoneError("PHONE_APP_DENIED", "Home leaves the app allowlist");
|
|
421
448
|
if (action.type === "typeText" && !observation.elements.some((node) => node.focused && node.editable && !node.password)) throw new PhoneError("PHONE_INPUT_NOT_FOCUSED", "Focus a non-password editable field before typing", 409);
|
|
422
449
|
const step = {
|
|
423
450
|
action: action.type,
|
|
@@ -497,7 +524,7 @@ var PhoneRuntime = class {
|
|
|
497
524
|
return this.io(session, async () => {
|
|
498
525
|
signal.throwIfAborted();
|
|
499
526
|
const observation = await (forText && session.driver.observeForText ? session.driver.observeForText : session.driver.observe).call(session.driver, session.device.serial, signal);
|
|
500
|
-
if (session.device
|
|
527
|
+
if (phoneAllowsApp(session.device, observation.package)) {
|
|
501
528
|
if (Date.now() - session.viewedAt < 3e4 && !terminal.has(session.report.status)) session.frames.set(observation);
|
|
502
529
|
} else session.frames.clear();
|
|
503
530
|
return observation;
|
|
@@ -597,6 +624,7 @@ var PhoneRuntime = class {
|
|
|
597
624
|
report: structuredClone(session.report),
|
|
598
625
|
ownControl: Boolean(session.human === client),
|
|
599
626
|
allowedApps: [...session.device.allowedApps],
|
|
627
|
+
appAccess: phoneAppAccess(session.device),
|
|
600
628
|
frame: session.frames.get() ? {
|
|
601
629
|
seq: session.frames.get().seq,
|
|
602
630
|
capturedAt: session.frames.get().capturedAt
|
|
@@ -631,7 +659,7 @@ var PhoneRuntime = class {
|
|
|
631
659
|
if (terminal.has(session.report.status)) throw new PhoneError("PHONE_VIDEO_ENDED", "Phone session ended", 409);
|
|
632
660
|
this.guard(session, session.context);
|
|
633
661
|
const app = await provider.foreground(AbortSignal.timeout(2e3));
|
|
634
|
-
if (!session.device
|
|
662
|
+
if (!phoneAllowsApp(session.device, app)) throw new PhoneError("PHONE_APP_DENIED", "Current page is outside the authorized applications", 403);
|
|
635
663
|
session.viewedAt = Date.now();
|
|
636
664
|
}, (client, epoch) => {
|
|
637
665
|
if (terminal.has(session.report.status) || session.report.handoff !== "idle" || session.report.controlOwner !== "human" || session.human !== client || session.report.controlEpoch !== epoch || Date.now() > (session.humanExpiresAt ?? 0)) throw new PhoneError("PHONE_CONTROL_CHANGED", "Manual control is no longer available", 409);
|
|
@@ -811,7 +839,7 @@ var PhoneRuntime = class {
|
|
|
811
839
|
for (const wake of session.wake) wake();
|
|
812
840
|
} else if (input.op === "recover") {
|
|
813
841
|
if (session.human !== client || Date.now() > (session.humanExpiresAt ?? 0)) throw new PhoneError("PHONE_CONTROL_REQUIRED", "Take over the phone first", 409);
|
|
814
|
-
if (input.action?.type !== "launch" || !session.device
|
|
842
|
+
if (input.action?.type !== "launch" || !phoneAllowsApp(session.device, input.action.package)) throw new PhoneError("PHONE_APP_DENIED", "Choose an authorized recovery application", 403);
|
|
815
843
|
const observation = await this.io(session, () => session.driver.capture ? session.driver.capture(session.device.serial, session.controller.signal) : session.driver.observe(session.device.serial, session.controller.signal));
|
|
816
844
|
try {
|
|
817
845
|
if (!await this.dispatch(session, input.action, observation, context, session.controller.signal, input.epoch, true)) throw new PhoneError("PHONE_CONTROL_CHANGED", "Control changed before recovery", 409);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PhoneError, init_contracts } from "./contracts.js";
|
|
2
|
+
import { SCRCPY_SHA256, SCRCPY_VERSION, managedScrcpyServerPath } from "../runtime-tools/phone-dependency-catalog.js";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
//#region src/phone/scrcpy-assets.ts
|
|
6
|
+
init_contracts();
|
|
7
|
+
const scrcpyServerPath = managedScrcpyServerPath;
|
|
8
|
+
async function readScrcpyServer() {
|
|
9
|
+
const binary = await readFile(scrcpyServerPath()).catch(() => {
|
|
10
|
+
throw new PhoneError("PHONE_VIDEO_SETUP_REQUIRED", "Install scrcpy server in Settings → Phone Use → Dependencies");
|
|
11
|
+
});
|
|
12
|
+
if (createHash("sha256").update(binary).digest("hex") !== "7e70323ba7f259649dd4acce97ac4fefbae8102b2c6d91e2e7be613fd5354be0") throw new PhoneError("PHONE_VIDEO_HASH_MISMATCH", "Phone video server checksum mismatch");
|
|
13
|
+
return binary;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { SCRCPY_SHA256, SCRCPY_VERSION, readScrcpyServer, scrcpyServerPath };
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { SCRCPY_SHA256, SCRCPY_VERSION } from '../runtime-tools/phone-dependency-catalog.js';
|
|
2
1
|
import type { PhoneInteractiveProvider, PhonePointer, PhoneVideoGeometry, PhoneVideoPacket } from './live-provider.js';
|
|
3
|
-
export { SCRCPY_VERSION, SCRCPY_SHA256 };
|
|
4
|
-
export declare const scrcpyServerPath: (stateDir?: string) => string;
|
|
2
|
+
export { readScrcpyServer, scrcpyServerPath, SCRCPY_VERSION, SCRCPY_SHA256 } from './scrcpy-assets.js';
|
|
5
3
|
/** The pinned server sends codec metadata followed by bounded, length-prefixed packets. */
|
|
6
4
|
export declare class ScrcpyVideoParser {
|
|
7
5
|
private buffer;
|
|
@@ -9,7 +7,6 @@ export declare class ScrcpyVideoParser {
|
|
|
9
7
|
push(chunk: Buffer, packet: (packet: PhoneVideoPacket) => void): void;
|
|
10
8
|
}
|
|
11
9
|
export declare function scrcpyTouch(phase: PhonePointer['phase'], x: number, y: number, width: number, height: number): Buffer;
|
|
12
|
-
export declare function readScrcpyServer(): Promise<Buffer>;
|
|
13
10
|
/** Local and cloud transports share geometry, gesture sequencing and revocation. */
|
|
14
11
|
export declare abstract class ScrcpyProvider implements PhoneInteractiveProvider {
|
|
15
12
|
private onFailure;
|
package/dist/src/phone/scrcpy.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { PhoneError, init_contracts } from "./contracts.js";
|
|
2
2
|
import { spawnPhoneCommand } from "../process/phone-process.js";
|
|
3
|
-
import { SCRCPY_SHA256, SCRCPY_VERSION
|
|
3
|
+
import { SCRCPY_SHA256, SCRCPY_VERSION } from "../runtime-tools/phone-dependency-catalog.js";
|
|
4
|
+
import { readScrcpyServer, scrcpyServerPath } from "./scrcpy-assets.js";
|
|
4
5
|
import { AdbPhoneDriver, runAdb } from "./adb-driver.js";
|
|
5
|
-
import {
|
|
6
|
-
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { randomBytes } from "node:crypto";
|
|
7
7
|
import { connect } from "node:net";
|
|
8
8
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
9
9
|
import { h264ParseConfiguration } from "@yume-chan/scrcpy";
|
|
10
10
|
//#region src/phone/scrcpy.ts
|
|
11
11
|
init_contracts();
|
|
12
|
-
const scrcpyServerPath = managedScrcpyServerPath;
|
|
13
12
|
/** The pinned server sends codec metadata followed by bounded, length-prefixed packets. */
|
|
14
13
|
var ScrcpyVideoParser = class {
|
|
15
14
|
buffer = Buffer.alloc(0);
|
|
@@ -55,13 +54,6 @@ function scrcpyTouch(phase, x, y, width, height) {
|
|
|
55
54
|
buffer.writeUInt16BE(phase === "up" || phase === "cancel" ? 0 : 65535, 22);
|
|
56
55
|
return buffer;
|
|
57
56
|
}
|
|
58
|
-
async function readScrcpyServer() {
|
|
59
|
-
const binary = await readFile(scrcpyServerPath()).catch(() => {
|
|
60
|
-
throw new PhoneError("PHONE_VIDEO_SETUP_REQUIRED", "Install scrcpy server in Settings → Phone Use → Dependencies");
|
|
61
|
-
});
|
|
62
|
-
if (createHash("sha256").update(binary).digest("hex") !== "7e70323ba7f259649dd4acce97ac4fefbae8102b2c6d91e2e7be613fd5354be0") throw new PhoneError("PHONE_VIDEO_HASH_MISMATCH", "Phone video server checksum mismatch");
|
|
63
|
-
return binary;
|
|
64
|
-
}
|
|
65
57
|
/** Local and cloud transports share geometry, gesture sequencing and revocation. */
|
|
66
58
|
var ScrcpyProvider = class {
|
|
67
59
|
descriptor = {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { RuntimeError } from "./errors.js";
|
|
2
2
|
import { isAbsolute, join, posix, relative, resolve } from "node:path";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
-
import AdmZip from "adm-zip";
|
|
5
4
|
import { lstat, mkdir, readdir, readlink, rename, rm, stat } from "node:fs/promises";
|
|
5
|
+
import AdmZip from "adm-zip";
|
|
6
6
|
//#region src/runtime-tools/archive.ts
|
|
7
7
|
const MAX_ARCHIVE_ENTRIES = 5e4;
|
|
8
8
|
const MAX_TAR_OUTPUT_BYTES = 16 * 1024 * 1024;
|
|
@@ -2,10 +2,10 @@ import { ProductReadContracts } from "../../../packages/gateway-contract/src/cap
|
|
|
2
2
|
import { init_src } from "../../../packages/gateway-contract/src/index.js";
|
|
3
3
|
import { TaskRepository, init_task_repository } from "../task-repository.js";
|
|
4
4
|
import { TaskRunRepository, init_task_run_repository } from "../task-run-repository.js";
|
|
5
|
-
import { TaskReadModelProjector } from "../task-read-model-projector.js";
|
|
6
|
-
import { TaskConversationRepository } from "../task-conversation-repository.js";
|
|
7
5
|
import { CapabilityError } from "../../capabilities/runtime/errors.js";
|
|
8
6
|
import { defineReadCapability } from "../../capabilities/runtime/dispatcher.js";
|
|
7
|
+
import { TaskReadModelProjector } from "../task-read-model-projector.js";
|
|
8
|
+
import { TaskConversationRepository } from "../task-conversation-repository.js";
|
|
9
9
|
import { TaskContextRepository } from "../task-context-repository.js";
|
|
10
10
|
import { TaskDependencyService } from "../task-dependency-service.js";
|
|
11
11
|
import { TaskCriterionReviewRepository } from "../task-criterion-review-repository.js";
|
|
@@ -2,9 +2,9 @@ import { TaskCommandRequestSchema, TaskCreateRequestSchema, TaskDetailResponseSc
|
|
|
2
2
|
import { init_src } from "../../../packages/gateway-contract/src/index.js";
|
|
3
3
|
import { TaskRepository, init_task_repository } from "../task-repository.js";
|
|
4
4
|
import { TaskRunRepository, init_task_run_repository } from "../task-run-repository.js";
|
|
5
|
-
import { resolveTaskLocale } from "../task-language.js";
|
|
6
5
|
import { CapabilityError } from "../../capabilities/runtime/errors.js";
|
|
7
6
|
import { defineAtomicCapability } from "../../capabilities/runtime/dispatcher.js";
|
|
7
|
+
import { resolveTaskLocale } from "../task-language.js";
|
|
8
8
|
import { resolveProjectAgentId } from "../../projects/project-agent.js";
|
|
9
9
|
import { resolveResponseLanguageForSession } from "../../agent/prompt/response-language.js";
|
|
10
10
|
import { TaskApplicationService } from "../task-application-service.js";
|
|
@@ -10,6 +10,7 @@ import { getSessionMetadata } from "../../storage/sqlite/session-read-repository
|
|
|
10
10
|
import { init_sqlite } from "../../storage/sqlite/index.js";
|
|
11
11
|
import { normalizeAgentId } from "../../agent-catalog/id.js";
|
|
12
12
|
import { init_agent_scope, listAgentEntries } from "../../agent/agent-scope.js";
|
|
13
|
+
import { AgentCatalogService } from "../../agent-catalog/service.js";
|
|
13
14
|
import { init_paths } from "../../config/paths.js";
|
|
14
15
|
import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
|
|
15
16
|
import { resolveEffectiveAgentProfile } from "../../config/agent-profile.js";
|
|
@@ -22,7 +23,6 @@ import { buildSessionTimeline } from "../../session/transcript-outline.js";
|
|
|
22
23
|
import { transcriptRowsToClientHistory } from "../../session/client-history.js";
|
|
23
24
|
import { createCreateShareTool, isShareToolAvailable } from "../../agent/tools/create-share-tool.js";
|
|
24
25
|
import { evictEmbeddedSessionRunner } from "../../agent/embedded/session-runner.js";
|
|
25
|
-
import { AgentCatalogService } from "../../agent-catalog/service.js";
|
|
26
26
|
import { SessionIndex } from "../../session/manager.js";
|
|
27
27
|
import "../../session/index.js";
|
|
28
28
|
import { parseModelRef } from "../../agent/models/selection.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { init_agent_scope, resolveAgentProfileDir } from "../../agent/agent-scope.js";
|
|
2
|
-
import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
|
|
3
2
|
import { DEFAULT_SOUL_FILENAME } from "../../agent/context/workspace.js";
|
|
3
|
+
import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
|
|
4
4
|
import { loadProfileBootstrapFiles } from "../../agent/bootstrap/load-bootstrap-files.js";
|
|
5
5
|
import { join } from "node:path";
|
|
6
6
|
import { statSync } from "node:fs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.414",
|
|
4
4
|
"description": "Local-first personal AI with Ada, task delegation, files, projects and automations. Use cloud or local models.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -172,10 +172,10 @@
|
|
|
172
172
|
"xlsx": "file:web/vendor/xlsx-0.20.3.tgz",
|
|
173
173
|
"@xopcai/browser-control-contract": "0.1.0",
|
|
174
174
|
"@xopcai/computer-control-contract": "0.1.0",
|
|
175
|
-
"@xopcai/endpoint-tools-protocol": "0.0.0",
|
|
176
|
-
"@xopcai/gateway-contract": "0.0.0",
|
|
177
175
|
"@xopcai/endpoint-tools-client": "0.0.0",
|
|
176
|
+
"@xopcai/endpoint-tools-protocol": "0.0.0",
|
|
178
177
|
"@xopcai/image-providers": "0.1.0",
|
|
178
|
+
"@xopcai/gateway-contract": "0.0.0",
|
|
179
179
|
"@xopcai/realtime-client": "0.0.0",
|
|
180
180
|
"@xopcai/realtime-protocol": "0.0.0"
|
|
181
181
|
},
|