Public: anyone can read this; the crew can change it.
`/migrate?from=<host>/<owner>/<name>&crew=<agent>` opens Migrate with that repository and agent chosen, matched on the origin's full host #1491
Check · Review · Land · Live done — Landed and live in production.
`/migrate?from=<host>/<owner>/<name>&crew=<agent>` now opens Migrate with that repository and agent chosen. `bun test test/migrate.test.ts` (13 tests) and `bunx tsc --noEmit` pass in the sandbox. I did not run the whole check.
shipped production is serving it deploy 119f4d2
Approved. The link matches on URL(webUrl).host (port kept, lower-cased) and not the display label, caps and character-limits both values, and ignores a miss instead of guessing. Misses are named in one escaped line. The GET starts nothing, and Migrate is still a same-origin POST. Tests cover host with and without a port, the label mismatch, hostile input, and the page itself. I could not reach the preview from my sandbox (network denied), so this is judged from the source and the green check; I did not see the phone screenshot.
Next two things: (1) when from matches no origin because the origin list is empty or its listing failed, the page says nothing matches here, which reads wrong; say the origin could not be listed. (2) the legacy source/url/name query params and the new from param now both prefill; pick one in the docs so a link-maker knows which wins (from wins on source today).
/migrate?from=<host>/<owner>/<name>&crew=<agent>now opens Migrate with that repository and agent chosen.bun test test/migrate.test.ts(13 tests) andbunx tsc --noEmitpass in the sandbox. I did not run the whole check.src/web/pages/migrate-prefill.tscomparesfromwithURL(origin.webUrl).host(port kept, lower-cased) and then/<owner>/<name>, ignoring case. It never useshostLabel, which is what broke the earlier tries.migratePageinsrc/web/pages/migrate.tsruns the matcher on the origins and agents it already loads. A match selects the repository and agent, and the name field follows the repository. It makes no extra fetch and starts no job. POST is untouched and keeps its same-origin check.#prefill-unmatched).fromis capped at 200 characters andcrewat 64, and both are limited to safe ref characters. Echoed values are cut to 80 characters.test/migrate.test.ts: it checks the selection, a named mismatch, escaping, and that no repository is created. The file is already inGATE, soscripts/gate.tsis unchanged.docs/ORIGINS.mddescribes the link form.I left out a separate "put a crew on it" checkbox, because the form has none: choosing an agent is what puts a crew on the repository. The "Autonomous" checkbox stays off, so the person still decides that and still presses Migrate.
To try it, open
/migrate?from=<your origin's host[:port]>/<owner>/<name>&crew=<agent>while signed in.🤖 Generated with Claude Code
Closes #1472