feat(CLI Tool): Return flexible codebase files to local environment on canvas pull
AI Disclosure: Yes. Used Claude to help develop and document this change.
Closes #3591862 (closed)
Summary
Extends the Canvas CLI push/pull to include the flexible codebase files a project needs to be reconstructed on disk. On push, in addition to component code, the CLI now stores and later restores:
package.json— pushed to and stored on the asset library, restored on pull. A terminal note prompts runningnpm installwhen it changes.- Local helper modules a component imports via the
@/…alias — overwritten on pull. - Binary assets (images, video, SVG) imported via
@/…,./, or../— overwritten on pull. - Transitively- or relatively-imported local modules stay bundled into the existing runtime entry rather than emitted as standalone artifacts. Their verbatim source is preserved separately so a pull can still restore the editable file on disk.
Global asset library changes
assets entries gain new fields:
path— the original relative disk path, so pull writes each file back to its true location. Derived from the resolved absolute path, never from the synthetic@/…specifier.source— the verbatim original source of a local module import.url— where the CLI can download the file over HTTP (external, computed fresh each response). Text modules skipurl: their content rides inline insource; only binaries need fetching.
New top-level keys:
packageJson— the projectpackage.jsoncontent as a string.bundledSources— verbatim sources of local modules that were bundled into another artifact and so have no standalone runtime entry (transitive or relative imports). Each entry is{ path, source }, keyed by disk path. These carry nouriand are never part of the import map; they exist only so a pull can reconstruct the editable file.
"assets": [
{
"name": "@/assets/mountain.png",
"uri": "public://canvas/assets/mountain-COB9CijR.png",
"path": "src/assets/mountain.png",
"url": "/sites/default/files/canvas/assets/mountain-COB9CijR.png"
},
{
"name": "@/lib/formatTitle",
"uri": "public://canvas/assets/formatTitle-CYObcZwM.js",
"path": "src/lib/formatTitle.ts",
"source": "export function formatTitle(value: string): string {\n return value.trim();\n}\n",
"url": "/sites/default/files/canvas/assets/formatTitle-CYObcZwM.js"
}
],
"bundledSources": [
{ "path": "src/lib/relative-helper.ts", "source": "export const x = 1;\n" }
],
"packageJson": "…package.json content as string…" canvas-manifest.json changes
Two new top-level keys carry the metadata needed to reconstruct files on disk. Everything else (vendor, local, shared) is unchanged and still acts as the import map.
localSources— per-entry{ path, source? }for local artifacts in the import map.sourceis present for text modules, absent for binaries.bundledSources— array of{ path, source }for local modules bundled into other artifacts (no standalone artifact, no import-map entry).
{
"vendor": { "lodash": "./vendor/lodash-abc123.js" },
"local": {
"@/lib/foo": "./local/foo-abc.js",
"@/assets/poster.webp": "./local/poster-def.webp"
},
"localSources": {
"@/assets/poster.webp": { "path": "src/assets/poster.webp" },
"@/lib/foo": { "path": "src/lib/foo.ts", "source": "export const x = 1;\n" }
},
"bundledSources": [
{ "path": "src/lib/relative-helper.ts", "source": "export const y = 2;\n" }
],
"shared": []
} Testing instructions
- Run
canvas pushon a project with local modules and imported assets. - Delete or alter a local module, a transitively-imported helper, or
package.json, then runcanvas pulland confirm each is restored to its original path. - Run
canvas pullfrom an empty repo and confirm all flexible codebase files are returned. - Confirm the terminal note about running
npm installappears whenpackage.jsonchanged.
Edited by Harumi Jang