agent-screenplay 0.0.0-stage → 0.1.0

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.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +141 -2
  3. package/assets/editor/index.html +536 -0
  4. package/assets/fonts/Inter-Bold.ttf +0 -0
  5. package/assets/fonts/Inter-LICENSE.txt +92 -0
  6. package/assets/fonts/Inter-Medium.ttf +0 -0
  7. package/assets/fonts/Inter-Regular.ttf +0 -0
  8. package/assets/fonts/Inter-SemiBold.ttf +0 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +163 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/core.d.ts +16 -0
  13. package/dist/core.js +73 -0
  14. package/dist/core.js.map +1 -0
  15. package/dist/direct/plan.d.ts +100 -0
  16. package/dist/direct/plan.js +274 -0
  17. package/dist/direct/plan.js.map +1 -0
  18. package/dist/drivers/browser.d.ts +9 -0
  19. package/dist/drivers/browser.js +44 -0
  20. package/dist/drivers/browser.js.map +1 -0
  21. package/dist/drivers/desktop.d.ts +53 -0
  22. package/dist/drivers/desktop.js +650 -0
  23. package/dist/drivers/desktop.js.map +1 -0
  24. package/dist/drivers/pace.d.ts +11 -0
  25. package/dist/drivers/pace.js +44 -0
  26. package/dist/drivers/pace.js.map +1 -0
  27. package/dist/drivers/web.d.ts +37 -0
  28. package/dist/drivers/web.js +570 -0
  29. package/dist/drivers/web.js.map +1 -0
  30. package/dist/editor/server.d.ts +96 -0
  31. package/dist/editor/server.js +303 -0
  32. package/dist/editor/server.js.map +1 -0
  33. package/dist/ffmpeg.d.ts +5 -0
  34. package/dist/ffmpeg.js +44 -0
  35. package/dist/ffmpeg.js.map +1 -0
  36. package/dist/guide.d.ts +6 -0
  37. package/dist/guide.js +25 -0
  38. package/dist/guide.js.map +1 -0
  39. package/dist/init.d.ts +19 -0
  40. package/dist/init.js +147 -0
  41. package/dist/init.js.map +1 -0
  42. package/dist/login.d.ts +2 -0
  43. package/dist/login.js +50 -0
  44. package/dist/login.js.map +1 -0
  45. package/dist/mcp/server.d.ts +1 -0
  46. package/dist/mcp/server.js +132 -0
  47. package/dist/mcp/server.js.map +1 -0
  48. package/dist/render/compose.d.ts +68 -0
  49. package/dist/render/compose.js +361 -0
  50. package/dist/render/compose.js.map +1 -0
  51. package/dist/render/presets.d.ts +42 -0
  52. package/dist/render/presets.js +111 -0
  53. package/dist/render/presets.js.map +1 -0
  54. package/dist/render/render.d.ts +25 -0
  55. package/dist/render/render.js +257 -0
  56. package/dist/render/render.js.map +1 -0
  57. package/dist/render/sources.d.ts +15 -0
  58. package/dist/render/sources.js +146 -0
  59. package/dist/render/sources.js.map +1 -0
  60. package/dist/render/style.d.ts +37 -0
  61. package/dist/render/style.js +118 -0
  62. package/dist/render/style.js.map +1 -0
  63. package/dist/scenario/config.d.ts +43 -0
  64. package/dist/scenario/config.js +69 -0
  65. package/dist/scenario/config.js.map +1 -0
  66. package/dist/scenario/fingerprint.d.ts +10 -0
  67. package/dist/scenario/fingerprint.js +58 -0
  68. package/dist/scenario/fingerprint.js.map +1 -0
  69. package/dist/scenario/load.d.ts +36 -0
  70. package/dist/scenario/load.js +101 -0
  71. package/dist/scenario/load.js.map +1 -0
  72. package/dist/scenario/schema.d.ts +553 -0
  73. package/dist/scenario/schema.js +262 -0
  74. package/dist/scenario/schema.js.map +1 -0
  75. package/dist/scenario/target.d.ts +26 -0
  76. package/dist/scenario/target.js +40 -0
  77. package/dist/scenario/target.js.map +1 -0
  78. package/dist/take.d.ts +100 -0
  79. package/dist/take.js +15 -0
  80. package/dist/take.js.map +1 -0
  81. package/dist/version.d.ts +1 -0
  82. package/dist/version.js +2 -0
  83. package/dist/version.js.map +1 -0
  84. package/dist/voice/cartesia.d.ts +12 -0
  85. package/dist/voice/cartesia.js +103 -0
  86. package/dist/voice/cartesia.js.map +1 -0
  87. package/package.json +65 -4
  88. package/schema/scenario.schema.json +1098 -0
  89. package/skills/screenplay/SKILL.md +127 -0
