@agimon-ai/po-computer-use 0.0.0-alpha.25 → 0.0.0-alpha.27

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.
@@ -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) => host.requestSessionApi(scope, {
1079
- basePath: API_BASE_PATH,
1080
- path,
1081
- method,
1082
- ...value === void 0 ? {} : { body: JSON.stringify(value) }
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: () => ({ get channels() {
1354
- return [() => via({ frameType: "computer_use" }, computer_use_server_default$2())];
1355
- } }),
1356
- workspace: (context) => ({ get channels() {
1357
- return defined([context.hosted("global") ? void 0 : () => via({ frameType: "computer_use" }, computer_use_server_default$2())]);
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())]);