Problem
Plugin projects currently declare release identity in multiple places. The cargo-hauler consumer plugin is a concrete example:
package.json "version" (npm release identity)
agent-bundle.config.ts plugin.version (required config field)
src/lib/version.ts — a hand-written export const packageVersion = '…' because runtime code (daemon status, CLI, MCP application registry) and browser widget bundles need an importable version constant and cannot read package.json at runtime
The plugin also carries a version-consistency test that asserts all three agree — slop the framework forces authors to maintain until release identity has one source and compiled surfaces get the value automatically.
Current framework behavior (evidence)
Config plugin.version is still required
The public config type requires a version string:
// packages/agent-bundle/src/core/types.ts
export interface AgentBundlePluginConfig {
description?: string;
name: string;
version: string;
[key: string]: unknown;
}
Source validation rejects missing/empty values with AB4001:
// packages/agent-bundle/src/config/validate.ts
if (typeof pluginVersion !== 'string' || pluginVersion.trim().length === 0) {
diagnostics.push(
sourceDiagnostic(
'AB4001',
'Plugin metadata must define a nonempty version.',
loaded.configPath,
),
);
}
Normalization still copies the authored config value into model metadata; it does not infer from package.json when omitted:
// packages/agent-bundle/src/config/normalize.ts
// package.json is authoritative for release identity (issue #94), while plugin.version
// remains the host-facing declared version during the migration.
version: loaded.config.plugin.version,
Issue #94 stage 1 is partially landed: snapshotPackageIdentity() reads package.json name/version (packages/agent-bundle/src/core/project-context.ts), and a mismatch with plugin.version emits warning AB4008 — but the config field remains mandatory and there is no default/fallback during normalization.
The audiobook-curator example documents the interim contract explicitly: package.json is the single version source, config must restate it until plugin.version becomes optional (#94 stage 3).
No build-time version constant for plugin source
Search of the build pipeline (packages/agent-bundle/src/build/**, MCP App Rsbuild config in mcp-apps.ts, Rslib composition in rslib.ts) shows:
- No framework-provided virtual module such as
agent-bundle:meta
- No injected
source.define / compile-time constant carrying name/version into plugin-authored modules
- Virtual sources exist only for generated entry shells, hook wrappers, MCP route workers, etc. — not for exposing project metadata to consumer source
Browser widget bundles (e.g. cargo-hauler views/dashboard-lib.ts) therefore cannot import release identity from the framework and rely on the hand-written src/lib/version.ts shim.
Requested design
(a) Config plugin.version optional with package.json default
(b) Framework-provided build-time version constant
Expose release identity to all compiled surfaces, including browser MCP App/widget bundles, via one of:
- a virtual module (e.g.
agent-bundle:meta exporting { name, version, packageName, packageVersion }), or
- a compile-time define injected consistently across Rslib route builds and Rsbuild MCP App builds
Goal: plugin runtime code imports the framework constant instead of maintaining src/lib/version.ts. The constant must reflect the same inferred identity used in manifests, dev status, and host projections.
(c) Release flow
One npm version patch (or equivalent) should be the entire bump — no parallel edits to config and hand-written version modules. Generated/consistency tests should pin the invariant automatically rather than requiring each plugin to author its own triplication police test.
Related issues
Acceptance criteria
- A packaged plugin can omit
plugin.version from config when package.json version is valid
- Plugin runtime modules (Node routes, daemon, CLI) and browser widget bundles can import framework-provided name/version without a local
version.ts
- Build, inspect, dev status, artifact manifests, and compiled surfaces agree on the same version axis
- cargo-hauler (or equivalent fixture) can delete
src/lib/version.ts and its hand-written consistency test once the framework owns the constant
Problem
Plugin projects currently declare release identity in multiple places. The cargo-hauler consumer plugin is a concrete example:
package.json"version"(npm release identity)agent-bundle.config.tsplugin.version(required config field)src/lib/version.ts— a hand-writtenexport const packageVersion = '…'because runtime code (daemon status, CLI, MCP application registry) and browser widget bundles need an importable version constant and cannot readpackage.jsonat runtimeThe plugin also carries a
version-consistencytest that asserts all three agree — slop the framework forces authors to maintain until release identity has one source and compiled surfaces get the value automatically.Current framework behavior (evidence)
Config
plugin.versionis still requiredThe public config type requires a version string:
Source validation rejects missing/empty values with AB4001:
Normalization still copies the authored config value into model metadata; it does not infer from
package.jsonwhen omitted:Issue #94 stage 1 is partially landed:
snapshotPackageIdentity()readspackage.jsonname/version (packages/agent-bundle/src/core/project-context.ts), and a mismatch withplugin.versionemits warning AB4008 — but the config field remains mandatory and there is no default/fallback during normalization.The audiobook-curator example documents the interim contract explicitly: package.json is the single version source, config must restate it until
plugin.versionbecomes optional (#94 stage 3).No build-time version constant for plugin source
Search of the build pipeline (
packages/agent-bundle/src/build/**, MCP App Rsbuild config inmcp-apps.ts, Rslib composition inrslib.ts) shows:agent-bundle:metasource.define/ compile-time constant carryingname/versioninto plugin-authored modulesBrowser widget bundles (e.g. cargo-hauler
views/dashboard-lib.ts) therefore cannot import release identity from the framework and rely on the hand-writtensrc/lib/version.tsshim.Requested design
(a) Config
plugin.versionoptional with package.json defaultplugin.versionoptional in config types and validationpackage.jsonversion during normalization (same axis already read bysnapshotPackageIdentity)(b) Framework-provided build-time version constant
Expose release identity to all compiled surfaces, including browser MCP App/widget bundles, via one of:
agent-bundle:metaexporting{ name, version, packageName, packageVersion }), orGoal: plugin runtime code imports the framework constant instead of maintaining
src/lib/version.ts. The constant must reflect the same inferred identity used in manifests, dev status, and host projections.(c) Release flow
One
npm version patch(or equivalent) should be the entire bump — no parallel edits to config and hand-written version modules. Generated/consistency tests should pin the invariant automatically rather than requiring each plugin to author its own triplication police test.Related issues
Acceptance criteria
plugin.versionfrom config whenpackage.jsonversion is validversion.tssrc/lib/version.tsand its hand-written consistency test once the framework owns the constant