diff --git a/examples/rsc-agent-runtime/rstest.config.ts b/examples/rsc-agent-runtime/rstest.config.ts index 9f7777633..ee62079f1 100644 --- a/examples/rsc-agent-runtime/rstest.config.ts +++ b/examples/rsc-agent-runtime/rstest.config.ts @@ -3,6 +3,10 @@ import { defineConfig } from '@rstest/core'; import { timeScale } from './tests/support/time-scale.ts'; export default defineConfig({ + // Route-unit proofs need the framework-generated configuration + // (rstest.route-unit.config.ts via `pnpm test:routes`), so they are not + // swept into this plain Node pool where no test manifest is registered. + exclude: ['tests/route-unit/**'], include: ['tests/**/*.test.{ts,tsx}'], pool: { maxWorkers: 1 }, testEnvironment: 'node', diff --git a/examples/rsc-agent-runtime/tests/dev-provider.integration.test.ts b/examples/rsc-agent-runtime/tests/dev-provider.integration.test.ts index eda04178e..e9c2b2f9a 100644 --- a/examples/rsc-agent-runtime/tests/dev-provider.integration.test.ts +++ b/examples/rsc-agent-runtime/tests/dev-provider.integration.test.ts @@ -375,12 +375,16 @@ test('declares an optional runtime while keeping Claude and Codex artifacts buil provider: './src/dev/provider.ts', servers: [expect.objectContaining({ name: 'timeline', transport: 'stdio' })], }); - // One prebuilt hook declaration per host, each carrying its own `--host` - // argument. - expect(prepared.model?.hooks).toEqual(expect.arrayContaining([ - expect.objectContaining({ prebuiltPath: 'runtime/hook/index.js', targets: ['claude'] }), - expect.objectContaining({ prebuiltPath: 'runtime/hook/index.js', targets: ['codex'] }), - ])); + // The example declares one semantic event route (src/events/tool/after.tsx) + // that serves both hosts through the generated native wrappers. + expect(prepared.model?.hooks).toEqual([ + expect.objectContaining({ + event: 'afterTool', + eventRoute: expect.objectContaining({ event: 'tool/after' }), + id: 'hook:event-route:tool-after', + targets: ['claude', 'codex'], + }), + ]); const artifact = await new ArtifactService({ epochStore: new EpochStore({ projectRoot: root }) }).build(prepared); if (artifact.outcome !== 'succeeded') throw new Error(JSON.stringify(artifact.diagnostics)); diff --git a/packages/agent-bundle/tests/hooks.test.ts b/packages/agent-bundle/tests/hooks.test.ts index 11f5151e0..b1356b9a1 100644 --- a/packages/agent-bundle/tests/hooks.test.ts +++ b/packages/agent-bundle/tests/hooks.test.ts @@ -1306,13 +1306,15 @@ it('normalizes a mixed hook fixture and reports malformed hook declarations', as targets: hook.targets, timeout: hook.timeout, tools: hook.tools, + // Normalization orders hooks by their stable id, not by declaration + // order, so mixed configured and conventional hooks emit deterministically. }))).toEqual([ { - event: 'sessionStart', - name: 'session-start-session-start-7ab7e8a5', + event: 'afterTool', + name: 'after-tool-record-87785f02', targets: ['claude', 'codex'], timeout: undefined, - tools: [], + tools: ['file.write', 'shell'], }, { event: 'beforeTool', @@ -1329,11 +1331,11 @@ it('normalizes a mixed hook fixture and reports malformed hook declarations', as tools: ['shell'], }, { - event: 'afterTool', - name: 'after-tool-record-87785f02', + event: 'sessionStart', + name: 'session-start-session-start-7ab7e8a5', targets: ['claude', 'codex'], timeout: undefined, - tools: ['file.write', 'shell'], + tools: [], }, { event: 'stop', diff --git a/packages/workbench/tests/runtime-playground.e2e.test.ts b/packages/workbench/tests/runtime-playground.e2e.test.ts index 3dcfa39fb..d042897df 100644 --- a/packages/workbench/tests/runtime-playground.e2e.test.ts +++ b/packages/workbench/tests/runtime-playground.e2e.test.ts @@ -35,10 +35,9 @@ e2e('renders the capability-gated Runtime sibling in the real RSC workbench', { await expect(page.getByRole('link', { name: 'Inspector' })).toHaveCount(0, { timeout: browserTimeout }); await expect(page.getByRole('link', { name: 'Runtime' })).toBeVisible({ timeout: browserTimeout }); - // The example's hooks are prebuilt payload commands packaged like native - // hooks, so no simulatable hook wrappers exist and the Hooks and - // Playground capability pages stay hidden alongside them. - await expect(page.getByRole('link', { name: 'Hooks' })).toHaveCount(0, { timeout: browserTimeout }); + // The example declares a semantic event route rendered through generated + // native wrappers, so the simulatable Hooks capability page is available. + await expect(page.getByRole('link', { exact: true, name: 'Hooks' })).toBeVisible({ timeout: browserTimeout }); for (const sibling of ['artifacts', 'logs'] as const) { await page.goto(workbenchUrl(fixture.url, sibling)); await expect(page.locator(`#${sibling}`)).toBeVisible({ timeout: browserTimeout });