`extension_dev`, `extension_start` and `extension_build` spawn that
release when a project has no engine of its own, and the nightly
engine-pin check reads it against `latest` again.
- A human now approves a real store submission and a promotion to stable
before either runs, by default. The first call answers
`approval-required` with an `approvalUrl` on extension.dev
(`/device/approve/<id>`) and an `approvalId`; once a workspace member
approves (an owner, for a submission), the same call with that
`approvalId` runs exactly that action, once. Promotions to other channels
and share revokes stay ungated unless `EXTENSION_DEV_APPROVAL_GATE=1`;
`EXTENSION_DEV_APPROVAL_GATE=0` turns the default off. Whatever the
setting, a platform that answers `APPROVAL_REQUIRED` now gets the same
approval flow instead of a bare failure.
- Two server flags narrow what an agent can reach. `--features=local`
or `--features=platform` (env `EXTENSION_DEV_FEATURES`) lists one tool
group; `local` alone is about 40% smaller. `--no-ship` (env
`EXTENSION_DEV_NO_SHIP`) hides `extension_publish` and
`extension_release_promote` and refuses a real submit, a share link and
a share revoke, while dry runs and listing keep working. A refused call
answers the new code `E_TOOL_DISABLED` with the flag to change. Both
default to everything on, so no existing setup changes.
- Every tool now carries MCP annotations (`readOnlyHint`,
`destructiveHint`, `idempotentHint`, `openWorldHint`) from one policy
table, so clients can auto-approve reads and ask before the rest. A
merged tool takes its worst action: `extension_shares` is destructive
because revoke is.
- A device-flow step waiting on a human (`extension_auth` login,
`extension_project_create`, `extension_workspace_create`) now answers
`ok: true` with `status: "authorization-pending"` and no error, instead
of `ok: false` with `E_AUTH_PENDING`, so clients stop rendering the
first login step as a failure. The approval link and code stay in
`hint` and `value`; `E_AUTH_PENDING` is retired.