feat: add AI-agent assisted migrations to create-plugin update#2774
feat: add AI-agent assisted migrations to create-plugin update#2774jackw wants to merge 16 commits into
Conversation
…gistry Migrations can now be script-only, prompt-only, or hybrid (script + prompt). Prompt-only migrations are skipped by the runner until the agentic runtime lands. Includes an unregistered example prompt documenting the authoring contract.
Prompt .md files are resolved relative to migrations.js at runtime via import.meta.resolve, so they must ship verbatim alongside the compiled migration scripts. Verified with a build smoke: dist/codemods/migrations/prompts/000-example.md exists.
AGENT_DEFINITIONS is pure data describing how to detect and interactively invoke Claude Code and OpenAI Codex. Claude invocations pre-authorize the handoff write via --allowedTools so sessions cannot stall on a permission prompt.
…ironments detectInstalledAgents probes each agent definition on the PATH via which, falling back to well-known install paths checked for the execute bit. isInsideAgent sniffs the environment variables agent CLIs set so update never spawns an agent from inside another agent.
The handoff JSON file is the completion signal for interactive agent sessions: ephemeral single-run IPC under node_modules/.cache, wiped at the start of every run, parsed with a strict valibot schema.
XML-sectioned system and user prompts with escaping of all file-derived content, a git-or-file-list hybrid change context (capped at 50 entries), an inside-agent directive block for deferred steps, and the manual next-steps list.
Spawns the agent CLI with inherited stdio, polls for the handoff file, and tears the session down with SIGINT escalating to SIGKILL. Exits are classified as handoff, user-aborted (130/143/SIGINT/SIGTERM), or ambiguous so the caller can prompt the user.
…d opt-in Resolution order: inside-agent env wins, --no-agent disables, non-TTY degrades (warning only when a flag was explicit), --agent=<id> pins and validates, bare --agent auto-picks or shows a picker, and no flag asks the user. Cancelled enquirer prompts are treated as a decline.
…, not HEAD The per-migration commit happens after the agent step so it can include the agent's edits — at agent time the codemod changes are flushed but uncommitted. Point the agent at git status/git diff instead of git show HEAD.
createAgenticRuntime resolves the mode once per run, wipes stale migrate runs, soft-forces per-migration commits when the user did not set --commit, runs prompt steps through the session runner (deferring in disabled and inside-agent modes), and prints the end-of-run directive block, next-steps list, or applied recap.
The runtime is lazily imported only when a queued migration has a prompt. Hybrid migrations run their codemod first, then the agent step before the per-migration commit so agent edits are included. Deferred prompt steps still stamp the version; a failed agent step aborts un-stamped.
The agent flag is stripped from codemodOptions so it never reaches codemod schemas, and --commit is forwarded as a tri-state so agentic runs can soft-force per-migration commits only when the user did not decide.
Covers the opt-in flow, agent flag forms, CI behavior (agent steps are skipped and surfaced as next steps in the job log), inside-agent deferral, and the prompt migration authoring contract.
joshhunt
left a comment
There was a problem hiding this comment.
Interesting! I initially thought it would be better to use an agent to write a deterministic codemod, but I understand your reasoning to use agents to perform actions that are tricky to determinately code up front.
Just to make sure - the intention here is that migrations within this repo are written as 000-migration.md and plugin developers in them with the create-plugin tooling? Plugin developers themselves wouldn't be writing migrations like this in their repo?
I'm unsure how to feel about this. It feels like an awkward mixing of tool fidelity. I completely understand the advantages this has, but I think if I run create-plugin update I'm expecting something deterministic to happen. Maybe, could these be surfaced as skills for users to invoke in their coding agent instead?
| id: 'claude-code', | ||
| displayName: 'Claude Code', | ||
| binaryNames: ['claude'], | ||
| wellKnownPaths: [join(homedir(), '.claude', 'local', 'claude')], |
There was a problem hiding this comment.
fwiw, i think it's more straight forward to just not try to guess where else claude could be other than path. feels almost kind of sneaky to do this.
I've written nearly all the codemods in this repo using an agent skill. I've had claude open a PR with it here.
Yes, migrations continue to live in this repo rather than plugin devs writing their own migrations in plugin repos. |
Drop the well-known-path fallbacks from agent detection per review feedback. If an agent binary isn't on PATH it isn't set up for CLI use, so probing hardcoded install locations added complexity without a legitimate use case.
It is a bit of an odd one but I'm trying to think of ways to leverage our AI overlords to make updates easier on devs. I'm thinking these prompts will be able to fix the things that we can't codemod (e.g. customisations devs have made to eslint, webpack that we can't possibly know or want to cater for). I'm not sure about skills - they don't have a migration manager and registry so a skill would need to reimplement these things to know what to run and when. Then there's the whole agent format fragmentation between claude, codex, whatever new agent where as in this way we have a single prompt file that serves them all. Maybe we gate spawning strictly behind |
What this PR does / why we need it:
Lets
create-plugin updateleverage locally installed AI agent CLIs across the migration pipeline. Some upgrade work can't be reliably codemodded (user-authored configs, plugin source refactors); this PR gives migrations a way to ship natural-language instructions that an agent applies under user supervision.How it works
prompt.md instructions file), and hybrid (codemod runs first, agent finishes). All 12 existing migrations are untouched; v1 ships infrastructure plus an unregistered example prompt (prompts/000-example.md) documenting the authoring contract.which. When a queued migration has a prompt and an agent is installed,updateasks before using it;--agent[=<id>]/--no-agentdecide up front.node_modules/.cache/grafana-create-plugin/migrate-runs/, wiped every run) that create-plugin polls, then tears the session down (SIGINT → 5s → SIGKILL). Failed handoffs abort the update un-stamped; ambiguous exits ask the user.--commit/--no-committhemselves) so each agent step sees an isolatedgit diff; hybrids embed the codemod's changed-file list from the stagedContextwhen commits are off.updateitself runs inside an agent session (env sniffing:CLAUDECODE,CODEX_THREAD_ID, etc.), no inner agent is spawned — deferred steps are printed as an XML directive block for the outer agent to complete.Verification
--no-agent, explicit--agenton non-TTY (warn + degrade), and the inside-agent directive block all verified live; version stamping and exit codes correct in every mode.claudeCLI confirms the--system-promptand--allowedToolsinvocation args.Which issue(s) this PR fixes:
n/a
Special notes for your reviewer:
update). The Codex invocation args mirror the Nx implementation but are unverified against a local install.--validate(agent validates script-only migrations), the first real prompt/hybrid migration, and surfacing deferred next-steps in the CI auto-update PR body.🤖 Generated with Claude Code