@agimon-ai/po-computer-use 0.0.0-alpha.24 → 0.0.0-alpha.26
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/extensions/server.cjs +97 -14
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts.map +1 -1
- package/dist/extensions/server.mjs +98 -15
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +252 -36
- package/dist/extensions/web.mjs.map +1 -1
- package/package.json +10 -10
|
@@ -142,6 +142,19 @@ function computerScriptFailure(error) {
|
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
//#endregion
|
|
145
|
+
//#region src/types/desktopPermissions.ts
|
|
146
|
+
/** The macOS privacy permissions Desktop reports, in the order the settings page shows them. */
|
|
147
|
+
const DESKTOP_PERMISSIONS = [
|
|
148
|
+
"accessibility",
|
|
149
|
+
"screen-recording",
|
|
150
|
+
"microphone",
|
|
151
|
+
"automation",
|
|
152
|
+
"full-disk-access"
|
|
153
|
+
];
|
|
154
|
+
function isDesktopPermission(value) {
|
|
155
|
+
return typeof value === "string" && DESKTOP_PERMISSIONS.includes(value);
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
145
158
|
//#region src/types/apiRoutes.ts
|
|
146
159
|
/**
|
|
147
160
|
* This package's routes, as data.
|
|
@@ -234,6 +247,18 @@ var apiRoutes_default = (0, _agimon_ai_po_core_web.defineApiRoutes)({
|
|
|
234
247
|
method: "POST",
|
|
235
248
|
path: COMPUTER_USE_ROUTES.hubStop,
|
|
236
249
|
response: (0, _agimon_ai_po_core_web.apiResponse)()
|
|
250
|
+
},
|
|
251
|
+
/** Desktop's macOS permission states, served by the hub's `desktop-permissions` mount. */
|
|
252
|
+
desktopPermissions: {
|
|
253
|
+
method: "GET",
|
|
254
|
+
path: "/",
|
|
255
|
+
response: (0, _agimon_ai_po_core_web.apiResponse)()
|
|
256
|
+
},
|
|
257
|
+
/** Asks macOS for the body's permission on the Mac running Desktop; answers the states after. */
|
|
258
|
+
requestDesktopPermission: {
|
|
259
|
+
method: "POST",
|
|
260
|
+
path: "/",
|
|
261
|
+
response: (0, _agimon_ai_po_core_web.apiResponse)()
|
|
237
262
|
}
|
|
238
263
|
});
|
|
239
264
|
//#endregion
|
|
@@ -676,7 +701,7 @@ function createComputerUseServer(host, apiContext) {
|
|
|
676
701
|
const publishMode = () => modeOwner?.publish();
|
|
677
702
|
const applyState = (next) => {
|
|
678
703
|
state = next;
|
|
679
|
-
host.context.client.setStatus(COMPUTER_USE_STATUS_KEY, next === void 0 || next.phase === "inactive" ? void 0 : `computer use: ${next.phase}`);
|
|
704
|
+
host.context.client.setStatus(COMPUTER_USE_STATUS_KEY, next === void 0 || next.phase === "inactive" && !modeSelected() && next.artifact === void 0 ? void 0 : `computer use: ${next.phase}`);
|
|
680
705
|
publishMode();
|
|
681
706
|
for (const listener of restrictionListeners) listener();
|
|
682
707
|
};
|
|
@@ -1024,6 +1049,43 @@ var root_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoot)((cont
|
|
|
1024
1049
|
};
|
|
1025
1050
|
});
|
|
1026
1051
|
//#endregion
|
|
1052
|
+
//#region src/services/desktopPermissionsApi/index.ts
|
|
1053
|
+
/**
|
|
1054
|
+
* Desktop's macOS permissions for the settings page.
|
|
1055
|
+
*
|
|
1056
|
+
* Hub-scoped because the permissions belong to the Mac, not a session. The server's
|
|
1057
|
+
* Desktop link reads and requests them; without Desktop the mount answers 404, so
|
|
1058
|
+
* the page can say so instead of guessing.
|
|
1059
|
+
*/
|
|
1060
|
+
async function desktopPermissionsResponse(access, request) {
|
|
1061
|
+
const path = new URL(request.url).pathname;
|
|
1062
|
+
const change = request.method === apiRoutes_default.requestDesktopPermission.method;
|
|
1063
|
+
if (path !== apiRoutes_default.desktopPermissions.path || !change && request.method !== apiRoutes_default.desktopPermissions.method) return Response.json({ error: "Not found." }, { status: 404 });
|
|
1064
|
+
if (access === void 0) return Response.json({ error: "Po Desktop is not running this server." }, { status: 404 });
|
|
1065
|
+
if (!access.authorize(request.headers, change)) return Response.json({ error: "Open Po Desktop on that Mac, or confirm with your passkey." }, { status: 403 });
|
|
1066
|
+
let permission;
|
|
1067
|
+
if (change) {
|
|
1068
|
+
const body = await request.json().catch(() => void 0);
|
|
1069
|
+
if (!isDesktopPermission(body?.permission)) return Response.json({ error: "Name one permission to ask for." }, { status: 400 });
|
|
1070
|
+
permission = body.permission;
|
|
1071
|
+
}
|
|
1072
|
+
try {
|
|
1073
|
+
return Response.json(await access.request(permission));
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
return Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: 502 });
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
//#endregion
|
|
1079
|
+
//#region src/extensions/(backend)/api/desktop-permissions/route.server.ts
|
|
1080
|
+
/** Mounts Desktop's macOS permissions at `desktop-permissions`, which the folder names. */
|
|
1081
|
+
var route_server_default$1 = (0, _agimon_ai_po_core_extensionFile.defineRoute)({
|
|
1082
|
+
basePath: "desktop-permissions",
|
|
1083
|
+
start: (context) => ({
|
|
1084
|
+
fetch: (request) => desktopPermissionsResponse(context.desktopPermissions, request),
|
|
1085
|
+
close: () => void 0
|
|
1086
|
+
})
|
|
1087
|
+
});
|
|
1088
|
+
//#endregion
|
|
1027
1089
|
//#region src/services/webComputerUseAvailability/index.ts
|
|
1028
1090
|
var MissingComputerUseApiError = class extends Error {};
|
|
1029
1091
|
function computerUseSessionApiError(status, value) {
|
|
@@ -1035,6 +1097,8 @@ function computerUseSessionApiError(status, value) {
|
|
|
1035
1097
|
//#region src/services/webComputerUseChannel/index.ts
|
|
1036
1098
|
/** Computer use runs on the Po Desktop host, so every other client declines it. */
|
|
1037
1099
|
const DESKTOP_UNAVAILABLE = "Po Desktop computer use is unavailable.";
|
|
1100
|
+
const SESSION_READY_ATTEMPTS = 5;
|
|
1101
|
+
const SESSION_READY_RETRY_MS = 200;
|
|
1038
1102
|
function record(value) {
|
|
1039
1103
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
1040
1104
|
}
|
|
@@ -1075,12 +1139,21 @@ function createComputerUseChannel() {
|
|
|
1075
1139
|
const requests = /* @__PURE__ */ new Map();
|
|
1076
1140
|
let activeSessionId;
|
|
1077
1141
|
let closed = false;
|
|
1078
|
-
const sessionRequest = async (scope, path, method = "GET", value) =>
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1142
|
+
const sessionRequest = async (scope, path, method = "GET", value) => {
|
|
1143
|
+
const registeredScope = scopes.get(scope.sessionId);
|
|
1144
|
+
for (let attempt = 1;; attempt++) {
|
|
1145
|
+
if (closed || registeredScope === void 0 || scopes.get(scope.sessionId) !== registeredScope) throw new Error("Computer-use session is closed.");
|
|
1146
|
+
const response = await host.requestSessionApi(scope, {
|
|
1147
|
+
basePath: API_BASE_PATH,
|
|
1148
|
+
path,
|
|
1149
|
+
method,
|
|
1150
|
+
...value === void 0 ? {} : { body: JSON.stringify(value) }
|
|
1151
|
+
});
|
|
1152
|
+
if (response.status !== 503 || attempt >= SESSION_READY_ATTEMPTS) return response;
|
|
1153
|
+
if (record(await response.clone().json().catch(() => void 0))?.error !== "Session selection is not ready.") return response;
|
|
1154
|
+
await new Promise((resolve) => setTimeout(resolve, SESSION_READY_RETRY_MS));
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1084
1157
|
const publish = (scope, state) => {
|
|
1085
1158
|
if (state.phase === "active" || state.phase === "activating" || state.phase === "stopping") activeSessionId = scope.sessionId;
|
|
1086
1159
|
else if (activeSessionId === scope.sessionId) {
|
|
@@ -1350,12 +1423,22 @@ const serverPlugin = (0, _agimon_ai_po_core_serverPlugin.defineServerPlugin)({
|
|
|
1350
1423
|
name: "@agimon-ai/po-computer-use",
|
|
1351
1424
|
providerOverrides: (0, _agimon_ai_po_core_serverPlugin.composeServerProviderOverrides)(root_server_default),
|
|
1352
1425
|
injects: (0, _agimon_ai_po_core_extensionFile.composeRootInjects)({ session: [root_server_default] }),
|
|
1353
|
-
global: () => ({
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1426
|
+
global: (context) => ({
|
|
1427
|
+
get api() {
|
|
1428
|
+
return [at(route_server_default$1, context)];
|
|
1429
|
+
},
|
|
1430
|
+
get channels() {
|
|
1431
|
+
return [() => via({ frameType: "computer_use" }, computer_use_server_default$2())];
|
|
1432
|
+
}
|
|
1433
|
+
}),
|
|
1434
|
+
workspace: (context) => ({
|
|
1435
|
+
get api() {
|
|
1436
|
+
return [at(route_server_default$1, context)];
|
|
1437
|
+
},
|
|
1438
|
+
get channels() {
|
|
1439
|
+
return defined([context.hosted("global") ? void 0 : () => via({ frameType: "computer_use" }, computer_use_server_default$2())]);
|
|
1440
|
+
}
|
|
1441
|
+
}),
|
|
1359
1442
|
session: async (context) => {
|
|
1360
1443
|
const scopeSession = await context.scopeRoot("session", root_server_default, context);
|
|
1361
1444
|
const contextSession = {
|
|
@@ -1365,7 +1448,7 @@ const serverPlugin = (0, _agimon_ai_po_core_serverPlugin.defineServerPlugin)({
|
|
|
1365
1448
|
return {
|
|
1366
1449
|
...(0, _agimon_ai_po_core_extensionFile.composeRootHooks)(scopeSession),
|
|
1367
1450
|
get api() {
|
|
1368
|
-
return defined([at(route_server_default, contextSession)]);
|
|
1451
|
+
return defined([at(route_server_default$1, context), at(route_server_default, contextSession)]);
|
|
1369
1452
|
},
|
|
1370
1453
|
get channels() {
|
|
1371
1454
|
return defined([context.hosted("global") ? void 0 : () => via({ frameType: "computer_use" }, computer_use_server_default$2())]);
|