From 6da8f061deff13152d5091c302d8037066687610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 27 Aug 2026 16:44:10 +0200 Subject: [PATCH 1/3] refactor: delete capabilities projection shell --- AGENTS.md | 8 ++++--- packages/platform-apple/src/gesture-facts.ts | 2 +- src/__tests__/eager-closure-budgets.ts | 1 - src/cli-schema/command-schema-guards.test.ts | 6 +++-- src/core/capabilities.ts | 22 ------------------- .../__tests__/focus-runtime-execution.test.ts | 3 +-- src/core/command-descriptor/registry.ts | 21 ++++++++++++++++++ src/daemon/handlers/session-inventory.ts | 5 ++++- 8 files changed, 36 insertions(+), 32 deletions(-) delete mode 100644 src/core/capabilities.ts diff --git a/AGENTS.md b/AGENTS.md index 913df72262..5ec92172d5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -50,12 +50,14 @@ Versioned CLI help is the source of truth for command behavior. Start workflow p Read the declaration rather than maintaining a prose copy: -- commands and their surface, capability, batch, and timeout traits: +- commands and their surface, runtime-use, batch, and timeout traits: `src/core/command-descriptor/registry.ts` - daemon route ownership and request-policy traits: `src/daemon/daemon-command-registry.ts` - interaction paths and guarantees: `packages/contracts/src/interaction-guarantees.ts` - canonical command names: `src/command-catalog.ts` -- device capability admission: `src/core/capabilities.ts` +- device runtime-use declarations and fact admission: + `src/core/command-descriptor/registry.ts`, `src/daemon/runtime-admission.ts`, and + `src/platform-runtime-gateway.ts` - common command input fields, and which surface may write an input key (model, operator, retired): `src/commands/common-input-fields.ts` and `src/commands/input-audience.ts` @@ -72,7 +74,7 @@ cross-language rules change through golden tables under `contracts/fixtures/`. - Plain `.mjs` packaging fixtures that cannot import TypeScript execution helpers keep child-process use local and prefer `execFile`. -- Apple target changes keep the kernel device model, capability admission, dispatch resolution, +- Apple target changes keep the kernel device model, runtime-fact admission, dispatch resolution, Apple discovery, and xctestrun preparation in sync. - iOS simulator-set scoping must never hide the host macOS desktop target. - Skills may carry a minimal start/routing card; command semantics belong in versioned CLI help. diff --git a/packages/platform-apple/src/gesture-facts.ts b/packages/platform-apple/src/gesture-facts.ts index daac83f3c8..2b8cfb75ba 100644 --- a/packages/platform-apple/src/gesture-facts.ts +++ b/packages/platform-apple/src/gesture-facts.ts @@ -12,7 +12,7 @@ import { resolveDeviceAppleOs, type DeviceInfo } from '@agent-device/kernel/devi * The Apple owner's gesture-family cell table (R52/R53). * * This is admission the daemon used to own: `requireGestureSupported` decided Apple's gesture - * tiers from inside `core/capabilities.ts`. Every refusal below reproduces the exact cell — and + * tiers. Every refusal below reproduces the exact cell — and * the exact hint — that function produced, which is why the wording constants are imported rather * than restated. `runtime.ts` composes these facts; it does not decide them. */ diff --git a/src/__tests__/eager-closure-budgets.ts b/src/__tests__/eager-closure-budgets.ts index 32af307f90..b3108d9f6f 100644 --- a/src/__tests__/eager-closure-budgets.ts +++ b/src/__tests__/eager-closure-budgets.ts @@ -339,7 +339,6 @@ export const HUB_BUDGETS: Readonly> = Object.freeze({ // module records for the same code, with no new subtree behind any of them. 'src/cli.ts': 368, 'src/platform-runtime.ts': 47, - 'src/core/capabilities.ts': 68, 'src/core/command-descriptor/registry.ts': 67, 'src/core/command-descriptor/platform-execution-entry.ts': 3, 'src/core/interactors/register-builtins.ts': 6, diff --git a/src/cli-schema/command-schema-guards.test.ts b/src/cli-schema/command-schema-guards.test.ts index 237b665e4e..b52711c8dd 100644 --- a/src/cli-schema/command-schema-guards.test.ts +++ b/src/cli-schema/command-schema-guards.test.ts @@ -4,14 +4,16 @@ import fs from 'node:fs'; import { fileURLToPath } from 'node:url'; import { parseSync } from 'oxc-parser'; import type { BinaryExpression, Expression, PrivateIdentifier } from 'oxc-parser'; -import { listRuntimeFactCommands } from '../core/capabilities.ts'; import { INTERNAL_COMMANDS, isKnownCliCommandName, listCliCommandNames, SPECIAL_CLI_COMMANDS, } from '../command-catalog.ts'; -import { commandDescriptors } from '../core/command-descriptor/registry.ts'; +import { + commandDescriptors, + listRuntimeFactCommands, +} from '../core/command-descriptor/registry.ts'; import { getCliCommandSchema } from './command-schema.ts'; test('every public runtime-fact command has a parser schema entry', () => { diff --git a/src/core/capabilities.ts b/src/core/capabilities.ts deleted file mode 100644 index a003066faf..0000000000 --- a/src/core/capabilities.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { commandDescriptors } from './command-descriptor/registry.ts'; - -export function commandRuntimeUseRequirements( - command: string, -): readonly (readonly string[])[] | undefined { - const descriptor = commandDescriptors.find((candidate) => candidate.name === command); - const execution = descriptor?.platformExecution; - if (execution?.kind !== 'device-runtime') return undefined; - const uses = 'uses' in execution ? execution.uses : [execution.use]; - return uses.map((use) => use.required); -} - -export function listRuntimeFactCommands(): string[] { - return commandDescriptors - .filter( - (descriptor) => - descriptor.catalog.group === 'public' && - descriptor.platformExecution.kind === 'device-runtime', - ) - .map((descriptor) => descriptor.name) - .sort(); -} diff --git a/src/core/command-descriptor/__tests__/focus-runtime-execution.test.ts b/src/core/command-descriptor/__tests__/focus-runtime-execution.test.ts index 3f92a4815a..a5473a2aff 100644 --- a/src/core/command-descriptor/__tests__/focus-runtime-execution.test.ts +++ b/src/core/command-descriptor/__tests__/focus-runtime-execution.test.ts @@ -1,7 +1,6 @@ import { expect, test } from 'vitest'; import { focusRuntimeUse } from '@agent-device/contracts/platform-runtime-operations'; -import { commandDescriptors } from '../registry.ts'; -import { listRuntimeFactCommands } from '../../capabilities.ts'; +import { commandDescriptors, listRuntimeFactCommands } from '../registry.ts'; test('focus descriptor declares its complete runtime use with no legacy projection', () => { const focus = commandDescriptors.find(({ name }) => name === 'focus'); diff --git a/src/core/command-descriptor/registry.ts b/src/core/command-descriptor/registry.ts index 1ce719902e..c86dd28b00 100644 --- a/src/core/command-descriptor/registry.ts +++ b/src/core/command-descriptor/registry.ts @@ -1635,6 +1635,27 @@ export function listMcpExposedCommandNames(): DescriptorCliCommandName[] { .sort(); } +export function commandRuntimeUseRequirements( + command: string, +): readonly (readonly string[])[] | undefined { + const descriptor = commandDescriptors.find((candidate) => candidate.name === command); + const execution = descriptor?.platformExecution; + if (execution?.kind !== 'device-runtime') return undefined; + const uses = 'uses' in execution ? execution.uses : [execution.use]; + return uses.map((use) => use.required); +} + +export function listRuntimeFactCommands(): string[] { + return commandDescriptors + .filter( + (descriptor) => + descriptor.catalog.group === 'public' && + descriptor.platformExecution.kind === 'device-runtime', + ) + .map((descriptor) => descriptor.name) + .sort(); +} + const COMMAND_DESCRIPTOR_BY_NAME: ReadonlyMap = new Map( commandDescriptors.map((descriptor) => [descriptor.name, descriptor]), ); diff --git a/src/daemon/handlers/session-inventory.ts b/src/daemon/handlers/session-inventory.ts index 67c99444d6..6def4d9682 100644 --- a/src/daemon/handlers/session-inventory.ts +++ b/src/daemon/handlers/session-inventory.ts @@ -1,4 +1,7 @@ -import { commandRuntimeUseRequirements, listRuntimeFactCommands } from '../../core/capabilities.ts'; +import { + commandRuntimeUseRequirements, + listRuntimeFactCommands, +} from '../../core/command-descriptor/registry.ts'; import { listDeviceInventory } from '../../request/device-inventory-context.ts'; import { assertResolvedAppsFilter } from '@agent-device/contracts/device'; import { AppError, asAppError } from '@agent-device/kernel/errors'; From c09f4212c62f23e3736c8f2015f6966bad36de07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 27 Aug 2026 18:32:25 +0200 Subject: [PATCH 2/3] chore: remove stale gesture-facts comment --- packages/platform-apple/src/gesture-facts.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/platform-apple/src/gesture-facts.ts b/packages/platform-apple/src/gesture-facts.ts index 2b8cfb75ba..86b8526899 100644 --- a/packages/platform-apple/src/gesture-facts.ts +++ b/packages/platform-apple/src/gesture-facts.ts @@ -8,14 +8,6 @@ import type { RuntimeOperationFact } from '@agent-device/contracts/platform-runt import { scrollRuntimeOperationFacts } from '@agent-device/contracts/scroll-runtime'; import { resolveDeviceAppleOs, type DeviceInfo } from '@agent-device/kernel/device'; -/** - * The Apple owner's gesture-family cell table (R52/R53). - * - * This is admission the daemon used to own: `requireGestureSupported` decided Apple's gesture - * tiers. Every refusal below reproduces the exact cell — and - * the exact hint — that function produced, which is why the wording constants are imported rather - * than restated. `runtime.ts` composes these facts; it does not decide them. - */ const available = Object.freeze({ available: true } as const); const gestureLeafUnavailable = Object.freeze({ available: false, From 24cac913a6e0bc27ce59e75a9def0dc240ad948d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 27 Aug 2026 19:29:56 +0200 Subject: [PATCH 3/3] chore: remove gesture-facts admission narration --- packages/platform-apple/src/gesture-facts.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/packages/platform-apple/src/gesture-facts.ts b/packages/platform-apple/src/gesture-facts.ts index 86b8526899..32459e7166 100644 --- a/packages/platform-apple/src/gesture-facts.ts +++ b/packages/platform-apple/src/gesture-facts.ts @@ -48,22 +48,11 @@ export function appleGestureAndScrollFacts(device: DeviceInfo) { }; } -/** - * One-contact gesture execution. The retired admission refused watchOS with every other - * `platform === 'web'` case and refused visionOS just after the multi-touch branch, both by - * reading `device.appleOs` RAW — an Apple device that declares no OS was admitted, so this reads - * it raw too rather than resolving a default that would newly refuse. - */ function appleGesturePlanFact(device: DeviceInfo): RuntimeOperationFact { if (device.appleOs === 'watchos' || device.appleOs === 'visionos') return gestureLeafUnavailable; return appleTouchKind(device) ? available : gestureKindUnavailable; } -/** - * Two-contact synthesis, which on Apple is the iOS-simulator-only XCTest two-finger model. watchOS - * is refused with no hint because the retired admission caught it in its first branch, before the - * multi-touch policy that carries the per-OS hints ever ran. - */ function appleMultiTouchGestureFact(device: DeviceInfo): RuntimeOperationFact { if (device.appleOs === 'watchos') return gestureLeafUnavailable; if (!appleTouchKind(device)) return gestureKindUnavailable; @@ -79,7 +68,6 @@ function appleMultiTouchGestureFact(device: DeviceInfo): RuntimeOperationFact { return device.kind === 'simulator' ? available : physicalIosMultiTouchUnavailable; } -/** Target-authored drag needs source hold, timed movement, and destination hold preserved. */ function appleTargetAuthoredDragFact(device: DeviceInfo): RuntimeOperationFact { if (!appleTouchKind(device)) return gestureKindUnavailable; const supported = @@ -89,22 +77,15 @@ function appleTargetAuthoredDragFact(device: DeviceInfo): RuntimeOperationFact { return supported ? available : targetAuthoredDragUnavailable; } -/** The runner reads the frame for every Apple leaf that has one; watchOS has no runner at all. */ function appleGestureViewportFact(device: DeviceInfo): RuntimeOperationFact { if (device.appleOs === 'watchos') return gestureLeafUnavailable; return appleTouchKind(device) ? available : gestureKindUnavailable; } -/** - * `scroll` had no admission beyond its capability bucket — no plugin closure, no gesture policy — - * so its cell is the bucket verbatim, watchOS included. A watchOS scroll still fails where it - * fails today: when the Apple interactor refuses to construct, not at admission. - */ function appleScrollFact(device: DeviceInfo): RuntimeOperationFact { return appleTouchKind(device) ? available : scrollKindUnavailable; } -/** The two kinds the Apple capability bucket ever admitted. */ function appleTouchKind(device: DeviceInfo): boolean { return device.kind === 'simulator' || device.kind === 'device'; }