Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Expand All @@ -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.
Expand Down
27 changes: 0 additions & 27 deletions packages/platform-apple/src/gesture-facts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 from inside `core/capabilities.ts`. 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,
Expand Down Expand Up @@ -56,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;
Expand All @@ -87,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 =
Expand All @@ -97,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';
}
1 change: 0 additions & 1 deletion src/__tests__/eager-closure-budgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,6 @@ export const HUB_BUDGETS: Readonly<Record<string, number>> = 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,
Expand Down
6 changes: 4 additions & 2 deletions src/cli-schema/command-schema-guards.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
22 changes: 0 additions & 22 deletions src/core/capabilities.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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');
Expand Down
21 changes: 21 additions & 0 deletions src/core/command-descriptor/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, CommandDescriptor> = new Map(
commandDescriptors.map((descriptor) => [descriptor.name, descriptor]),
);
Expand Down
5 changes: 4 additions & 1 deletion src/daemon/handlers/session-inventory.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
Loading