Skip to content

Commit 7dbfacf

Browse files
fix(test): honest registry version gate, binary-faithful CLI cwd, README field (#206)
Post-merge review findings from #190: bump AGENT_TEST_REGISTRY_VERSION to 2 so registries missing the required cliCommands/plugin manifest fields fail the existing version gate with a recoverable AgentTestError instead of crashing inside invokeCli or the MCP helpers; derive the invokeCli request workspace from process.cwd() to match the generated executable's semantics instead of manifest.projectRoot; correct the README example to read call.structuredContent (the McpToolInvocation field) rather than call.result.
1 parent 079a77d commit 7dbfacf

6 files changed

Lines changed: 57 additions & 3 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"agent-bundle": patch
3+
---
4+
5+
Reject stale consumer test registries before projection helpers read fields
6+
they do not contain, and derive CLI dispatch workspace context from the
7+
invocation working directory to match generated executables.

‎packages/agent-bundle/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ import { cliJson, expectEvents, invokeCli, invokeMcpTool } from 'agent-bundle/te
252252

253253
// mcp-in-memory: the generated server projects the document to protocol content.
254254
const call = await invokeMcpTool('summarize', { input: { title: 'Dune' } });
255-
expect(call.result.structuredContent).toEqual({ chapters: 24 });
255+
expect(call.structuredContent).toEqual({ chapters: 24 });
256256

257257
// cli-dispatch: the routed CLI resolves the command, parses argv, and maps the exit code.
258258
const run = await invokeCli(['library', 'audit', './books', '--max-files', '8']);

‎packages/agent-bundle/src/test/cli.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export const invokeCli = async (
181181
} catch (error) {
182182
throw new CliInputError(error instanceof Error ? error.message : String(error));
183183
}
184-
const root = manifest.projectRoot;
184+
const root = process.cwd();
185185
const result = await runtime.runAgentRequest({
186186
capabilities: {
187187
command: runtime.unavailable(),

‎packages/agent-bundle/src/test/registry.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const AGENT_TEST_REGISTRY_SYMBOL_KEY = 'agent-bundle/test-route-registry'
1414

1515
const REGISTRY_SYMBOL = Symbol.for(AGENT_TEST_REGISTRY_SYMBOL_KEY);
1616

17-
export const AGENT_TEST_REGISTRY_VERSION = 1;
17+
export const AGENT_TEST_REGISTRY_VERSION = 2;
1818

1919
export interface AgentTestRouteRegistry {
2020
/** Lazy loaders keyed by compiled route id, so a test only compiles the routes it renders. */

‎packages/agent-bundle/tests/projection/cli-dispatch.test.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, expect, it } from '@rstest/core';
22

3+
import { agent } from '@agent-bundle/runtime';
34
import { cliJson, invokeCli } from '../../src/test/cli.ts';
45

56
/**
@@ -84,4 +85,27 @@ describe('the CLI dispatch level', () => {
8485
expect(run.exitCode).toBe(0);
8586
expect(progress.map((update) => update.message)).toEqual(['reading inventory', 'inventory ready']);
8687
});
88+
89+
it('derives the request workspace from the invocation cwd like the generated binary', async () => {
90+
const invocationCwd = process.cwd();
91+
let observed: { readonly projectRoot: string | null; readonly workspace: string | null } | undefined;
92+
const run = await invokeCli(['inventory', 'fiction'], {
93+
context: {
94+
progress: {
95+
report: async () => {
96+
const context = await agent();
97+
observed = {
98+
projectRoot: context.capabilities.projectRoot.state === 'available'
99+
? context.capabilities.projectRoot.value.root
100+
: null,
101+
workspace: context.workspace.state === 'available' ? context.workspace.value.root : null,
102+
};
103+
},
104+
},
105+
},
106+
});
107+
108+
expect(invocationCwd).not.toBe(run.provenance.projectRoot);
109+
expect(observed).toEqual({ projectRoot: invocationCwd, workspace: invocationCwd });
110+
});
87111
});

‎packages/agent-bundle/tests/test-harness-manifest.test.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { describe, expect, it } from '@rstest/core';
55

66
import { routeTestSetupSource } from '../src/rstest/setup-module.ts';
77
import { AgentTestError } from '../src/test/errors.ts';
8+
import { invokeCli } from '../src/test/cli.ts';
89
import { compileTestManifest, testManifestFromRouteGraph } from '../src/test/manifest.ts';
910
import {
1011
AGENT_TEST_REGISTRY_SYMBOL_KEY,
@@ -144,6 +145,28 @@ describe('the generated route registry', () => {
144145
expect(() => testManifest()).toThrow('Incompatible Agent Bundle test registry version');
145146
});
146147
});
148+
149+
it('refuses a version-1 manifest before a helper reads fields that version did not carry', async () => {
150+
const versionOneManifest = Object.fromEntries(
151+
Object.entries(manifest).filter(([key]) => key !== 'cliCommands' && key !== 'plugin'),
152+
);
153+
const error = await withRealmRegistry(
154+
{ loaders: {}, manifest: versionOneManifest, version: 1 },
155+
async () => invokeCli(['--help']).catch((thrown: unknown) => thrown),
156+
);
157+
158+
expect(error).toBeInstanceOf(AgentTestError);
159+
expect((error as AgentTestError).code).toBe('manifest-unavailable');
160+
expect((error as AgentTestError).message).toContain('found 1');
161+
expect((error as AgentTestError).message).toContain('Install one agent-bundle version');
162+
});
163+
164+
it('accepts a registry carrying the current manifest version', async () => {
165+
await withRealmRegistry(
166+
{ loaders: {}, manifest, version: AGENT_TEST_REGISTRY_VERSION },
167+
() => expect(testManifest()).toBe(manifest),
168+
);
169+
});
147170
});
148171

149172
describe('route loaders and the manifest that produced them', () => {

0 commit comments

Comments
 (0)