Skip to content

Infer plugin version from package.json and expose a build-time version constant to plugin code #237

Description

@ScriptedAlchemy

Problem

Plugin projects currently declare release identity in multiple places. The cargo-hauler consumer plugin is a concrete example:

  1. package.json "version" (npm release identity)
  2. agent-bundle.config.ts plugin.version (required config field)
  3. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions