mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
2ec4e91b11
* refactor(core): move the command descriptor registry into its own package `src/core/command-descriptor/`, `src/command-catalog.ts`, `src/core/wait-positionals.ts` and `src/core/parse-timeout.ts` move as git renames into a new private package `@agent-device/command-registry` (deps: contracts, selectors). One subpath per module points straight at the moved file; no `index.ts`, no re-export at the old path. Every consumer switches to the owning specifier. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz * test(host-kit): pin the command-registry package inside the daemon code graph The daemon reaches the registry and its catalog only by workspace specifier. A walk that stopped at the package boundary would report an unchanged signature after a descriptor edit, and the client would keep reusing a daemon running the superseded policy. The manifest is asserted beside the sources because its `exports` map is what chose them. The cache doc comment quoting the old ~800-module graph is corrected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz * chore(gates): point the descriptor-registry gates at the package path R66's `COMMAND_DESCRIPTOR_MODULE`, R16's record-runtime join subject and the Fallow `AssertTrue` totality-guard key follow the registry to its package. The two descriptor hubs leave `HUB_ENTRY_FILES` because the package manifest now publishes them, so the eager-closure gate discovers them as facades and one entry gets one rule; this also flips `denyPlatformImplementations` from false (hub) to true (package entry) for both, which is intentional and stricter. `command-registry` joins the ranked spine at rank 1. No `APPROVED_OVER_CEILING` row: rename detection carries every moved entry's merge-base baseline, so all twelve fall under the no-growth rule rather than a ceiling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jqfa11D8QsCMuL17SsLvDz --------- Co-authored-by: Claude <noreply@anthropic.com>
147 lines
4.8 KiB
TypeScript
147 lines
4.8 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
import { runtimeExecutionIntegrityViolations } from './runtime-execution-policy.ts';
|
|
|
|
const REGISTRY = 'packages/command-registry/src/registry.ts';
|
|
const ADMISSION = 'src/daemon/runtime-admission.ts';
|
|
|
|
function sources(entries: readonly (readonly [string, string])[]): ReadonlyMap<string, string> {
|
|
return new Map(entries);
|
|
}
|
|
|
|
function admission(body: string): string {
|
|
return `
|
|
function requireFactsInspection(value) { return value; }
|
|
function requireDeviceBinding(value) { return value; }
|
|
export async function admitRuntimeOperations(request) {
|
|
${body}
|
|
}
|
|
`;
|
|
}
|
|
|
|
function messages(entries: readonly (readonly [string, string])[]): string[] {
|
|
return runtimeExecutionIntegrityViolations(sources(entries)).map(({ message }) => message);
|
|
}
|
|
|
|
test('the permanent runtime policy accepts facts-only admission and typed operation access', () => {
|
|
assert.deepEqual(
|
|
messages([
|
|
[REGISTRY, `const descriptor = { name: 'focus', platformExecution: { kind: 'none' } };`],
|
|
[
|
|
ADMISSION,
|
|
admission(`
|
|
const inspect = requireFactsInspection(request.inspectFacts);
|
|
const bind = requireDeviceBinding(request.bindDevice);
|
|
return { inspect, bind };
|
|
`),
|
|
],
|
|
[
|
|
'src/daemon/handler.ts',
|
|
`async function run(runtime) { return runtime.operations.focusPoint(input); }`,
|
|
],
|
|
]),
|
|
[],
|
|
);
|
|
});
|
|
|
|
test('a descriptor capability bucket and legacy admission call are rejected globally', () => {
|
|
const found = messages([
|
|
[
|
|
REGISTRY,
|
|
`const descriptor = { name: 'focus', capability: { apple: {} }, platformExecution: { kind: 'none' } };`,
|
|
],
|
|
[
|
|
ADMISSION,
|
|
admission(
|
|
`requireFactsInspection(request.inspectFacts); requireDeviceBinding(request.bindDevice);`,
|
|
),
|
|
],
|
|
['src/daemon/planted.ts', `requireCommandSupported('focus', device);`],
|
|
]);
|
|
assert.deepEqual(found, [
|
|
'command descriptors may not restore capability-bucket admission',
|
|
'runtime facts are the only device-command admission authority',
|
|
]);
|
|
});
|
|
|
|
test('daemon code cannot cast, assert, or bracket its way around runtime narrowing', () => {
|
|
const found = messages([
|
|
[REGISTRY, `const descriptor = { platformExecution: { kind: 'none' } };`],
|
|
[
|
|
ADMISSION,
|
|
admission(
|
|
`requireFactsInspection(request.inspectFacts); requireDeviceBinding(request.bindDevice);`,
|
|
),
|
|
],
|
|
[
|
|
'src/daemon/planted.ts',
|
|
`
|
|
const forged = value as BoundDeviceRuntime<typeof use>;
|
|
runtime.operations.focusPoint!;
|
|
runtime.operations['focusPoint'](input);
|
|
runtime.operations['focus' + 'Point'](input);
|
|
runtime['operations'].focusPoint!;
|
|
`,
|
|
],
|
|
]);
|
|
assert.deepEqual(found, [
|
|
'daemon code may not manufacture a narrowed runtime proof',
|
|
'daemon code may not repair a missing runtime operation with !',
|
|
'daemon code must consume narrowed runtime operations through named properties',
|
|
'daemon code must consume narrowed runtime operations through named properties',
|
|
'daemon code may not repair a missing runtime operation with !',
|
|
]);
|
|
});
|
|
|
|
test('dynamic operation iteration used by admission remains legal', () => {
|
|
assert.deepEqual(
|
|
messages([
|
|
[REGISTRY, `const descriptor = { platformExecution: { kind: 'none' } };`],
|
|
[
|
|
ADMISSION,
|
|
admission(
|
|
`requireFactsInspection(request.inspectFacts); requireDeviceBinding(request.bindDevice);`,
|
|
),
|
|
],
|
|
['src/daemon/planted.ts', `const fact = facts.operations[operation];`],
|
|
]),
|
|
[],
|
|
);
|
|
});
|
|
|
|
test('shared admission must inspect facts and expose binding exactly once', () => {
|
|
const found = messages([
|
|
[REGISTRY, `const descriptor = { platformExecution: { kind: 'none' } };`],
|
|
[
|
|
ADMISSION,
|
|
admission(`
|
|
requireFactsInspection(request.inspectFacts);
|
|
requireFactsInspection(request.inspectFacts);
|
|
return request.bindDevice;
|
|
`),
|
|
],
|
|
]);
|
|
assert.deepEqual(found, [
|
|
'shared runtime admission must make one facts inspection call (found 2)',
|
|
'shared runtime admission must make one binding call (found 0)',
|
|
]);
|
|
});
|
|
|
|
test('shared admission cannot hide an additional inspection behind an alias', () => {
|
|
const found = messages([
|
|
[REGISTRY, `const descriptor = { platformExecution: { kind: 'none' } };`],
|
|
[
|
|
ADMISSION,
|
|
admission(`
|
|
requireFactsInspection(request.inspectFacts);
|
|
const inspectAgain = requireFactsInspection;
|
|
inspectAgain(request.inspectFacts);
|
|
requireDeviceBinding(request.bindDevice);
|
|
`),
|
|
],
|
|
]);
|
|
assert.deepEqual(found, [
|
|
'shared runtime admission must call requireFactsInspection directly without aliasing it',
|
|
]);
|
|
});
|