package/dist/init.js ADDED
@@ -0,0 +1,147 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { createRequire } from "node:module";
5
+ import { spawnSync } from "node:child_process";
6
+ import { isChromiumInstalled } from "./drivers/browser.js";
7
+ import { ffmpegPath } from "./ffmpeg.js";
8
+ import { packageRoot, skillFile } from "./guide.js";
9
+ const require = createRequire(import.meta.url);
10
+ function onPath(cmd) {
11
+ const probe = spawnSync(process.platform === "win32" ? "where" : "which", [cmd], { stdio: "ignore" });
12
+ return probe.status === 0;
13
+ }
14
+ /** How agents should start the MCP server: from npm, or from this checkout when not installed from npm. */
15
+ export function mcpCommand() {
16
+ const root = packageRoot();
17
+ if (fs.existsSync(path.join(root, ".git"))) {
18
+ return { command: process.execPath, args: [path.join(root, "dist", "cli.js"), "mcp"] };
19
+ }
20
+ // The npm package is agent-screenplay ("screenplay" belongs to someone else on npm).
21
+ return { command: "npx", args: ["-y", "agent-screenplay", "mcp"] };
22
+ }
23
+ export async function init(opts = {}) {
24
+ const log = opts.log ?? (() => { });
25
+ const home = opts.home ?? os.homedir();
26
+ const report = { done: [], skipped: [], warnings: [] };
27
+ const act = (what, fn) => {
28
+ if (opts.dryRun) {
29
+ report.done.push(`(dry run) ${what}`);
30
+ return;
31
+ }
32
+ try {
33
+ fn();
34
+ report.done.push(what);
35
+ }
36
+ catch (e) {
37
+ report.warnings.push(`${what}: ${e.message}`);
38
+ }
39
+ };
40
+ // 1. Chromium for web recordings.
41
+ if (opts.browser !== false) {
42
+ if (isChromiumInstalled())
43
+ report.skipped.push("Chromium already installed");
44
+ else {
45
+ log("Downloading Chromium (once)…");
46
+ act("Installed Chromium for web recordings", () => {
47
+ const cli = path.join(path.dirname(require.resolve("playwright-core/package.json")), "cli.js");
48
+ const r = spawnSync(process.execPath, [cli, "install", "chromium"], { stdio: "inherit" });
49
+ if (r.status !== 0)
50
+ throw new Error("the download failed; run `npx playwright install chromium`, or set SCREENPLAY_CHROME to an installed Chrome");
51
+ });
52
+ }
53
+ }
54
+ // 2. ffmpeg.
55
+ try {
56
+ ffmpegPath();
57
+ }
58
+ catch (e) {
59
+ report.warnings.push(e.message);
60
+ }
61
+ // 3. MCP server in the agents found on this machine.
62
+ if (opts.mcp !== false) {
63
+ const { command, args } = mcpCommand();
64
+ const found = [];
65
+ if (onPath("claude")) {
66
+ found.push("Claude Code");
67
+ const exists = spawnSync("claude", ["mcp", "get", "screenplay"], { stdio: "ignore" }).status === 0;
68
+ if (exists)
69
+ report.skipped.push("Claude Code already has the screenplay MCP server");
70
+ else
71
+ act("Added the MCP server to Claude Code (user scope)", () => {
72
+ const r = spawnSync("claude", ["mcp", "add", "--scope", "user", "screenplay", "--", command, ...args], { encoding: "utf8" });
73
+ if (r.status !== 0)
74
+ throw new Error(r.stderr || "claude mcp add failed");
75
+ });
76
+ }
77
+ const codexDir = path.join(home, ".codex");
78
+ if (onPath("codex") || fs.existsSync(codexDir)) {
79
+ found.push("Codex");
80
+ const file = path.join(codexDir, "config.toml");
81
+ const current = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
82
+ if (/^\[mcp_servers\.screenplay\]/m.test(current))
83
+ report.skipped.push("Codex already has the screenplay MCP server");
84
+ else
85
+ act(`Added the MCP server to Codex (${file})`, () => {
86
+ fs.mkdirSync(codexDir, { recursive: true });
87
+ const block = [
88
+ "",
89
+ "[mcp_servers.screenplay]",
90
+ `command = ${JSON.stringify(command)}`,
91
+ `args = [${args.map((a) => JSON.stringify(a)).join(", ")}]`,
92
+ "# Filming and editing a video takes longer than the default tool timeout.",
93
+ "tool_timeout_sec = 900",
94
+ "",
95
+ ].join("\n");
96
+ fs.writeFileSync(file, current.replace(/\s*$/, "\n") + block);
97
+ });
98
+ }
99
+ const cursorDir = path.join(home, ".cursor");
100
+ if (fs.existsSync(cursorDir)) {
101
+ found.push("Cursor");
102
+ const file = path.join(cursorDir, "mcp.json");
103
+ let json = {};
104
+ if (fs.existsSync(file)) {
105
+ try {
106
+ json = JSON.parse(fs.readFileSync(file, "utf8"));
107
+ }
108
+ catch {
109
+ report.warnings.push(`${file} is not valid JSON: add the screenplay server by hand`);
110
+ json = { mcpServers: { screenplay: true } };
111
+ }
112
+ }
113
+ if (json.mcpServers?.screenplay)
114
+ report.skipped.push("Cursor already has the screenplay MCP server");
115
+ else
116
+ act(`Added the MCP server to Cursor (${file})`, () => {
117
+ json.mcpServers = { ...(json.mcpServers ?? {}), screenplay: { command, args } };
118
+ fs.writeFileSync(file, JSON.stringify(json, null, 2) + "\n");
119
+ });
120
+ }
121
+ if (found.length === 0) {
122
+ report.warnings.push(`No agent found (Claude Code, Codex, Cursor). Add the MCP server by hand: command "${command}", args ${JSON.stringify(args)}.`);
123
+ }
124
+ }
125
+ // 4. The guide as a skill, for agents that load skills from disk.
126
+ if (opts.skill !== false) {
127
+ const targets = [
128
+ { dir: path.join(home, ".claude"), name: "Claude Code" },
129
+ { dir: path.join(home, ".codex"), name: "Codex" },
130
+ ];
131
+ for (const t of targets) {
132
+ if (!fs.existsSync(t.dir))
133
+ continue;
134
+ const dest = path.join(t.dir, "skills", "screenplay", "SKILL.md");
135
+ act(`Installed the screenplay skill for ${t.name} (${dest})`, () => {
136
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
137
+ fs.copyFileSync(skillFile(), dest);
138
+ });
139
+ }
140
+ }
141
+ // 5. Desktop recordings need OS permissions on macOS.
142
+ if (process.platform === "darwin") {
143
+ report.warnings.push("For desktop apps on macOS, allow your terminal (or agent app) in System Settings → Privacy & Security → Screen Recording and → Accessibility. Web recordings need nothing.");
144
+ }
145
+ return report;
146
+ }
147
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Open a visible browser on `url`, let a person sign in, and save the session for scenarios (`auth.storageState`). */
2
+ export declare function login(url: string, out: string, log?: (msg: string) => void): Promise<string>;
package/dist/login.js ADDED
@@ -0,0 +1,50 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import readline from "node:readline";
4
+ import { launchBrowser } from "./drivers/browser.js";
5
+ /** Open a visible browser on `url`, let a person sign in, and save the session for scenarios (`auth.storageState`). */
6
+ export async function login(url, out, log = () => { }) {
7
+ if (process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
8
+ throw new Error("`screenplay login` opens a visible browser, and this machine has no screen. Log in with steps in the scenario instead (type ${EMAIL} / ${PASSWORD} with secret: true), or run login on a computer with a screen and copy the session file.");
9
+ }
10
+ const file = path.resolve(out);
11
+ const browser = await launchBrowser({ headless: false });
12
+ const context = await browser.newContext({ viewport: null });
13
+ const page = await context.newPage();
14
+ await page.goto(url);
15
+ log(`Sign in in the browser window, then press Enter here (or close the window).`);
16
+ let last;
17
+ const poll = setInterval(async () => {
18
+ try {
19
+ last = await context.storageState();
20
+ }
21
+ catch {
22
+ /* closing */
23
+ }
24
+ }, 1500);
25
+ await new Promise((resolve) => {
26
+ const rl = readline.createInterface({ input: process.stdin });
27
+ rl.once("line", () => {
28
+ rl.close();
29
+ resolve();
30
+ });
31
+ browser.once("disconnected", () => {
32
+ rl.close();
33
+ resolve();
34
+ });
35
+ });
36
+ clearInterval(poll);
37
+ try {
38
+ last = await context.storageState();
39
+ }
40
+ catch {
41
+ /* the window was closed: keep the last saved state */
42
+ }
43
+ await browser.close().catch(() => { });
44
+ if (!last)
45
+ throw new Error("No session was captured.");
46
+ fs.mkdirSync(path.dirname(file), { recursive: true });
47
+ fs.writeFileSync(file, JSON.stringify(last, null, 2), { mode: 0o600 });
48
+ return file;
49
+ }
50
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../src/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,uHAAuH;AACvH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,GAAW,EAAE,GAAW,EAAE,GAAG,GAA0B,GAAG,EAAE,GAAE,CAAC;IACzF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;QACzF,MAAM,IAAI,KAAK,CACb,4OAA4O,CAC7O,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACrC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrB,GAAG,CAAC,6EAA6E,CAAC,CAAC;IACnF,IAAI,IAAkE,CAAC;IACvE,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAClC,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,aAAa;QACf,CAAC;IACH,CAAC,EAAE,IAAI,CAAC,CAAC;IACT,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9D,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;YACnB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,EAAE;YAChC,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,aAAa,CAAC,IAAI,CAAC,CAAC;IACpB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;IACxD,CAAC;IACD,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function startMcpServer(): Promise<void>;
@@ -0,0 +1,132 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { loadImage, createCanvas } from "@napi-rs/canvas";
6
+ import { z } from "zod";
7
+ import { check, record, render } from "../core.js";
8
+ import { guideText } from "../guide.js";
9
+ import { parseScenario } from "../scenario/load.js";
10
+ import { VERSION } from "../version.js";
11
+ const INSTRUCTIONS = `Screenplay makes Screen Studio-quality screen recordings (smooth cursor, auto-zoom, callouts, captions, optional voice-over) from a JSON scenario you write.
12
+ Before your first recording, call screenplay_guide and follow it: explore the app, write the scenario, screenplay_check until it plays to the end, screenplay_record, look at the returned storyboard, fix, and re-run (screenplay_render when only text/style/zoom changed).`;
13
+ const PathArg = z
14
+ .string()
15
+ .describe("Path of the scenario JSON file. Prefer an absolute path; a relative one is resolved from the server's working directory.");
16
+ const ScenarioArg = z
17
+ .record(z.string(), z.unknown())
18
+ .optional()
19
+ .describe("Optional scenario object: validated, then written to `path` (overwriting that file), then used.");
20
+ const SIDE_EFFECTS = " It really performs the steps in the app (a click on Send sends, a click on Delete deletes): use a demo account or a staging environment.";
21
+ // One recording at a time: each one runs a browser and a video encoder.
22
+ let queue = Promise.resolve();
23
+ function serialize(job) {
24
+ const run = queue.then(job, job);
25
+ queue = run.catch(() => { });
26
+ return run;
27
+ }
28
+ function resolvePath(p, scenario) {
29
+ const abs = path.resolve(process.cwd(), p);
30
+ if (scenario) {
31
+ parseScenario(scenario); // never overwrite a file with an invalid scenario
32
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
33
+ fs.writeFileSync(abs, JSON.stringify(scenario, null, 2) + "\n");
34
+ }
35
+ return abs;
36
+ }
37
+ async function imageContent(file, maxWidth = 1600) {
38
+ const img = await loadImage(fs.readFileSync(file));
39
+ const k = Math.min(1, maxWidth / img.width);
40
+ const c = createCanvas(Math.round(img.width * k), Math.round(img.height * k));
41
+ c.getContext("2d").drawImage(img, 0, 0, c.width, c.height);
42
+ const data = (await c.encode("jpeg", 82)).toString("base64");
43
+ return { type: "image", data, mimeType: "image/jpeg" };
44
+ }
45
+ function errorResult(e) {
46
+ return { isError: true, content: [{ type: "text", text: e instanceof Error ? e.message : String(e) }] };
47
+ }
48
+ function progressLogger(extra) {
49
+ const token = extra._meta?.progressToken;
50
+ let n = 0;
51
+ return (msg) => {
52
+ if (token === undefined)
53
+ return;
54
+ extra.sendNotification({ method: "notifications/progress", params: { progressToken: token, progress: ++n, message: msg } }).catch(() => { });
55
+ };
56
+ }
57
+ export async function startMcpServer() {
58
+ const server = new McpServer({ name: "screenplay", version: VERSION }, { instructions: INSTRUCTIONS });
59
+ server.registerTool("screenplay_guide", {
60
+ title: "How to make a good screen recording",
61
+ description: "The guide to writing Screenplay scenarios: the loop, targets, steps, style, voice-over and direction tips. Read it before the first recording.",
62
+ annotations: { readOnlyHint: true },
63
+ }, async () => ({ content: [{ type: "text", text: guideText() }] }));
64
+ server.registerTool("screenplay_check", {
65
+ title: "Check a scenario",
66
+ description: "Play the scenario quickly without filming. Reports each step; for a missing element, lists the visible targets you can use instead, with a screenshot of where it stopped." +
67
+ SIDE_EFFECTS,
68
+ inputSchema: { path: PathArg, scenario: ScenarioArg },
69
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
70
+ }, async ({ path: p, scenario }, extra) => serialize(async () => {
71
+ try {
72
+ const file = resolvePath(p, scenario);
73
+ const report = await check(file, { log: progressLogger(extra) });
74
+ const content = [{ type: "text", text: JSON.stringify(report, null, 2) }];
75
+ if (report.screenshot && fs.existsSync(report.screenshot))
76
+ content.push(await imageContent(report.screenshot, 1280));
77
+ return { content, isError: !report.ok };
78
+ }
79
+ catch (e) {
80
+ return errorResult(e);
81
+ }
82
+ }));
83
+ const recordArgs = {
84
+ path: PathArg,
85
+ scenario: ScenarioArg,
86
+ gif: z.boolean().optional().describe("Also write a GIF."),
87
+ noVoice: z.boolean().optional().describe("Skip the voice-over even if the scenario enables it."),
88
+ };
89
+ server.registerTool("screenplay_record", {
90
+ title: "Film and edit a scenario",
91
+ description: "Film the scenario and edit the video. Returns the MP4 path and the storyboard (one image per step): look at it and fix framing, bubbles or data before handing the video over. Takes about the length of the video plus a few seconds per 10 seconds of video." +
92
+ SIDE_EFFECTS,
93
+ inputSchema: recordArgs,
94
+ annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: true },
95
+ }, async ({ path: p, scenario, gif, noVoice }, extra) => serialize(async () => {
96
+ try {
97
+ const file = resolvePath(p, scenario);
98
+ const r = await record(file, { gif, noVoice, log: progressLogger(extra) });
99
+ return {
100
+ content: [
101
+ { type: "text", text: JSON.stringify({ mp4: r.mp4, gif: r.gif, storyboard: r.storyboard, duration: Number(r.duration.toFixed(1)), steps: r.steps }, null, 2) },
102
+ await imageContent(r.storyboard),
103
+ ],
104
+ };
105
+ }
106
+ catch (e) {
107
+ return errorResult(e);
108
+ }
109
+ }));
110
+ server.registerTool("screenplay_render", {
111
+ title: "Edit the last recording again",
112
+ description: "Re-edit the last recording of this scenario without filming: use it after changing text, narration (say), callouts, style, zoom or output. Changing actions needs screenplay_record. Does not touch the app; writes the video files, and sends new narration text to Cartesia when the scenario enables voice-over.",
113
+ inputSchema: recordArgs,
114
+ annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true },
115
+ }, async ({ path: p, scenario, gif, noVoice }, extra) => serialize(async () => {
116
+ try {
117
+ const file = resolvePath(p, scenario);
118
+ const r = await render(file, { gif, noVoice, log: progressLogger(extra) });
119
+ return {
120
+ content: [
121
+ { type: "text", text: JSON.stringify({ mp4: r.mp4, gif: r.gif, storyboard: r.storyboard, duration: Number(r.duration.toFixed(1)) }, null, 2) },
122
+ await imageContent(r.storyboard),
123
+ ],
124
+ };
125
+ }
126
+ catch (e) {
127
+ return errorResult(e);
128
+ }
129
+ }));
130
+ await server.connect(new StdioServerTransport());
131
+ }
132
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { type Canvas, type Image, type SKRSContext2D } from "@napi-rs/canvas";
2
+ import type { Annotation, Camera, Caption } from "../direct/plan.js";
3
+ import type { Point } from "../take.js";
4
+ import { type ResolvedStyle } from "./style.js";
5
+ export interface Layout {
6
+ OW: number;
7
+ OH: number;
8
+ /** Unit for sizes: 1 at 1080p. */
9
+ k: number;
10
+ window: {
11
+ x: number;
12
+ y: number;
13
+ w: number;
14
+ h: number;
15
+ };
16
+ content: {
17
+ x: number;
18
+ y: number;
19
+ w: number;
20
+ h: number;
21
+ };
22
+ barH: number;
23
+ }
24
+ export declare function computeLayout(OW: number, OH: number, W: number, H: number, style: ResolvedStyle): Layout;
25
+ /** Background, shadow and window chrome: drawn once, reused for every frame. */
26
+ export declare function buildStaticLayer(layout: Layout, style: ResolvedStyle, url?: string): Canvas;
27
+ export interface CaptureFrame {
28
+ image: Image | Canvas;
29
+ sx: number;
30
+ sy: number;
31
+ sw: number;
32
+ sh: number;
33
+ }
34
+ export interface FrameState {
35
+ o: number;
36
+ camera: Camera;
37
+ cursor?: {
38
+ p: Point;
39
+ alpha: number;
40
+ press: number;
41
+ };
42
+ ripples: Array<{
43
+ p: Point;
44
+ u: number;
45
+ }>;
46
+ annotations: Array<{
47
+ a: Annotation;
48
+ inU: number;
49
+ outU: number;
50
+ }>;
51
+ caption?: {
52
+ c: Caption;
53
+ alpha: number;
54
+ };
55
+ }
56
+ /** Draw one recorded frame with the camera, overlays and cursor. */
57
+ export declare function drawCapture(ctx: SKRSContext2D, layout: Layout, style: ResolvedStyle, staticLayer: Canvas, frame: CaptureFrame, W: number, H: number, st: FrameState): void;
58
+ /** Full-screen title or end card. `u` is the time since it appeared (seconds). */
59
+ export declare function drawCard(ctx: SKRSContext2D, layout: Layout, style: ResolvedStyle, bgLayer: Canvas, card: {
60
+ kind: "title" | "end";
61
+ title: string;
62
+ subtitle?: string;
63
+ }, u: number, alpha?: number): void;
64
+ /** macOS-style arrow, or a soft dot. `size` is 1 at 1080p. */
65
+ export declare function drawCursor(ctx: SKRSContext2D, kind: "macos" | "dot", p: Point, size: number, alpha: number): void;
66
+ export declare function wrap(ctx: SKRSContext2D, text: string, maxW: number): string[];
67
+ export declare function easeOut(t: number): number;
68
+ export declare function clamp01(t: number): number;