import { type AgentId } from './agent-targets.js'; import { type AgentsMdOutcome } from './agents-md.js'; import { type RepointedAsset } from './legacy-default-assets.js'; export interface UpgradeOptions { root: string; /** Where extractEngine unpacked the new engine tree, same shape scaffoldProject reads from. */ extractedEngineDir: string; /** The engine version being upgraded to, written into bitmagic.json's engineVersion field. */ engineVersion: string; /** * The environment to record when the project has none — a project scaffolded before the field * existed. Never overwrites an existing value, and the caller omits it when this run was pointed * somewhere by --env or BITMAGIC_ENV: a one-off override must not become the project's permanent * answer in a committed file. */ environmentToPin?: string; /** * Agents to ADD to the project's recorded set, from `--agent`. Unioned with whatever * `bitmagic.json` already says and persisted, because "I also use Kiro" is a fact about the * project rather than an aim for one command — the opposite of `--env`, which is deliberately not * persisted. Nothing is ever removed: see `agent-targets.ts`. */ addAgents?: readonly AgentId[]; } export interface UpgradeResult { engineVersion: string; previousEngineVersion: string; /** Every top-level path this run actually rewrote, in the order it rewrote them. */ replaced: string[]; /** What happened to AGENTS.md, and what to suggest about it. See scaffold/agents-md.ts. */ agentsMd: AgentsMdOutcome; /** * Why the `bitmagic reload` Stop hook could not be added, when it could not be. Absent when it * was added or was already there — the creator only needs telling about the case where they now * silently lack it. See scaffold/claude-settings.ts. */ claudeSettingsSkipped?: string; /** * The environment just backfilled into bitmagic.json, when one was. Absent when the project * already had one or none was offered — reported so a permanent write to a committed file is * never silent. */ environmentPinned?: string; /** The agent set this run wrote for, after unioning the recorded set with `--agent`. */ agents: AgentId[]; /** * The agents just added to bitmagic.json, when any were — including the backfill a project * scaffolded before the field existed receives. Reported for the same reason * `environmentPinned` is: a permanent write to a committed file is never silent. */ agentsAdded: AgentId[]; /** * Values in the project's `agents` field this CLI does not recognise — a hand edit, or a newer * CLI's. Reported and otherwise ignored, exactly as an unrecognised `environment` is: refusing to * upgrade would be a strange way to report a typo. */ agentsUnknown: string[]; /** * The platform-owned default assets in `src/work/world.json` that were repointed from their * legacy JSON files to the VXL3 ones. Empty when there was nothing to repoint. This is the one * write this command makes to the creator's game, so it is reported per asset rather than * folded into `replaced` — see scaffold/legacy-default-assets.ts. */ legacyAssetsRepointed: RepointedAsset[]; /** * Why world.json could not even be inspected for that repoint, when it could not be (missing, * unreadable, not JSON). Absent when it was read. The creator is told rather than left to * conclude their default assets are already current. */ legacyAssetsSkipped?: string; } /** * Refreshes the platform-owned parts of a scaffolded project in place, and nothing else. This is * the file-boundary described in the task brief: `engine/` (every VENDORED_DIRS entry) and * sw-cache-buster.js are wholesale-replaced, the config files AND SHIPPED SKILLS in * PLATFORM_GENERATED_FILES are re-rendered, and bitmagic.json is read-modified-written so only its * engineVersion field changes. Everything else on disk — src/ (bar the one world.json case next), * game.json, package.json, GAME-DESIGN.md, CLAUDE.md, .gitignore, and any skill the creator wrote * themselves — is never opened. * * `src/work/world.json` is opened for exactly one thing: the platform's own default voxel assets, * scaffolded before engine 3.1056 as legacy JSON `.vxl` URLs, are repointed to their VXL3 files * (nine known URLs, matched exactly; every other asset and field is left as found — see * scaffold/legacy-default-assets.ts). Nothing the creator put there is touched. * * AGENTS.md is the one conditional case, and never a destructive one: it is refreshed only when it * still hashes to what the CLI itself last wrote, and otherwise left untouched with a suggestion. * See scaffold/agents-md.ts for why that is worth the machinery. * * The skills are in that list on purpose (see PLATFORM_GENERATED_FILES): they describe the CLI, so * a project that never receives an updated one has an agent that cannot discover anything the CLI * learned since the project was scaffolded. Note the asymmetry with the rest of `.claude/`: paths * we render are overwritten, paths we do not are left entirely alone. Nothing under `.claude/` is * ever deleted, so a skill we stop shipping stays behind rather than being cleaned up — a stale * file being much cheaper than deleting one a creator wrote. * * Mirrors scaffoldProject's copy behaviour (same VENDORED_DIRS loop, same * `assertEngineBundleComplete` check), except it clears engine/ first: unlike a brand new * project's empty target, an existing engine/ may hold files a since-removed VENDORED_DIRS entry * left behind, or a leftover from a bad manual edit, and cpSync alone would merge over those * rather than remove them. * * That "clear first" step is what makes the up-front validation load-bearing here rather than * merely tidy: the target is a live project's engine/, already rm'd, so a check inside the copy * loop would demolish it and fail partway through repopulating it — and a project not under * version control has no way to recover that. */ export declare function upgradeProject(options: UpgradeOptions): UpgradeResult;