feat: Add get-plugin-info MCP action and improve configure-plugin usability#868
Conversation
…rrent config, and dependencies
🦋 Changeset detectedLatest commit: 97a93cc The changes in this PR will be included in the next version bump. This PR includes changesets to release 23 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (2)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR establishes a validation hint and schema description registry system across the codebase, introduces a new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
packages/project-builder-lib/src/schema/utils/validation.ts (1)
17-22: Consider adding a validation hint toOPTIONAL_CONSTANT_CASE_STRINGfor consistency.The other three validators in this file now have validation hints registered, but
OPTIONAL_CONSTANT_CASE_STRING(lines 23-27) does not. If this is intentional because it's a compound schema with.or(z.literal('')).optional(), the current state is fine. Otherwise, consider adding a hint for completeness.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-lib/src/schema/utils/validation.ts` around lines 17 - 22, The OPTIONAL_CONSTANT_CASE_STRING schema lacks a registered validation hint—update the OPTIONAL_CONSTANT_CASE_STRING declaration to call .register(validationHintRegistry, { description: "CONSTANT_CASE (e.g. 'MY_CONSTANT') or empty" }) (or a similar descriptive string) so it matches the other validators; locate the OPTIONAL_CONSTANT_CASE_STRING variable in this file and append the .register(...) call after the existing .or(z.literal('')).optional() chain to provide the consistent validation hint.packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts (2)
103-106: Multiline JSON output will have inconsistent indentation.When
currentConfigis a complex object,JSON.stringify(..., null, 2)produces multiline output, but only the first line gets theprefix. This results in misaligned CLI output.♻️ Proposed fix for consistent indentation
if (output.currentConfig != null) { console.info(` Current config:`); - console.info(` ${JSON.stringify(output.currentConfig, null, 2)}`); + const configJson = JSON.stringify(output.currentConfig, null, 2); + const indentedConfig = configJson.replace(/\n/g, '\n '); + console.info(` ${indentedConfig}`); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts` around lines 103 - 106, The console output for output.currentConfig uses JSON.stringify(..., null, 2) but only prefixes the first line with " ", causing misaligned multiline output; update the block in get-plugin-info.action.ts that logs output.currentConfig so that after calling JSON.stringify on output.currentConfig you normalize indentation by prefixing every line (e.g., split the string on "\n", add the " " prefix to each line, then join) before passing to console.info, keeping the existing log messages and using the same variable (output.currentConfig) and surrounding console.info calls.
99-102: Same indentation issue for multiline config schema.The
configSchemaTypeScript type string may also span multiple lines for complex schemas, causing the same misaligned output issue.♻️ Proposed fix
if (output.configSchema) { console.info(` Config schema:`); - console.info(` ${output.configSchema}`); + const indentedSchema = output.configSchema.replace(/\n/g, '\n '); + console.info(` ${indentedSchema}`); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts` around lines 99 - 102, The multiline configSchema string (output.configSchema) is printed with a single-console.info call which misaligns when it contains newlines; update the printing to split output.configSchema by '\n' and log each line with the same indentation applied (e.g., console.info(' ' + line)) so every line of the schema is properly indented—change the block that references output.configSchema and the two console.info calls to iterate lines and prefix each with the intended spaces.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@packages/project-builder-server/src/actions/definition/configure-plugin.action.ts`:
- Around line 83-85: The code seeds existingIds only from top-level plugins and
passes that set into assignEntityIds (in the call with configSchema and
pluginConfig), which misses IDs nested elsewhere and can produce collisions; fix
by implementing a collector (e.g., collectExistingIds) that recursively
traverses the entire draft/config/plugin object graph and accumulates all string
.id values into the existingIds Set, then use that comprehensive Set when
calling assignEntityIds (update both the existingIds creation site and the call
where assignEntityIds(configSchema, pluginConfig, { isExistingId: ... }) is
invoked) so generated nested IDs are checked against all definition-wide IDs.
- Around line 139-163: The update branch currently only rewrites plugins[idx] =
{ ...plugins[idx], config: processedConfig } and so leaves configSchemaVersion
stale or sets it to undefined; compute the latest migration version via
pluginConfigService.getLastMigrationVersion(pluginMetadata.key) (move or call
the pluginConfigService lookup used in the isNew branch into the update branch
or above both branches) and when idx !== -1 include configSchemaVersion:
lastMigrationVersion in the object only if lastMigrationVersion is not undefined
(i.e. merge it into plugins[idx] when present) so existing plugin rewrites keep
configSchemaVersion in sync but do not write undefined for plugins with no
migrations.
---
Nitpick comments:
In `@packages/project-builder-lib/src/schema/utils/validation.ts`:
- Around line 17-22: The OPTIONAL_CONSTANT_CASE_STRING schema lacks a registered
validation hint—update the OPTIONAL_CONSTANT_CASE_STRING declaration to call
.register(validationHintRegistry, { description: "CONSTANT_CASE (e.g.
'MY_CONSTANT') or empty" }) (or a similar descriptive string) so it matches the
other validators; locate the OPTIONAL_CONSTANT_CASE_STRING variable in this file
and append the .register(...) call after the existing
.or(z.literal('')).optional() chain to provide the consistent validation hint.
In
`@packages/project-builder-server/src/actions/definition/get-plugin-info.action.ts`:
- Around line 103-106: The console output for output.currentConfig uses
JSON.stringify(..., null, 2) but only prefixes the first line with " ",
causing misaligned multiline output; update the block in
get-plugin-info.action.ts that logs output.currentConfig so that after calling
JSON.stringify on output.currentConfig you normalize indentation by prefixing
every line (e.g., split the string on "\n", add the " " prefix to each line,
then join) before passing to console.info, keeping the existing log messages and
using the same variable (output.currentConfig) and surrounding console.info
calls.
- Around line 99-102: The multiline configSchema string (output.configSchema) is
printed with a single-console.info call which misaligns when it contains
newlines; update the printing to split output.configSchema by '\n' and log each
line with the same indentation applied (e.g., console.info(' ' + line)) so
every line of the schema is properly indented—change the block that references
output.configSchema and the two console.info calls to iterate lines and prefix
each with the intended spaces.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9c652853-f19a-41d0-8e96-eab8af5fef19
📒 Files selected for processing (19)
.agents/mcp-actions.md.changeset/add-get-plugin-info-mcp-action.mdexamples/todo-with-better-auth/pnpm-workspace.yamlpackage.jsonpackages/project-builder-lib/src/parser/index.tspackages/project-builder-lib/src/schema/utils/validation.tspackages/project-builder-lib/src/tools/index.tspackages/project-builder-server/src/actions/definition/build-ts-description-registry.tspackages/project-builder-server/src/actions/definition/build-ts-description-registry.unit.test.tspackages/project-builder-server/src/actions/definition/configure-plugin.action.tspackages/project-builder-server/src/actions/definition/get-entity-schema.action.tspackages/project-builder-server/src/actions/definition/get-plugin-info.action.tspackages/project-builder-server/src/actions/definition/index.tspackages/project-builder-server/src/actions/definition/schema-to-type-string.tspackages/project-builder-server/src/actions/definition/schema-to-type-string.unit.test.tspackages/project-builder-server/src/actions/registry.tspackages/utils/src/validators/case-validators.tspackages/utils/src/validators/index.tspackages/utils/src/validators/validation-hint-registry.ts
| return assignEntityIds(configSchema, pluginConfig, { | ||
| isExistingId: (id) => existingIds.has(id), | ||
| }); |
There was a problem hiding this comment.
Use definition-wide IDs when auto-generating nested entity IDs.
Line 124 only seeds existingIds from plugins[].id, and Lines 83-85 pass that straight into assignEntityIds. That leaves collisions with the rest of the draft invisible, including IDs nested under other plugins and the new plugin entity ID itself, so generated config IDs can still duplicate existing entities.
💡 Minimal fix sketch
- const existingIds = new Set(
- serializedPlugins.map((p) => p.id as string).filter(Boolean),
- );
+ const existingIds = collectExistingIds(serializedDef);
+ existingIds.add(pluginEntityId);function collectExistingIds(
value: unknown,
ids = new Set<string>(),
): Set<string> {
if (Array.isArray(value)) {
for (const item of value) collectExistingIds(item, ids);
return ids;
}
if (value && typeof value === 'object') {
const record = value as Record<string, unknown>;
if (typeof record.id === 'string') ids.add(record.id);
for (const child of Object.values(record)) {
collectExistingIds(child, ids);
}
}
return ids;
}Also applies to: 124-126
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@packages/project-builder-server/src/actions/definition/configure-plugin.action.ts`
around lines 83 - 85, The code seeds existingIds only from top-level plugins and
passes that set into assignEntityIds (in the call with configSchema and
pluginConfig), which misses IDs nested elsewhere and can produce collisions; fix
by implementing a collector (e.g., collectExistingIds) that recursively
traverses the entire draft/config/plugin object graph and accumulates all string
.id values into the existingIds Set, then use that comprehensive Set when
calling assignEntityIds (update both the existingIds creation site and the call
where assignEntityIds(configSchema, pluginConfig, { isExistingId: ... }) is
invoked) so generated nested IDs are checked against all definition-wide IDs.
| if (isNew) { | ||
| const pluginConfigService = pluginStore.use(pluginConfigSpec); | ||
| const lastMigrationVersion = pluginConfigService.getLastMigrationVersion( | ||
| pluginMetadata.key, | ||
| ); | ||
| })(container.definition); | ||
|
|
||
| // Serialize back to name-based format | ||
| const serializedDef = serializeSchema( | ||
| container.schema, | ||
| newDefinition, | ||
| ) as Record<string, unknown>; | ||
| updatedDef = produce(serializedDef, (draft) => { | ||
| const plugins = (draft.plugins ?? []) as Record<string, unknown>[]; | ||
| plugins.push({ | ||
| id: pluginEntityId, | ||
| name: pluginMetadata.name, | ||
| version: pluginMetadata.version, | ||
| packageName: pluginMetadata.packageName, | ||
| config: processedConfig, | ||
| configSchemaVersion: lastMigrationVersion, | ||
| }); | ||
| draft.plugins = plugins; | ||
| }); | ||
| } else { | ||
| updatedDef = produce(serializedDef, (draft) => { | ||
| const plugins = draft.plugins as Record<string, unknown>[]; | ||
| const idx = plugins.findIndex((p) => p.id === pluginEntityId); | ||
| if (idx !== -1) { | ||
| plugins[idx] = { ...plugins[idx], config: processedConfig }; | ||
| } |
There was a problem hiding this comment.
Keep configSchemaVersion in sync when rewriting configs.
New plugins get the latest migration version, but updates leave the previous configSchemaVersion untouched. After rewriting an existing plugin against the current schema, the saved definition can still look stale to migration code later. This branch should also avoid writing configSchemaVersion: undefined for plugins with no migrations.
💡 Minimal fix sketch
- if (isNew) {
- const pluginConfigService = pluginStore.use(pluginConfigSpec);
- const lastMigrationVersion = pluginConfigService.getLastMigrationVersion(
- pluginMetadata.key,
- );
+ const pluginConfigService = pluginStore.use(pluginConfigSpec);
+ const lastMigrationVersion = pluginConfigService.getLastMigrationVersion(
+ pluginMetadata.key,
+ );
+
+ if (isNew) {
updatedDef = produce(serializedDef, (draft) => {
const plugins = (draft.plugins ?? []) as Record<string, unknown>[];
- plugins.push({
+ const nextPlugin: Record<string, unknown> = {
id: pluginEntityId,
name: pluginMetadata.name,
version: pluginMetadata.version,
packageName: pluginMetadata.packageName,
config: processedConfig,
- configSchemaVersion: lastMigrationVersion,
- });
+ };
+ if (lastMigrationVersion !== undefined) {
+ nextPlugin.configSchemaVersion = lastMigrationVersion;
+ }
+ plugins.push(nextPlugin);
draft.plugins = plugins;
});
} else {
updatedDef = produce(serializedDef, (draft) => {
const plugins = draft.plugins as Record<string, unknown>[];
const idx = plugins.findIndex((p) => p.id === pluginEntityId);
if (idx !== -1) {
- plugins[idx] = { ...plugins[idx], config: processedConfig };
+ const nextPlugin = {
+ ...plugins[idx],
+ config: processedConfig,
+ } as Record<string, unknown>;
+ if (lastMigrationVersion === undefined) {
+ delete nextPlugin.configSchemaVersion;
+ } else {
+ nextPlugin.configSchemaVersion = lastMigrationVersion;
+ }
+ plugins[idx] = nextPlugin;
}
});
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@packages/project-builder-server/src/actions/definition/configure-plugin.action.ts`
around lines 139 - 163, The update branch currently only rewrites plugins[idx] =
{ ...plugins[idx], config: processedConfig } and so leaves configSchemaVersion
stale or sets it to undefined; compute the latest migration version via
pluginConfigService.getLastMigrationVersion(pluginMetadata.key) (move or call
the pluginConfigService lookup used in the isNew branch into the update branch
or above both branches) and when idx !== -1 include configSchemaVersion:
lastMigrationVersion in the object only if lastMigrationVersion is not undefined
(i.e. merge it into plugins[idx] when present) so existing plugin rewrites keep
configSchemaVersion in sync but do not write undefined for plugins with no
migrations.
Summary by CodeRabbit
New Features
get-plugin-infoaction for retrieving detailed plugin information, including configuration schema and current settings.Improvements