Skip to content

Commit bce8291

Browse files
fix: green main after #656/#664 — ignore package-build compile staging in dev, update superseded test contracts
1 parent 7e56517 commit bce8291

4 files changed

Lines changed: 27 additions & 24 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"agent-bundle": patch
3+
---
4+
5+
Fix `agent-bundle dev` republishing a fresh epoch after every npm-root package build: the package build's compile staging directory now uses the `.<output>.stage-` name the source watcher already ignores, so a project with a `bin` or `lib` no longer sees a spurious rebuild (and a lost operator `.env` layer) seconds after each publish (#666)

‎packages/agent-bundle/src/build/package-build.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,11 @@ export const buildPackageOutputs = async (options: {
388388

389389
const stageParent = dirname(outputRoot);
390390
await mkdir(stageParent, { recursive: true });
391+
// Both share the `.<output>.stage-` prefix the dev watcher treats as build
392+
// output (`dev/watcher.ts` `isOutputStagingPath`); any other sibling name
393+
// invalidates the epoch the package build just followed.
391394
const stageRoot = await mkdtemp(join(stageParent, `.${basename(outputRoot)}.stage-`));
392-
const compileRoot = await mkdtemp(join(stageParent, `.${basename(outputRoot)}.compile-`));
395+
const compileRoot = await mkdtemp(join(stageParent, `.${basename(outputRoot)}.stage-`));
393396
try {
394397
const ignoredRuntimeRoots = Object.freeze([...new Set([
395398
...(entries.some((entry) => entry.aliases?.[terminalCapabilityRuntimeSpecifier] !== undefined)

‎packages/agent-bundle/tests/prepack.test.ts‎

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -427,14 +427,16 @@ it('reports git, GitHub-shorthand, remote-tarball, and path dependency specifier
427427
};
428428
},
429429
async () => {
430-
await mkdir(join(projectRoot, 'vendor', 'vendored'), { recursive: true });
431-
await mkdir(join(projectRoot, 'vendor', 'bad-manifest'), { recursive: true });
430+
// `file:` sources resolve inside the packed npm root (`dist`), not the project.
431+
const vendor = join(projectRoot, 'dist', 'vendor');
432+
await mkdir(join(vendor, 'vendored'), { recursive: true });
433+
await mkdir(join(vendor, 'bad-manifest'), { recursive: true });
432434
await Promise.all([
433-
writeFile(join(projectRoot, 'vendor', 'vendored', 'package.json'), '{ "name": "vendored", "version": "1.0.0" }\n'),
434-
writeFile(join(projectRoot, 'vendor', 'bad-manifest', 'package.json'), '{\n'),
435-
writeFile(join(projectRoot, 'vendor', 'tarred.tgz'), packageTarball('{ "name": "tarred", "version": "1.0.0" }')),
436-
writeFile(join(projectRoot, 'vendor', 'bad-tarred-manifest.tgz'), packageTarball('not json\n')),
437-
writeFile(join(projectRoot, 'vendor', 'not-archive.tgz'), 'not a tarball\n'),
435+
writeFile(join(vendor, 'vendored', 'package.json'), '{ "name": "vendored", "version": "1.0.0" }\n'),
436+
writeFile(join(vendor, 'bad-manifest', 'package.json'), '{\n'),
437+
writeFile(join(vendor, 'tarred.tgz'), packageTarball('{ "name": "tarred", "version": "1.0.0" }')),
438+
writeFile(join(vendor, 'bad-tarred-manifest.tgz'), packageTarball('not json\n')),
439+
writeFile(join(vendor, 'not-archive.tgz'), 'not a tarball\n'),
438440
]);
439441
const pack = { ...result.pack, files: [...result.pack.files,
440442
{ path: 'node_modules/embedded/package.json' },
@@ -466,7 +468,7 @@ it('reports git, GitHub-shorthand, remote-tarball, and path dependency specifier
466468
for (const name of ['alias', 'tilde', 'versioned', 'embedded', 'vendored', 'tarred']) {
467469
expect(reported[0]?.message).not.toContain(JSON.stringify(name));
468470
}
469-
await rm(join(projectRoot, 'vendor'), { force: true, recursive: true });
471+
await rm(vendor, { force: true, recursive: true });
470472
expect(reported[0]?.recovery).toContain('registry');
471473

472474
const underPnpm = withCode(await diagnostics(pack, true), 'AB7015');
@@ -600,20 +602,13 @@ it('reads an installed manifest as npm does, so the last of duplicate name keys
600602
it('prepack succeeds and surfaces the warning when the only finding is an unresolvable optional dependency', () => withPackageDocument(
601603
(document) => {
602604
document.optionalDependencies = { 'optional-native': 'github:owner/optional-native' };
603-
// The build rewrites dist, so the packed declaration that references the optional package lives in its own
604-
// packed directory; an install script running it instead would make the failed fetch fatal.
605-
document.files = [...(document.files as readonly string[]), 'extras'];
605+
// The generated npm root carries only emitted files, so the evidence that keeps the optional package out of
606+
// AB7014 is a consumer install script that mentions it; one that ran it would make the failed fetch fatal.
607+
document.scripts = { ...(document.scripts as Record<string, string> | undefined), postinstall: 'echo optional-native' };
606608
},
607609
async () => {
608-
const extras = join(projectRoot, 'extras');
609-
await mkdir(extras, { recursive: true });
610-
await writeFile(join(extras, 'optional.d.ts'), 'export type { Native } from "optional-native";\n');
611-
try {
612-
const packed = await prepack({ root: projectRoot });
613-
expect(packed.diagnostics.map((diagnostic) => [diagnostic.code, diagnostic.severity])).toEqual([['AB7015', 'warning']]);
614-
} finally {
615-
await rm(extras, { force: true, recursive: true });
616-
}
610+
const packed = await prepack({ root: projectRoot });
611+
expect(packed.diagnostics.map((diagnostic) => [diagnostic.code, diagnostic.severity])).toEqual([['AB7015', 'warning']]);
617612
},
618613
));
619614

@@ -638,7 +633,7 @@ it('accepts a dependency that only packed declaration files reference, including
638633
// A `#` specifier reaches the package the imports map names.
639634
await writeFile(modern, 'export type { Driver } from "#driver";\n');
640635
try {
641-
const pack = { ...result.pack, files: [...result.pack.files, { path: 'dist/consumer.d.ts' }, { path: 'dist/driver.d.mts' }] };
636+
const pack = { ...result.pack, files: [...result.pack.files, { path: 'consumer.d.ts' }, { path: 'driver.d.mts' }] };
642637
const [reported] = withCode(await diagnostics(pack), 'AB7014');
643638
expect(reported?.message).toContain('"never-loaded"');
644639
for (const name of ['zod', '@types/node', 'driver-package']) expect(reported?.message).not.toContain(JSON.stringify(name));

‎packages/agent-bundle/tests/route-register-typegen.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,8 @@ it('types every route-aware public surface from the generated route registration
172172
"export type FindResult = Assert<Equal<RegisteredRouteResult<'tool:curator/find'>, { hits: number }>>;",
173173
"export type Unregistered = Assert<Equal<RegisteredRouteInput<'tool:curator/missing'>, unknown>>;",
174174
'// An event route registers the harness payload — the component props without the `signal` the harness',
175-
'// injects — and no result, since event modules export no resultSchema.',
176-
"export type EventInput = Assert<Equal<keyof RegisteredRouteInput<'event:tool/after'>, 'canonical' | 'native'>>;",
175+
'// injects, including the optional preflight `data` (#661) — and no result, since event modules export no resultSchema.',
176+
"export type EventInput = Assert<Equal<keyof RegisteredRouteInput<'event:tool/after'>, 'canonical' | 'native' | 'preflight'>>;",
177177
"export type EventCanonical = Assert<Equal<RegisteredRouteInput<'event:tool/after'>['canonical'], AgentEventCanonicalIdentity<'tool/after'>>>;",
178178
'// The route\'s family narrows `canonical.payload`: tool/after fields are present, stop-only fields are not.',
179179
"export type EventPayload = Assert<Equal<RegisteredRouteInput<'event:tool/after'>['canonical']['payload'], AgentEventPayload<'tool/after'>>>;",

0 commit comments

Comments
 (0)