fix(core,figma-skill): address PR feedback — regex key escaping, no-shell psnr probe

- motionContextToDocs: escape regex metacharacters in arrayAfterKey /
  scalarAfterKey key interpolation (safe today for \\w+ keys; now safe for
  any future caller), and document balancedBlock's no-strings invariant.
- verify-motion.mjs: execSync shell string -> spawnSync with array args
  (JSON.stringify is not shell escaping); verifier re-calibrated unchanged
  (faithful render still PASS at min 20.30dB).
- command-failure-tracking: rebase folded the group-delegation skip into
  upstream's recursive wrapCommand (HF#2033) — leaf commands now assert
  their own flag tables, so `figma component --namee` is rejected at the
  leaf while `--name` passes the group; heuristic invariant documented.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Vance Ingalls
2026-07-09 00:51:35 -07:00
co-authored by Claude Fable 5
parent a2243f7586
commit 3d59dcc694
3 changed files with 16 additions and 7 deletions
+11 -3
View File
@@ -58,7 +58,15 @@ export interface MotionContextToDocsOptions {
/** motion.dev property → GSAP property. */
const PROPERTY_MAP: Record<string, string> = { rotate: "rotation" };
/** Extract the balanced `{...}` body following `marker` in `src`. */
/** Escape regex metacharacters — keys are `\w+` property names today, but a
* future caller passing anything else must not silently misparse. */
function escapeRegExp(text: string): string {
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
/** Extract the balanced `{...}` body following `marker` in `src`. Brace
* counting does not skip string literals — sound for motion.dev output
* (numeric arrays + named eases, never arbitrary strings containing `}`). */
function balancedBlock(src: string, marker: string): string | null {
const at = src.indexOf(marker);
if (at === -1) return null;
@@ -77,7 +85,7 @@ function balancedBlock(src: string, marker: string): string | null {
/** Extract a balanced `[...]` immediately after `key:` inside `src`. */
function arrayAfterKey(src: string, key: string): string | null {
const re = new RegExp(`${key}\\s*:\\s*\\[`);
const re = new RegExp(`${escapeRegExp(key)}\\s*:\\s*\\[`);
const m = re.exec(src);
if (!m) return null;
const start = m.index + m[0].length - 1;
@@ -93,7 +101,7 @@ function arrayAfterKey(src: string, key: string): string | null {
}
function scalarAfterKey(src: string, key: string): string | null {
const m = new RegExp(`${key}\\s*:\\s*("[^"]*"|[\\w.]+)`).exec(src);
const m = new RegExp(`${escapeRegExp(key)}\\s*:\\s*("[^"]*"|[\\w.]+)`).exec(src);
return m?.[1] ?? null;
}
+1 -1
View File
@@ -10,7 +10,7 @@
"files": 18
},
"figma": {
"hash": "e84abcb652194f57",
"hash": "3172ad95070aaecc",
"files": 2
},
"general-video": {
+4 -3
View File
@@ -21,7 +21,7 @@
* frame. Measure it from the render (the card's left/top edge + scaled
* size), don't guess: a wrong crop reads as motion divergence.
*/
import { execFileSync, execSync } from "node:child_process";
import { execFileSync, spawnSync } from "node:child_process";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
@@ -72,8 +72,9 @@ const frame = (src, t, vf, dst) => {
const diff = (a, b, dst) =>
execFileSync("ffmpeg", ["-y", "-v", "error", "-i", a, "-i", b, "-filter_complex", "blend=all_mode=difference", dst]);
const psnr = (a, b) => {
const err = execSync(`ffmpeg -i ${JSON.stringify(a)} -i ${JSON.stringify(b)} -lavfi psnr -f null - 2>&1`).toString();
const m = err.match(/average:([\d.]+|inf)/);
// spawnSync with array args (no shell): psnr stats land on stderr
const r = spawnSync("ffmpeg", ["-i", a, "-i", b, "-lavfi", "psnr", "-f", "null", "-"], { encoding: "utf8" });
const m = (r.stderr || "").match(/average:([\d.]+|inf)/);
return m ? (m[1] === "inf" ? 99 : Number(m[1])) : NaN;
};