mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 10:37:35 +00:00
feat(runtime): let a paired desktop register its phones as phone devices (#26427)
* feat(runtime): let a paired desktop register its phones as delegated mobile devices A desktop paired to this runtime can now call pairing.delegatedMobileDevice.sync to make each of its phones an ordinary mobile-scope device it owns, so the phone mirrors that host through the desktop. Children are never pending, inherit the parent's reach, and die with the parent's grant. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * refactor(runtime): move the mobile device revoke primitive below dispatch Dispatch binds the caller-bound delegated-device context, so the revoke path it needs now lives in a layer under it as a pure move; this drops the abstract method seam. No behaviour change. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(runtime): keep a runtime grant until its delegated phones are revoked A failed child cleanup now leaves the parent in place so a retry can still find the children, and revokeRuntimeAccess lives beside the revoke it cascades to. Adds restart, rename and bounds coverage, shares credential minting, and drops the timing-dependent census. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(runtime): fail a delegated sync whose dropped phone cannot be revoked Matches the parent revoke: a child whose cleanup could not be saved is kept and the sync errors before minting anything, so the desktop retries instead of believing the server matches its list. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(runtime): refuse pairing admin to phones delegated through a paired desktop A delegated child phone could call the mobile-allowlisted pairing-admin methods (push registration, relay provisioning) that its parent desktop is never granted. The caller scope now marks delegated phones and denies them that permission. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
import { z } from 'zod'
|
||||
import type { RUNTIME_CAPABILITIES } from './protocol-version'
|
||||
|
||||
// Why: a paired desktop relays each of its phones to this host as an ordinary phone device it owns.
|
||||
export const DELEGATED_MOBILE_DEVICE_SYNC_METHOD = 'pairing.delegatedMobileDevice.sync'
|
||||
// Why: a desktop relays phones only to a host advertising this; `satisfies` ties it to RUNTIME_CAPABILITIES.
|
||||
export const DELEGATED_MOBILE_DEVICES_RUNTIME_CAPABILITY =
|
||||
'pairing.delegated-mobile-devices.v1' satisfies (typeof RUNTIME_CAPABILITIES)[number]
|
||||
export const DELEGATED_MOBILE_DEVICE_SYNC_MAX_PHONES = 32
|
||||
|
||||
const DelegatedPhoneSchema = z
|
||||
.object({
|
||||
phoneKey: z.string().min(1).max(128),
|
||||
name: z.string().min(1).max(128)
|
||||
})
|
||||
.strict()
|
||||
|
||||
export const DelegatedMobileDeviceSyncParamsSchema = z
|
||||
.object({
|
||||
phones: z
|
||||
.array(DelegatedPhoneSchema)
|
||||
.max(DELEGATED_MOBILE_DEVICE_SYNC_MAX_PHONES)
|
||||
.refine((phones) => new Set(phones.map((phone) => phone.phoneKey)).size === phones.length, {
|
||||
message: 'duplicate phoneKey'
|
||||
})
|
||||
})
|
||||
.strict()
|
||||
|
||||
export type DelegatedPhone = z.infer<typeof DelegatedPhoneSchema>
|
||||
export type DelegatedMobileDeviceSyncParams = z.infer<typeof DelegatedMobileDeviceSyncParamsSchema>
|
||||
|
||||
export type DelegatedMobileDeviceSyncResult = {
|
||||
devices: { phoneKey: string; deviceId: string; token: string }[]
|
||||
}
|
||||
@@ -436,6 +436,7 @@ export const RUNTIME_CAPABILITIES = [
|
||||
...SKILL_RUNTIME_CAPABILITIES,
|
||||
...AUTOMATION_RUNTIME_CAPABILITIES,
|
||||
NOTIFICATIONS_REMOTE_PUSH_RUNTIME_CAPABILITY,
|
||||
'pairing.delegated-mobile-devices.v1',
|
||||
PREFLIGHT_WORKSPACE_SCOPED_RUNTIME_CAPABILITY,
|
||||
PREFLIGHT_OTHER_RUNTIME_REFUSAL_RUNTIME_CAPABILITY,
|
||||
WORKSPACE_PORTS_HOST_SCOPED_RUNTIME_CAPABILITY,
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
BrowserNetworkTunnelAttachParams
|
||||
} from '../browser-client-host-protocol'
|
||||
import { BrowserClientPageMetadataParams } from '../browser-client-page-metadata-protocol'
|
||||
import { DelegatedMobileDeviceSyncParamsSchema } from '../delegated-mobile-device-contract'
|
||||
import {
|
||||
PairingGetEndpointsParamsSchema,
|
||||
PairingProvisionRelayParamsSchema
|
||||
@@ -1109,6 +1110,7 @@ export const RPC_PARAMS_BY_METHOD = {
|
||||
'orchestration.workerStart': WorkerStartParams,
|
||||
'orchestration.workerStop': WorkerDispatchParamsOfOrchestrationWorkerStopParams,
|
||||
'orchestration.workerTerminalUserInput': OrchestrationWorkerTerminalUserInputParams,
|
||||
'pairing.delegatedMobileDevice.sync': DelegatedMobileDeviceSyncParamsSchema,
|
||||
'pairing.getEndpoints': PairingGetEndpointsParamsSchema,
|
||||
'pairing.provisionRelay': PairingProvisionRelayParamsSchema,
|
||||
'plugins.consent': pluginConsentRequestSchema,
|
||||
|
||||
Reference in New Issue
Block a user