/** * Renaming and removing a canvas extension. * * Design: `docs/canvas-extensions-design.md` §13.6. These exist because a canvas * has more identity than a file does, and it is spread across four places: the * directory name (which *is* the extension id, since discovery keys off * position), the `id` a canvas declares, its `displayName`, and whatever the * header comment tells the reader to type. Renaming by hand means getting all * four right, and getting the `id` wrong is not a typo — it drops the canvas the * person is looking at on the next reload, because the instance was opened * against a canvas that no longer exists. * * So the rewriting is deliberately narrow. It changes the three places the * scaffold puts the name and nothing else, then **reports every other line the * old name still appears on** rather than guessing at prose. A rename that * silently edited a description would be worse than one that admits what it left * behind. */ import type { CanvasSearchRoot, DiscoveredCanvasExtension } from "./discovery.js"; /** One line the rename changed. */ export interface CanvasRewrite { /** 1-based, so it can be read straight off an editor gutter. */ line: number; before: string; after: string; } /** What {@link renameCanvasExtension} did. */ export interface CanvasRenameResult { from: string; to: string; /** Workspace-relative where possible, for a message a person can act on. */ dir: string; rewrites: CanvasRewrite[]; /** * Lines where the old name survives, because they are prose rather than * identity. Surfaced, never silently edited. */ leftovers: number[]; } /** * Why a canvas cannot be renamed or removed in place. * * `packaged` is the interesting one: a plugin's canvases are named by its * manifest rather than by where they sit, so moving the directory would either * do nothing or break the plugin. That is `/plugin`'s job, not this one's. */ export type CanvasLifecycleRefusal = { reason: "invalid-name"; detail: string; } | { reason: "exists"; detail: string; } | { reason: "packaged"; detail: string; } | { reason: "unwritable"; detail: string; }; /** * Whether this extension is one we may move or delete. * * The test is positional and deliberately so: an extension is ours to edit when * its directory sits *directly* inside one of the search roots, which is exactly * the layout `discoverCanvasExtensions` walks. Anything else arrived inside a * package — resolved through a manifest by `plugin-canvases.ts` — and its * location is that package's business. */ export declare function canvasHomeRoot(extension: DiscoveredCanvasExtension, roots: readonly CanvasSearchRoot[]): CanvasSearchRoot | undefined; /** * Rename a canvas extension: its directory, and the name inside its code. * * The caller is responsible for closing open instances first. This does not do * it, because closing is the *session's* concern and this module has no session — * but skipping it leaves an instance pointing at a directory that has moved. */ export declare function renameCanvasExtension(extension: DiscoveredCanvasExtension, to: string, roots: readonly CanvasSearchRoot[]): CanvasRenameResult | CanvasLifecycleRefusal; /** What {@link removeCanvasExtension} deleted. */ export interface CanvasRemoveResult { id: string; dir: string; } /** * Delete a canvas extension's directory. * * As with rename, the caller closes open instances first — a deleted directory * whose child is still forked leaves a process serving code that no longer * exists on disk, which is the most confusing state of all. */ export declare function removeCanvasExtension(extension: DiscoveredCanvasExtension, roots: readonly CanvasSearchRoot[]): CanvasRemoveResult | CanvasLifecycleRefusal; /** Narrow a lifecycle return value to its refusal case. */ export declare function isCanvasRefusal(value: object): value is CanvasLifecycleRefusal; //# sourceMappingURL=lifecycle.d.ts.map