feat(core,cli): media-use interop — shared index.md regen + description/entity on figma imports (#1927)

Post-release review of media-use ↔ figma coupling (spec §13.1):
- figma asset imports now regenerate .media/index.md, the agent-readable
  inventory media-use maintains — format locked byte-identical via a
  cross-runner parity test against media-use's own index-gen.mjs
- figma asset --description/--entity land in the manifest record, the
  index table, and <img alt>; component rasterize auto-describes with
  the node name. Named brand marks become visible to media-use's
  resolve --entity lookups.
- spec §13.1 records the review verdict (loose coupling correct) and
  the follow-up queue (shared media-ledger module, global cache for
  figma assets, media-use version-keyed idempotency)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-07-03 22:56:43 -07:00
committed by GitHub
co-authored by Claude Fable 5
parent cf594403ef
commit 3900caaaa9
12 changed files with 418 additions and 33 deletions
+8 -4
View File
@@ -67,12 +67,14 @@ export async function runComponentImport(
// The search key must match the EMITTED (html-escaped) node id, and
// replaceAll covers the same node appearing twice in the tree.
let html = mapped.html;
const frozenAssets: string[] = [];
for (const req of mapped.rasterize) {
const asset = await runAssetImport(
`${ref.fileKey}:${req.nodeId}`,
{ format: "svg" },
{ format: "svg", description: req.name },
{ projectDir: deps.projectDir, client: deps.client, download: deps.download },
);
frozenAssets.push(asset.record.path);
// src is a URL — always forward slashes, even when relative() yields
// windows separators.
const srcRel = relative(componentDir, join(deps.projectDir, asset.record.path)).replaceAll(
@@ -99,9 +101,11 @@ export async function runComponentImport(
target: `compositions/components/${name}/${name}.html`,
type: "hyperframes:snippet",
},
...mapped.rasterize.map((r) => ({
path: `${r.slug}.svg`,
target: `.media/images/${r.slug}.svg`,
// The paths the frozen files ACTUALLY landed at (image_NNN.svg), which
// is also what the emitted HTML references — not the slug names.
...frozenAssets.map((p) => ({
path: p.split("/").pop() ?? p,
target: p.replaceAll("\\", "/"),
type: "hyperframes:asset",
})),
],