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
4 changes: 4 additions & 0 deletions examples/rsc-agent-runtime/rstest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
16 changes: 10 additions & 6 deletions examples/rsc-agent-runtime/tests/dev-provider.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
14 changes: 8 additions & 6 deletions packages/agent-bundle/tests/hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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',
Expand Down
7 changes: 3 additions & 4 deletions packages/workbench/tests/runtime-playground.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
Loading