Skip to content

feat: support plugin configuration in bsconfig and CLI#1706

Draft
TwitchBronBron wants to merge 2 commits into
masterfrom
plugin-configuration-support
Draft

feat: support plugin configuration in bsconfig and CLI#1706
TwitchBronBron wants to merge 2 commits into
masterfrom
plugin-configuration-support

Conversation

@TwitchBronBron
Copy link
Copy Markdown
Member

@TwitchBronBron TwitchBronBron commented May 12, 2026

Summary

  • bsconfig.json plugins entries can now be objects: { src, name?, config? }. config is either an inline object or a path to a JSONC file (parsed with comments).
  • New Plugin.onSetConfiguration(config) lifecycle hook fires on every plugin immediately after load (string-shorthand plugins receive {}).
  • CLI --plugin <src> [<name>] pair syntax to load and name a plugin in one flag (repeatable). Coexists with the existing --plugins (plural) array form.
  • CLI --plugin.<id>.<prop>=<value> deep-merges on top of the bsconfig-provided config. A bare --plugin.<id>=<value> (no dotted path) replaces the bsconfig config entirely (loading a JSONC file if the value is a path); the two forms can be combined.
  • Override <id> is resolved with strict precedence: bsconfig user-supplied name → factory name → bsconfig src. A higher-priority match wins outright; ambiguity at the chosen level hard-fails with a clear message.
  • Quoted segments ("@scope/x", "id.with.dots") are supported at any position in the dotted key so ids or props containing dots can be addressed without escaping.
  • Docs rewritten in docs/plugins.md to cover naming precedence, replace vs. merge, and quoting rules, with worked examples for each.

Implementation notes

  • util.loadPlugins now returns Array<{ plugin, config, entry }> so the caller can match a plugin against its original bsconfig identity.
  • New pluginOverrides?: Record<string, { replace?, merge? }> runtime field on BsConfig (CLI-only — not loaded from bsconfig.json).
  • New helpers in util.ts:
    • extractPluginEntriesFromArgv — pre-tokenizes argv for --plugin <src> [<name>] pairs before yargs runs (yargs can't natively distinguish a name positional from another src in an array form).
    • parsePluginOverrideKey — tokenizes a dotted key, honoring "..." quoting at any segment.
    • extractPluginOverridesFromArgv — walks an argv map and builds the structured pluginOverrides object.
    • deepMerge, resolvePluginConfig (loads JSONC).
  • ProgramBuilder.loadPlugins does the override resolution: matches each <id> via the precedence above, applies replace first (resolving JSONC paths), then deep-merges merge on top, then dispatches onSetConfiguration.
  • util.resolvePathsRelativeTo handles PluginDefinition objects so relative src and (file-path) config resolve against the cwd/bsconfig directory. Pair entries collected by the pre-tokenizer flow through this same path resolution.

Test plan

  • npm run build clean
  • npm run lint clean
  • npm run test:nocover — 2633 passing, 0 failing (+ 40 new test cases across util.spec.ts and ProgramBuilder.spec.ts)
  • Manual smoke test: load a plugin via object form with both inline and file-based config, verify onSetConfiguration receives the merged values
  • Manual smoke test: CLI --plugin <src> <name> pair syntax, with and without an inline name
  • Manual smoke test: CLI --plugin.<id>.<prop>=<value> merge override
  • Manual smoke test: CLI --plugin.<id>=./config.jsonc total replacement, plus replace+merge combo
  • Manual smoke test: name precedence — verify user-supplied bsconfig name wins over factory-name collisions

🤖 Generated with Claude Code

Allow `plugins` entries in `bsconfig.json` to be objects with `src`,
optional `name`, and optional `config` (inline object or path to a JSONC
file) in addition to the existing string shorthand. Introduces a new
`Plugin.onSetConfiguration(config)` lifecycle hook that fires on every
plugin immediately after load. CLI flags of the form
`--plugin.<name>.<key>=<value>` deep-merge on top of the bsconfig
plugin config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@markwpearce
Copy link
Copy Markdown
Collaborator

Should this be in v1?

If not, can we change some stuff to match what v1 is doing with plugins? For Example changing event names.. "onSetConfiguration" -> "setConfiguration" (verb_noun format)

… plugin overrides

- Pre-tokenize argv for --plugin <src> [<name>] pairs (yargs can't natively
  distinguish a name positional from another src in an array form).
- Add `pluginOverrides` runtime field with replace/merge semantics:
  bare --plugin.<id>=<value> fully replaces the bsconfig config (loading a
  JSONC file if the value is a path); --plugin.<id>.<prop>=<value> deep-merges.
- Resolve override identifiers with strict precedence: bsconfig user-supplied
  `name` → factory `name` → bsconfig `src`. A higher-priority match wins
  outright; ambiguity at the chosen level hard-fails with a clear message.
- Add a flat-key parser supporting double-quoted segments at any position
  so ids/props containing dots can be addressed without escaping.
- Document the new CLI behavior and naming precedence in docs/plugins.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants