@prestyj/editor 0.7.60 → 0.7.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/brand-kit.test.js +1 -1
- package/dist/core/doctor.test.js +5 -5
- package/dist/core/hosts/premiere/bridge-source.js +1 -1
- package/dist/core/hosts/resolve/bridge.integration.test.js +1 -1
- package/dist/core/skills-loader.test.js +16 -16
- package/dist/core/styles-loader.test.js +8 -8
- package/dist/tools/audit-retention-structure.test.js +2 -2
- package/dist/tools/compose-layered.js +1 -1
- package/dist/tools/concat-videos.js +1 -1
- package/dist/tools/concat-videos.test.js +2 -2
- package/dist/tools/cut-filler-words.js +1 -1
- package/dist/tools/find-viral-moments.test.js +4 -4
- package/dist/tools/generate-gif.js +1 -1
- package/dist/tools/generate-gif.test.js +2 -2
- package/dist/tools/generate-youtube-metadata.test.js +3 -3
- package/dist/tools/new-tools.test.js +7 -7
- package/dist/tools/path-traversal.test.js +1 -1
- package/dist/tools/read-transcript.test.js +1 -1
- package/dist/tools/render-multi-format.test.js +1 -1
- package/dist/tools/reorder-timeline.js +1 -1
- package/dist/tools/score-clip.test.js +2 -2
- package/dist/tools/suggest-broll.js +1 -1
- package/dist/tools/suggest-broll.test.js +4 -4
- package/dist/tools/text-based-cut.js +1 -1
- package/package.json +4 -4
|
@@ -4,7 +4,7 @@ import { tmpdir } from "node:os";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { BRAND_KIT_PATH, loadBrandKit, validateBrandKit } from "./brand-kit.js";
|
|
6
6
|
function makeCwd(brand) {
|
|
7
|
-
const cwd = mkdtempSync(join(tmpdir(), "
|
|
7
|
+
const cwd = mkdtempSync(join(tmpdir(), "ez-brandkit-test-"));
|
|
8
8
|
if (brand !== undefined) {
|
|
9
9
|
mkdirSync(join(cwd, ".ezcoder"), { recursive: true });
|
|
10
10
|
writeFileSync(join(cwd, BRAND_KIT_PATH), brand, "utf8");
|
package/dist/core/doctor.test.js
CHANGED
|
@@ -58,24 +58,24 @@ describe("runDoctor", () => {
|
|
|
58
58
|
});
|
|
59
59
|
describe("isOnboarded / onboardedMarkerPath", () => {
|
|
60
60
|
it("returns false when the marker is absent", () => {
|
|
61
|
-
const home = mkdtempSync(join(tmpdir(), "
|
|
61
|
+
const home = mkdtempSync(join(tmpdir(), "ez-doctor-"));
|
|
62
62
|
expect(isOnboarded(home)).toBe(false);
|
|
63
63
|
});
|
|
64
64
|
it("returns true once the marker file exists", () => {
|
|
65
|
-
const home = mkdtempSync(join(tmpdir(), "
|
|
65
|
+
const home = mkdtempSync(join(tmpdir(), "ez-doctor-"));
|
|
66
66
|
const path = onboardedMarkerPath(home);
|
|
67
67
|
mkdirSync(join(home, ".ezcoder"), { recursive: true });
|
|
68
68
|
writeFileSync(path, "2026-04-30T00:00:00.000Z\n", "utf8");
|
|
69
69
|
expect(isOnboarded(home)).toBe(true);
|
|
70
70
|
});
|
|
71
71
|
it("returns false when the marker path exists but isn't a regular file", () => {
|
|
72
|
-
const home = mkdtempSync(join(tmpdir(), "
|
|
72
|
+
const home = mkdtempSync(join(tmpdir(), "ez-doctor-"));
|
|
73
73
|
// Create a directory at the marker path instead of a file.
|
|
74
74
|
mkdirSync(onboardedMarkerPath(home), { recursive: true });
|
|
75
75
|
expect(isOnboarded(home)).toBe(false);
|
|
76
76
|
});
|
|
77
77
|
it("auth check sees a present auth.json under the synthetic home", () => {
|
|
78
|
-
const home = mkdtempSync(join(tmpdir(), "
|
|
78
|
+
const home = mkdtempSync(join(tmpdir(), "ez-doctor-"));
|
|
79
79
|
mkdirSync(join(home, ".ezcoder"), { recursive: true });
|
|
80
80
|
writeFileSync(join(home, ".ezcoder", "auth.json"), "{}", "utf8");
|
|
81
81
|
const r = runDoctor(home);
|
|
@@ -84,7 +84,7 @@ describe("isOnboarded / onboardedMarkerPath", () => {
|
|
|
84
84
|
expect(auth.detail).toBe("signed in");
|
|
85
85
|
});
|
|
86
86
|
it("auth check reports missing on a fresh home", () => {
|
|
87
|
-
const home = mkdtempSync(join(tmpdir(), "
|
|
87
|
+
const home = mkdtempSync(join(tmpdir(), "ez-doctor-"));
|
|
88
88
|
const r = runDoctor(home);
|
|
89
89
|
const auth = r.checks.find((c) => c.id === "auth");
|
|
90
90
|
expect(auth.status).toBe("missing");
|
|
@@ -178,7 +178,7 @@ const METHODS = {
|
|
|
178
178
|
`,
|
|
179
179
|
create_timeline: String.raw `
|
|
180
180
|
if (!app.project) throw new Error("No project open in Premiere.");
|
|
181
|
-
var name = String(P.name || "
|
|
181
|
+
var name = String(P.name || "EZ Sequence");
|
|
182
182
|
var preset = P.presetPath || "";
|
|
183
183
|
var newSeq = null;
|
|
184
184
|
if (preset) {
|
|
@@ -421,7 +421,7 @@ def scriptapp(name): return _Resolve()
|
|
|
421
421
|
}
|
|
422
422
|
});
|
|
423
423
|
it("applies a LUT", async () => {
|
|
424
|
-
const lutDir = mkdtempSync(join(tmpdir(), "
|
|
424
|
+
const lutDir = mkdtempSync(join(tmpdir(), "ez-lut-"));
|
|
425
425
|
const lutPath = join(lutDir, "x.cube");
|
|
426
426
|
writeFileSync(lutPath, "# LUT\n");
|
|
427
427
|
const b = new ResolveBridge();
|
|
@@ -27,15 +27,15 @@ describe("extractDescription", () => {
|
|
|
27
27
|
});
|
|
28
28
|
describe("discoverSkills", () => {
|
|
29
29
|
it("returns bundled-only when no dirs exist", () => {
|
|
30
|
-
const cwd = tmp("
|
|
31
|
-
const home = tmp("
|
|
30
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
31
|
+
const home = tmp("ez-skills-home-");
|
|
32
32
|
const r = discoverSkills({ cwd, homeDir: home, bundled: BUNDLED });
|
|
33
33
|
expect(r.map((s) => s.name).sort()).toEqual(["alpha", "beta"]);
|
|
34
34
|
expect(r.every((s) => s.origin === "bundled")).toBe(true);
|
|
35
35
|
});
|
|
36
36
|
it("loads project skills with extracted description", () => {
|
|
37
|
-
const cwd = tmp("
|
|
38
|
-
const home = tmp("
|
|
37
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
38
|
+
const home = tmp("ez-skills-home-");
|
|
39
39
|
mkdirSync(join(cwd, ".ezcoder/editor-skills"), { recursive: true });
|
|
40
40
|
writeFileSync(join(cwd, ".ezcoder/editor-skills/gamma.md"), "# gamma\n\nProject-only skill body.\n");
|
|
41
41
|
const r = discoverSkills({ cwd, homeDir: home, bundled: BUNDLED });
|
|
@@ -44,8 +44,8 @@ describe("discoverSkills", () => {
|
|
|
44
44
|
expect(gamma?.description).toBe("Project-only skill body.");
|
|
45
45
|
});
|
|
46
46
|
it("user skill overrides bundled (last-wins)", () => {
|
|
47
|
-
const cwd = tmp("
|
|
48
|
-
const home = tmp("
|
|
47
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
48
|
+
const home = tmp("ez-skills-home-");
|
|
49
49
|
mkdirSync(join(home, ".ezcoder/editor-skills"), { recursive: true });
|
|
50
50
|
writeFileSync(join(home, ".ezcoder/editor-skills/alpha.md"), "# alpha\n\nUser-overridden alpha.\n");
|
|
51
51
|
const r = discoverSkills({ cwd, homeDir: home, bundled: BUNDLED });
|
|
@@ -54,8 +54,8 @@ describe("discoverSkills", () => {
|
|
|
54
54
|
expect(alpha?.description).toBe("User-overridden alpha.");
|
|
55
55
|
});
|
|
56
56
|
it("user wins over project when both define the same name", () => {
|
|
57
|
-
const cwd = tmp("
|
|
58
|
-
const home = tmp("
|
|
57
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
58
|
+
const home = tmp("ez-skills-home-");
|
|
59
59
|
mkdirSync(join(cwd, ".ezcoder/editor-skills"), { recursive: true });
|
|
60
60
|
mkdirSync(join(home, ".ezcoder/editor-skills"), { recursive: true });
|
|
61
61
|
writeFileSync(join(cwd, ".ezcoder/editor-skills/alpha.md"), "# a\n\nfrom project\n");
|
|
@@ -65,8 +65,8 @@ describe("discoverSkills", () => {
|
|
|
65
65
|
expect(alpha?.origin).toBe("user");
|
|
66
66
|
});
|
|
67
67
|
it("reads YAML frontmatter for name + description", () => {
|
|
68
|
-
const cwd = tmp("
|
|
69
|
-
const home = tmp("
|
|
68
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
69
|
+
const home = tmp("ez-skills-home-");
|
|
70
70
|
mkdirSync(join(cwd, ".ezcoder/editor-skills"), { recursive: true });
|
|
71
71
|
const md = '---\nname: my-skill\ndescription: "Use when X happens."\n---\n\n# My Skill\n\nBody.\n';
|
|
72
72
|
writeFileSync(join(cwd, ".ezcoder/editor-skills/anything.md"), md);
|
|
@@ -79,8 +79,8 @@ describe("discoverSkills", () => {
|
|
|
79
79
|
expect(s?.content.startsWith("---\nname:")).toBe(true);
|
|
80
80
|
});
|
|
81
81
|
it("frontmatter falls back to filename + body extraction when keys missing", () => {
|
|
82
|
-
const cwd = tmp("
|
|
83
|
-
const home = tmp("
|
|
82
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
83
|
+
const home = tmp("ez-skills-home-");
|
|
84
84
|
mkdirSync(join(cwd, ".ezcoder/editor-skills"), { recursive: true });
|
|
85
85
|
writeFileSync(join(cwd, ".ezcoder/editor-skills/foo.md"), "---\nother: stuff\n---\n\nA body line.\n");
|
|
86
86
|
const r = discoverSkills({ cwd, homeDir: home, bundled: BUNDLED });
|
|
@@ -88,8 +88,8 @@ describe("discoverSkills", () => {
|
|
|
88
88
|
expect(s?.description).toBe("A body line.");
|
|
89
89
|
});
|
|
90
90
|
it("loads bundle-layout skill (<name>/SKILL.md)", () => {
|
|
91
|
-
const cwd = tmp("
|
|
92
|
-
const home = tmp("
|
|
91
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
92
|
+
const home = tmp("ez-skills-home-");
|
|
93
93
|
mkdirSync(join(cwd, ".ezcoder/editor-skills/bundled-name"), { recursive: true });
|
|
94
94
|
writeFileSync(join(cwd, ".ezcoder/editor-skills/bundled-name/SKILL.md"), "---\nname: real-name\ndescription: From SKILL.md\n---\n\nBody.\n");
|
|
95
95
|
const r = discoverSkills({ cwd, homeDir: home, bundled: BUNDLED });
|
|
@@ -99,8 +99,8 @@ describe("discoverSkills", () => {
|
|
|
99
99
|
expect(s?.path?.endsWith("SKILL.md")).toBe(true);
|
|
100
100
|
});
|
|
101
101
|
it("discovers from .ezcoder/skills/ as well as legacy .ezcoder/editor-skills/", () => {
|
|
102
|
-
const cwd = tmp("
|
|
103
|
-
const home = tmp("
|
|
102
|
+
const cwd = tmp("ez-skills-cwd-");
|
|
103
|
+
const home = tmp("ez-skills-home-");
|
|
104
104
|
mkdirSync(join(cwd, ".ezcoder/skills"), { recursive: true });
|
|
105
105
|
writeFileSync(join(cwd, ".ezcoder/skills/ecosystem.md"), "---\nname: ecosystem\ndescription: skills.sh format\n---\nBody\n");
|
|
106
106
|
const r = discoverSkills({ cwd, homeDir: home, bundled: BUNDLED });
|
|
@@ -8,13 +8,13 @@ function tmp(prefix) {
|
|
|
8
8
|
}
|
|
9
9
|
describe("discoverStyles", () => {
|
|
10
10
|
it("returns empty when neither dir exists", () => {
|
|
11
|
-
const cwd = tmp("
|
|
12
|
-
const home = tmp("
|
|
11
|
+
const cwd = tmp("ez-styles-cwd-");
|
|
12
|
+
const home = tmp("ez-styles-home-");
|
|
13
13
|
expect(discoverStyles({ cwd, homeDir: home })).toEqual([]);
|
|
14
14
|
});
|
|
15
15
|
it("loads project + user styles", () => {
|
|
16
|
-
const cwd = tmp("
|
|
17
|
-
const home = tmp("
|
|
16
|
+
const cwd = tmp("ez-styles-cwd-");
|
|
17
|
+
const home = tmp("ez-styles-home-");
|
|
18
18
|
mkdirSync(join(cwd, ".ezcoder/editor-styles"), { recursive: true });
|
|
19
19
|
mkdirSync(join(home, ".ezcoder/editor-styles"), { recursive: true });
|
|
20
20
|
writeFileSync(join(cwd, ".ezcoder/editor-styles/voice.md"), "# voice\nproject voice");
|
|
@@ -25,8 +25,8 @@ describe("discoverStyles", () => {
|
|
|
25
25
|
expect(r.find((s) => s.name === "format")?.origin).toBe("user");
|
|
26
26
|
});
|
|
27
27
|
it("project overrides user on name collision (opposite of skills)", () => {
|
|
28
|
-
const cwd = tmp("
|
|
29
|
-
const home = tmp("
|
|
28
|
+
const cwd = tmp("ez-styles-cwd-");
|
|
29
|
+
const home = tmp("ez-styles-home-");
|
|
30
30
|
mkdirSync(join(cwd, ".ezcoder/editor-styles"), { recursive: true });
|
|
31
31
|
mkdirSync(join(home, ".ezcoder/editor-styles"), { recursive: true });
|
|
32
32
|
writeFileSync(join(cwd, ".ezcoder/editor-styles/x.md"), "project");
|
|
@@ -36,8 +36,8 @@ describe("discoverStyles", () => {
|
|
|
36
36
|
expect(r[0].origin).toBe("project");
|
|
37
37
|
});
|
|
38
38
|
it("skips empty files", () => {
|
|
39
|
-
const cwd = tmp("
|
|
40
|
-
const home = tmp("
|
|
39
|
+
const cwd = tmp("ez-styles-cwd-");
|
|
40
|
+
const home = tmp("ez-styles-home-");
|
|
41
41
|
mkdirSync(join(home, ".ezcoder/editor-styles"), { recursive: true });
|
|
42
42
|
writeFileSync(join(home, ".ezcoder/editor-styles/empty.md"), " \n \n");
|
|
43
43
|
expect(discoverStyles({ cwd, homeDir: home })).toEqual([]);
|
|
@@ -37,7 +37,7 @@ describe("audit_retention_structure tool", () => {
|
|
|
37
37
|
});
|
|
38
38
|
it("errors on transcript with no segments", async () => {
|
|
39
39
|
process.env.OPENAI_API_KEY = "k";
|
|
40
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
40
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-ars-"));
|
|
41
41
|
writeTranscript(dir, { language: "en", durationSec: 600, segments: [] });
|
|
42
42
|
const tool = createAuditRetentionStructureTool(dir);
|
|
43
43
|
const r = await tool.execute({ transcript: "t.json" }, ctx);
|
|
@@ -45,7 +45,7 @@ describe("audit_retention_structure tool", () => {
|
|
|
45
45
|
});
|
|
46
46
|
it("returns parseable JSON with default checkpoints", async () => {
|
|
47
47
|
process.env.OPENAI_API_KEY = "k";
|
|
48
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
48
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-ars-"));
|
|
49
49
|
writeTranscript(dir, {
|
|
50
50
|
language: "en",
|
|
51
51
|
durationSec: 600,
|
|
@@ -85,7 +85,7 @@ export function createComposeLayeredTool(host, cwd) {
|
|
|
85
85
|
const xml = buildFcpxml({ title, frameRate, width, height, events });
|
|
86
86
|
const outAbs = fcpxmlOutput
|
|
87
87
|
? safeOutputPath(cwd, fcpxmlOutput)
|
|
88
|
-
: join(mkdtempSync(join(tmpdir(), "
|
|
88
|
+
: join(mkdtempSync(join(tmpdir(), "ez-compose-")), "composed.fcpxml");
|
|
89
89
|
if (fcpxmlOutput)
|
|
90
90
|
mkdirSync(dirname(outAbs), { recursive: true });
|
|
91
91
|
writeFileSync(outAbs, xml, "utf8");
|
|
@@ -48,7 +48,7 @@ export function createConcatVideosTool(cwd) {
|
|
|
48
48
|
// concat demuxer: build a list file `file 'path'\n` and feed it.
|
|
49
49
|
// The list file is a temp scratch artifact — clean it up no matter
|
|
50
50
|
// how this branch exits (success, ffmpeg non-zero, or thrown error).
|
|
51
|
-
const listPath = join(tmpdir(), `
|
|
51
|
+
const listPath = join(tmpdir(), `ez-concat-${Date.now()}.txt`);
|
|
52
52
|
const body = buildConcatListBody(absInputs);
|
|
53
53
|
writeFileSync(listPath, body, "utf8");
|
|
54
54
|
try {
|
|
@@ -35,7 +35,7 @@ describe("concat_videos temp-file cleanup", () => {
|
|
|
35
35
|
let workDir;
|
|
36
36
|
beforeEach(() => {
|
|
37
37
|
vi.restoreAllMocks();
|
|
38
|
-
workDir = mkdtempSync(join(tmpdir(), "
|
|
38
|
+
workDir = mkdtempSync(join(tmpdir(), "ez-concat-test-"));
|
|
39
39
|
// Make the inputs and output resolve to real-looking files so the
|
|
40
40
|
// pre-flight identity check doesn't trip.
|
|
41
41
|
writeFileSync(join(workDir, "a.mp4"), "");
|
|
@@ -53,7 +53,7 @@ describe("concat_videos temp-file cleanup", () => {
|
|
|
53
53
|
expect(r).not.toMatch(/^error:/);
|
|
54
54
|
const listPath = captured.current();
|
|
55
55
|
expect(listPath).toBeDefined();
|
|
56
|
-
expect(listPath).toMatch(/
|
|
56
|
+
expect(listPath).toMatch(/ez-concat-/);
|
|
57
57
|
expect(existsSync(listPath)).toBe(false);
|
|
58
58
|
});
|
|
59
59
|
it("writes the concat list before invoking ffmpeg (sanity-check the body)", async () => {
|
|
@@ -149,7 +149,7 @@ export function createCutFillerWordsTool(cwd) {
|
|
|
149
149
|
});
|
|
150
150
|
const outAbs = args.edlOutput
|
|
151
151
|
? safeOutputPath(cwd, args.edlOutput)
|
|
152
|
-
: join(mkdtempSync(join(tmpdir(), "
|
|
152
|
+
: join(mkdtempSync(join(tmpdir(), "ez-fillercut-")), "fillers.edl");
|
|
153
153
|
if (args.edlOutput)
|
|
154
154
|
mkdirSync(dirname(outAbs), { recursive: true });
|
|
155
155
|
writeFileSync(outAbs, edl, "utf8");
|
|
@@ -29,7 +29,7 @@ describe("find_viral_moments tool", () => {
|
|
|
29
29
|
});
|
|
30
30
|
it("errors on empty transcript", async () => {
|
|
31
31
|
process.env.OPENAI_API_KEY = "k";
|
|
32
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
32
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-fvm-"));
|
|
33
33
|
writeTranscript(dir, { language: "en", durationSec: 60, segments: [] });
|
|
34
34
|
const tool = createFindViralMomentsTool(dir);
|
|
35
35
|
const r = await tool.execute({ transcript: "t.json" }, ctx);
|
|
@@ -37,7 +37,7 @@ describe("find_viral_moments tool", () => {
|
|
|
37
37
|
});
|
|
38
38
|
it("errors on durationRange[1] <= durationRange[0]", async () => {
|
|
39
39
|
process.env.OPENAI_API_KEY = "k";
|
|
40
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
40
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-fvm-"));
|
|
41
41
|
writeTranscript(dir, {
|
|
42
42
|
language: "en",
|
|
43
43
|
durationSec: 60,
|
|
@@ -49,7 +49,7 @@ describe("find_viral_moments tool", () => {
|
|
|
49
49
|
});
|
|
50
50
|
it("returns ranked candidates after proposal+score+dedup", async () => {
|
|
51
51
|
process.env.OPENAI_API_KEY = "k";
|
|
52
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
52
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-fvm-"));
|
|
53
53
|
writeTranscript(dir, {
|
|
54
54
|
language: "en",
|
|
55
55
|
durationSec: 200,
|
|
@@ -103,7 +103,7 @@ describe("find_viral_moments tool", () => {
|
|
|
103
103
|
});
|
|
104
104
|
it("threshold drops low-scoring candidates", async () => {
|
|
105
105
|
process.env.OPENAI_API_KEY = "k";
|
|
106
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
106
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-fvm-"));
|
|
107
107
|
writeTranscript(dir, {
|
|
108
108
|
language: "en",
|
|
109
109
|
durationSec: 100,
|
|
@@ -53,7 +53,7 @@ export function createGenerateGifTool(cwd) {
|
|
|
53
53
|
return err(`durationSec ${dur} > 15s`, "GIFs over 15s rarely autoplay; use a smaller window");
|
|
54
54
|
}
|
|
55
55
|
mkdirSync(dirname(outAbs), { recursive: true });
|
|
56
|
-
const palettePath = join(tmpdir(), `
|
|
56
|
+
const palettePath = join(tmpdir(), `ez-gif-palette-${Date.now()}.png`);
|
|
57
57
|
const filterChain = `fps=${fps},scale=${width}:-1:flags=lanczos`;
|
|
58
58
|
// The palette PNG is a temp scratch artifact between the two ffmpeg
|
|
59
59
|
// passes — always clean it up, including on early-return / thrown errors.
|
|
@@ -23,7 +23,7 @@ describe("generate_gif temp-file cleanup", () => {
|
|
|
23
23
|
let workDir;
|
|
24
24
|
beforeEach(() => {
|
|
25
25
|
vi.restoreAllMocks();
|
|
26
|
-
workDir = mkdtempSync(join(tmpdir(), "
|
|
26
|
+
workDir = mkdtempSync(join(tmpdir(), "ez-gif-test-"));
|
|
27
27
|
writeFileSync(join(workDir, "in.mp4"), "");
|
|
28
28
|
vi.spyOn(ffmpegMod, "checkFfmpeg").mockReturnValue(true);
|
|
29
29
|
});
|
|
@@ -46,7 +46,7 @@ describe("generate_gif temp-file cleanup", () => {
|
|
|
46
46
|
const r = await tool.execute({ input: "in.mp4", output: "out.gif" }, ctx);
|
|
47
47
|
expect(r).not.toMatch(/^error:/);
|
|
48
48
|
expect(palettePath).toBeDefined();
|
|
49
|
-
expect(palettePath).toMatch(/
|
|
49
|
+
expect(palettePath).toMatch(/ez-gif-palette-/);
|
|
50
50
|
// ffmpeg ran twice (palettegen + paletteuse).
|
|
51
51
|
expect(call).toBe(2);
|
|
52
52
|
expect(existsSync(palettePath)).toBe(false);
|
|
@@ -37,7 +37,7 @@ describe("generate_youtube_metadata tool", () => {
|
|
|
37
37
|
});
|
|
38
38
|
it("errors on transcript with no segments", async () => {
|
|
39
39
|
process.env.OPENAI_API_KEY = "k";
|
|
40
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
40
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-yt-"));
|
|
41
41
|
writeTranscript(dir, { language: "en", durationSec: 10, segments: [] });
|
|
42
42
|
const tool = createGenerateYouTubeMetadataTool(dir);
|
|
43
43
|
const r = await tool.execute({ transcript: "t.json" }, ctx);
|
|
@@ -45,7 +45,7 @@ describe("generate_youtube_metadata tool", () => {
|
|
|
45
45
|
});
|
|
46
46
|
it("returns parseable JSON on success and drops chapters for short videos", async () => {
|
|
47
47
|
process.env.OPENAI_API_KEY = "k";
|
|
48
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
48
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-yt-"));
|
|
49
49
|
writeTranscript(dir, {
|
|
50
50
|
language: "en",
|
|
51
51
|
durationSec: 120, // < 5 min → chapters dropped
|
|
@@ -79,7 +79,7 @@ describe("generate_youtube_metadata tool", () => {
|
|
|
79
79
|
});
|
|
80
80
|
it("uses json_object response format and temperature 0", async () => {
|
|
81
81
|
process.env.OPENAI_API_KEY = "k";
|
|
82
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
82
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-yt-"));
|
|
83
83
|
writeTranscript(dir, {
|
|
84
84
|
language: "en",
|
|
85
85
|
durationSec: 60,
|
|
@@ -158,7 +158,7 @@ describe("write_ass tool", () => {
|
|
|
158
158
|
const { mkdtempSync, readFileSync } = await import("node:fs");
|
|
159
159
|
const { tmpdir } = await import("node:os");
|
|
160
160
|
const { join } = await import("node:path");
|
|
161
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
161
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-ass-"));
|
|
162
162
|
const tool = createWriteAssTool(dir);
|
|
163
163
|
const r = await tool.execute({
|
|
164
164
|
output: "t.ass",
|
|
@@ -196,7 +196,7 @@ describe("compose_layered tool", () => {
|
|
|
196
196
|
const { mkdtempSync, readFileSync } = await import("node:fs");
|
|
197
197
|
const { tmpdir } = await import("node:os");
|
|
198
198
|
const { join } = await import("node:path");
|
|
199
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
199
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-compose-"));
|
|
200
200
|
const tool = createComposeLayeredTool(new NoneAdapter(), dir);
|
|
201
201
|
const r = await tool.execute({
|
|
202
202
|
title: "t",
|
|
@@ -242,7 +242,7 @@ describe("write_lower_third tool", () => {
|
|
|
242
242
|
const { mkdtempSync, readFileSync } = await import("node:fs");
|
|
243
243
|
const { tmpdir } = await import("node:os");
|
|
244
244
|
const { join } = await import("node:path");
|
|
245
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
245
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-lt-"));
|
|
246
246
|
const tool = createWriteLowerThirdTool(dir);
|
|
247
247
|
const r = await tool.execute({
|
|
248
248
|
output: "lt.ass",
|
|
@@ -270,7 +270,7 @@ describe("write_title_card tool", () => {
|
|
|
270
270
|
const { mkdtempSync, readFileSync } = await import("node:fs");
|
|
271
271
|
const { tmpdir } = await import("node:os");
|
|
272
272
|
const { join } = await import("node:path");
|
|
273
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
273
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-tc-"));
|
|
274
274
|
const tool = createWriteTitleCardTool(dir);
|
|
275
275
|
const r = await tool.execute({
|
|
276
276
|
output: "tc.ass",
|
|
@@ -392,7 +392,7 @@ describe("cut_filler_words tool", () => {
|
|
|
392
392
|
const { mkdtempSync, writeFileSync } = await import("node:fs");
|
|
393
393
|
const { tmpdir } = await import("node:os");
|
|
394
394
|
const { join } = await import("node:path");
|
|
395
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
395
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-fillercut-"));
|
|
396
396
|
const path = join(dir, "transcript.json");
|
|
397
397
|
writeFileSync(path, JSON.stringify({
|
|
398
398
|
language: "en",
|
|
@@ -442,7 +442,7 @@ describe("write_keyword_captions tool", () => {
|
|
|
442
442
|
const { mkdtempSync, writeFileSync, readFileSync } = await import("node:fs");
|
|
443
443
|
const { tmpdir } = await import("node:os");
|
|
444
444
|
const { join } = await import("node:path");
|
|
445
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
445
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-kw-"));
|
|
446
446
|
const transcriptPath = join(dir, "t.json");
|
|
447
447
|
writeFileSync(transcriptPath, JSON.stringify({
|
|
448
448
|
language: "en",
|
|
@@ -474,7 +474,7 @@ describe("write_keyword_captions tool", () => {
|
|
|
474
474
|
const { mkdtempSync, writeFileSync } = await import("node:fs");
|
|
475
475
|
const { tmpdir } = await import("node:os");
|
|
476
476
|
const { join } = await import("node:path");
|
|
477
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
477
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-kw-"));
|
|
478
478
|
const path = join(dir, "t.json");
|
|
479
479
|
writeFileSync(path, JSON.stringify({
|
|
480
480
|
language: "en",
|
|
@@ -83,7 +83,7 @@ vi.mock("../core/frames.js", () => ({
|
|
|
83
83
|
// Helpers
|
|
84
84
|
// ---------------------------------------------------------------------------
|
|
85
85
|
const TRAVERSAL = "../../etc/passwd";
|
|
86
|
-
const SAFE_CWD = "/tmp/
|
|
86
|
+
const SAFE_CWD = "/tmp/ez-test-safe-cwd";
|
|
87
87
|
/** Shared ctx stub accepted by all tool execute() calls. */
|
|
88
88
|
const ctx = {
|
|
89
89
|
signal: new AbortController().signal,
|
|
@@ -8,7 +8,7 @@ import { createReadTranscriptTool } from "./read-transcript.js";
|
|
|
8
8
|
* pull-only-what-you-need lever — wrong filtering blows the context budget.
|
|
9
9
|
*/
|
|
10
10
|
function makeTranscriptFile(t) {
|
|
11
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
11
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-rt-"));
|
|
12
12
|
const path = join(dir, "transcript.json");
|
|
13
13
|
writeFileSync(path, JSON.stringify(t), "utf8");
|
|
14
14
|
return { dir, path };
|
|
@@ -47,7 +47,7 @@ export function createReorderTimelineTool(host, cwd) {
|
|
|
47
47
|
});
|
|
48
48
|
const outAbs = fcpxmlOutput
|
|
49
49
|
? safeOutputPath(cwd, fcpxmlOutput)
|
|
50
|
-
: join(mkdtempSync(join(tmpdir(), "
|
|
50
|
+
: join(mkdtempSync(join(tmpdir(), "ez-reorder-")), "reorder.fcpxml");
|
|
51
51
|
if (fcpxmlOutput)
|
|
52
52
|
mkdirSync(dirname(outAbs), { recursive: true });
|
|
53
53
|
writeFileSync(outAbs, xml, "utf8");
|
|
@@ -42,7 +42,7 @@ describe("score_clip tool", () => {
|
|
|
42
42
|
});
|
|
43
43
|
it("errors on transcript with no segments", async () => {
|
|
44
44
|
process.env.OPENAI_API_KEY = "k";
|
|
45
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
45
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-sc-"));
|
|
46
46
|
writeTranscript(dir, { language: "en", durationSec: 10, segments: [] });
|
|
47
47
|
const tool = createScoreClipTool(dir);
|
|
48
48
|
const r = await tool.execute({ transcript: "t.json", startSec: 0, endSec: 5 }, ctx);
|
|
@@ -50,7 +50,7 @@ describe("score_clip tool", () => {
|
|
|
50
50
|
});
|
|
51
51
|
it("returns a JSON-shaped success when LLM responds correctly", async () => {
|
|
52
52
|
process.env.OPENAI_API_KEY = "k";
|
|
53
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
53
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-sc-"));
|
|
54
54
|
writeTranscript(dir, {
|
|
55
55
|
language: "en",
|
|
56
56
|
durationSec: 60,
|
|
@@ -362,6 +362,6 @@ async function downloadVideo(opts) {
|
|
|
362
362
|
}
|
|
363
363
|
// Re-export for tests that want to seed a tempdir without poking the cwd.
|
|
364
364
|
export function _tempBrollDir() {
|
|
365
|
-
return mkdtempSync(join(tmpdir(), "
|
|
365
|
+
return mkdtempSync(join(tmpdir(), "ez-broll-"));
|
|
366
366
|
}
|
|
367
367
|
//# sourceMappingURL=suggest-broll.js.map
|
|
@@ -20,7 +20,7 @@ const TX = {
|
|
|
20
20
|
],
|
|
21
21
|
};
|
|
22
22
|
function makeTranscriptFile(t) {
|
|
23
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
23
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-sbr-"));
|
|
24
24
|
const path = join(dir, "transcript.json");
|
|
25
25
|
writeFileSync(path, JSON.stringify(t), "utf8");
|
|
26
26
|
return { dir, path };
|
|
@@ -99,13 +99,13 @@ describe("suggest_broll", () => {
|
|
|
99
99
|
vi.doUnmock("../core/auth/api-keys.js");
|
|
100
100
|
});
|
|
101
101
|
it("errors when transcript file is missing", async () => {
|
|
102
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
102
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-sbr-"));
|
|
103
103
|
const tool = createSuggestBrollTool(dir);
|
|
104
104
|
const r = (await tool.execute({ transcript: "nope.json" }, ctx));
|
|
105
105
|
expect(r).toMatch(/^error: cannot read transcript/);
|
|
106
106
|
});
|
|
107
107
|
it("errors when transcript is malformed JSON", async () => {
|
|
108
|
-
const dir = mkdtempSync(join(tmpdir(), "
|
|
108
|
+
const dir = mkdtempSync(join(tmpdir(), "ez-sbr-"));
|
|
109
109
|
writeFileSync(join(dir, "t.json"), "{not json", "utf8");
|
|
110
110
|
const tool = createSuggestBrollTool(dir);
|
|
111
111
|
const r = (await tool.execute({ transcript: "t.json" }, ctx));
|
|
@@ -175,7 +175,7 @@ describe("suggest_broll", () => {
|
|
|
175
175
|
expect(parsed.skipped[0].reason).toMatch(/no Pexels match/);
|
|
176
176
|
});
|
|
177
177
|
it("downloads to outDir when download=true and writes the file", async () => {
|
|
178
|
-
const downloadDir = mkdtempSync(join(tmpdir(), "
|
|
178
|
+
const downloadDir = mkdtempSync(join(tmpdir(), "ez-sbr-out-"));
|
|
179
179
|
const fakeBytes = Buffer.from("FAKE_VIDEO_BYTES");
|
|
180
180
|
const fetchMock = vi
|
|
181
181
|
.fn()
|
|
@@ -143,7 +143,7 @@ export function createTextBasedCutTool(cwd) {
|
|
|
143
143
|
});
|
|
144
144
|
const outAbs = args.edlOutput
|
|
145
145
|
? safeOutputPath(cwd, args.edlOutput)
|
|
146
|
-
: join(mkdtempSync(join(tmpdir(), "
|
|
146
|
+
: join(mkdtempSync(join(tmpdir(), "ez-textcut-")), "cuts.edl");
|
|
147
147
|
if (args.edlOutput)
|
|
148
148
|
mkdirSync(dirname(outAbs), { recursive: true });
|
|
149
149
|
writeFileSync(outAbs, edl, "utf8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prestyj/editor",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.62",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI video editor agent. Drives DaVinci Resolve and Premiere Pro via API + hotkeys + GUI fallback.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"react": "^19.2.5",
|
|
36
36
|
"ws": "^8.18.0",
|
|
37
37
|
"zod": "^4.4.3",
|
|
38
|
-
"@prestyj/
|
|
39
|
-
"@prestyj/
|
|
40
|
-
"@prestyj/
|
|
38
|
+
"@prestyj/agent": "5.13.0",
|
|
39
|
+
"@prestyj/ai": "5.13.0",
|
|
40
|
+
"@prestyj/cli": "5.13.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^25.6.0",
|