Files
zooqueenandHanzo Dev 70b41673a3 frames: rebrand the fork to Hanzo Frames
Forked from HyperFrames (Apache-2.0), full history preserved.

Hosts are mapped explicitly and BEFORE the identifier rename, because
hyperframes.heygen.com is not decoration: 175 of its occurrences are $schema
identifiers that a validator dereferences. A blind rename would have left them
naming a host that never serves them. The schema files are in this repo under
docs/schema, so the mapped host is one we can actually serve -- that is the
condition that makes the rewrite safe, and serving them is a deploy task, not
an edit. docs/schema/hyperframes.json is renamed to frames.json to match the
identifier it is now published under.

api.heygen.com and the CLI auth against heygen.com are left UNRENAMED on
purpose. They are a dependency on HeyGen's SaaS, not a name of ours to take,
and the right move is to remove that integration rather than rebrand it.

LICENSE and CREDITS.md are untouched; NOTICE records the lineage.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-28 23:42:24 -07:00

63 lines
2.4 KiB
JavaScript

#!/usr/bin/env node
// Thin wrapper over the shared packet builder in frames-core — this file pins
// this workflow's paths plus its two behavioral differences: a code frame must carry
// an upstream-selected `### Source excerpt`, and code frames get a code-vocabulary
// excerpt appended to their packet. Everything else has one owner:
// ../../frames-core/scripts/lib/frame-packets-core.mjs
import { existsSync, readFileSync } from "node:fs";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import * as core from "../../frames-core/scripts/lib/frame-packets-core.mjs";
const SKILL_DIR = resolve(dirname(fileURLToPath(import.meta.url)), "..");
function sourceExcerpt(block) {
const match = block.match(/^### Source excerpt\s*\n+(```[^\n]*\n[\s\S]*?\n```)/im);
return match?.[1] ?? null;
}
function validateFrame(frame) {
const codeFrame = /\bcode-[a-z0-9-]+\b/i.test(core.field(frame.block, "focal") ?? "");
if (codeFrame && !sourceExcerpt(frame.block)) {
throw new Error(`${frame.heading}: code frame requires an upstream-selected Source excerpt`);
}
}
function codeVocabularySection(block) {
const focal = core.field(block, "focal") ?? "";
const codeId = focal.match(/\b(code-[a-z0-9-]+)\b/i)?.[1];
if (!codeId) return "";
const vocabPath = join(SKILL_DIR, "references", "code-vocabulary.md");
if (!existsSync(vocabPath)) {
return `\n## Code block\n\nUse registry block \`${codeId}\`.\n`;
}
const vocab = readFileSync(vocabPath, "utf8");
const lines = vocab.split("\n");
const exactToken = `\`${codeId.toLowerCase()}\``;
const matchingLines = lines.filter((line) => line.toLowerCase().includes(exactToken));
if (matchingLines.length === 0) {
return `\n## Code block\n\nUse registry block \`${codeId}\`.\n`;
}
return `\n## Code block excerpt (${codeId})\n\n${matchingLines.join("\n").trim()}\n`;
}
const CONFIG = {
animationDir: resolve(SKILL_DIR, "../frames-animation"),
corePath: resolve(SKILL_DIR, "../frames-core/references/frame-worker-core.md"),
deltaPath: resolve(SKILL_DIR, "sub-agents/frame-worker.md"),
validateFrame,
extraSections: codeVocabularySection,
};
export function buildRolePayload({ outDir }) {
return core.buildRolePayload({ ...CONFIG, outDir });
}
export function buildFramePackets(options) {
return core.buildFramePackets({ ...CONFIG, ...options });
}
if (core.isMainModule(import.meta.url)) core.runCli({ buildFramePackets, buildRolePayload });