@martini-film/cli 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.
package/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # @martini-film/cli
2
+
3
+ The Martini command-line interface for agents and scripts. Every tool the Martini MCP server exposes is a
4
+ command with the same name; on top, a handful of compound commands do what no single tool does — upload local
5
+ files, download and measure assets, block until work settles, edit project memory files as a directory, and sign
6
+ in. One HTTPS request per call, a static key, no MCP session.
7
+
8
+ ```bash
9
+ npx @martini-film/cli --help # or: pnpm add -g @martini-film/cli → martini
10
+ martini login # pair this device through the browser (90-day key)
11
+ martini get_board_overview --project <id> # any MCP tool, flags from its arguments
12
+ martini get_asset --asset-id <id> --fields asset.status,asset.imageUrl
13
+ martini upload ./ref.png ./take.mp4 --canvas <id>
14
+ martini create_node_and_generate --canvas-id <id> --prompt "…" --reference-images <url> --wait
15
+ martini wait <asset-id…> # resume a wait; exit 4 with the pending ids on timeout
16
+ martini files pull ./memory && martini files push ./memory
17
+ martini probe <path|asset-id>… # duration, resolution, fps, codecs, sha256 (needs ffprobe)
18
+ ```
19
+
20
+ ## How commands are generated
21
+
22
+ `martini <tool>` exists for every entry of the tool manifest (`src/generated/manifest.json`), which the backend
23
+ exports from its MCP registry (`pnpm --dir backend run export:tool-manifest`) and drift-tests against the live
24
+ registry. Flags are derived from each tool's JSON Schema: `assetId` becomes `--asset-id`, arrays repeat the flag
25
+ (or take a JSON list), objects take JSON, and `--json '{…}'` / `--json @args.json` passes the whole arguments
26
+ object — so a plan a script computed is submitted without retyping it. `martini <tool> --help` prints the tool's
27
+ own description, every flag with its type and whether it is required, and one example.
28
+
29
+ `projectId`, `canvasId`, and `runId` are filled from context when a tool takes them and the caller did not say:
30
+ `--project` / `--canvas` / `--run`, else `MARTINI_PROJECT_ID` / `MARTINI_CANVAS_ID` / `MARTINI_RUN_ID`, else the
31
+ config file.
32
+
33
+ ## Credentials and context
34
+
35
+ Most specific first:
36
+
37
+ 1. Flags: `--api-key`, `--api-url`, `--profile`.
38
+ 2. Environment: `MARTINI_API_KEY`, `MARTINI_API_URL`, `MARTINI_PROFILE`, `MARTINI_CONFIG_FILE`.
39
+ 3. The nearest `.martini/config.json` above the working directory — what a workflow run's sandbox has.
40
+ 4. `~/.config/martini/config.json` — the profiles `martini login` saves, one per organization, with a default.
41
+
42
+ A workflow run's sandbox therefore needs nothing but its working directory; a laptop needs one `martini login`;
43
+ a script sets `MARTINI_API_KEY`. A raw Martini API key (`mtn_live_…`) always works.
44
+
45
+ ## Output and exit codes
46
+
47
+ Results are JSON on stdout — compact when piped, indented on a terminal. `--fields a,b.c` keeps only those
48
+ dotted paths, applied on the server so a large listing never crosses the wire. `--out <path>` writes the result
49
+ (or, with `--raw`, the media bytes of tools like `view_asset`) to a file and prints one summary line. `--quiet`
50
+ prints nothing on success. Errors are one JSON object on stderr: `{ "error": { "code", "message", "hint", "tool",
51
+ "exitCode" } }`, with the tool's own MCP error code (`ASSET_NOT_READY`, `NODE_NOT_FOUND`, …).
52
+
53
+ | Exit | Meaning |
54
+ | ---- | -------------------------------------------- |
55
+ | 0 | ok |
56
+ | 1 | the tool failed |
57
+ | 2 | usage: unknown command, missing or bad flags |
58
+ | 3 | no key, or the key is invalid / expired |
59
+ | 4 | not ready or timed out (pending ids named) |
60
+ | 5 | insufficient olives |
61
+
62
+ ## Waiting
63
+
64
+ Generation and rendering are asynchronous. `--wait` blocks until the produced assets (or the render) settle and
65
+ adds `waited` to the result; it is on by default for single-item generation and rendering tools and off for batch
66
+ tools, where you fan out and then `martini wait <ids…>` once. `--timeout <seconds>` (default 50, under the 60 s a
67
+ sandbox command has) ends the wait with exit 4 and the pending ids, so the next command can resume it.
68
+
69
+ ## Compound commands
70
+
71
+ | Command | Does |
72
+ | ------------------------------------ | ----------------------------------------------------------------------------------------------------- |
73
+ | `login`, `logout`, `whoami` | device-code pairing, forget a profile, who the CLI acts as |
74
+ | `tools`, `models` | the manifest this build knows (and whether the server has a newer one); the cached model catalog |
75
+ | `upload <paths…>` | prepare → PUT → complete from local files, then wait for processing |
76
+ | `download <ids…>` | presigned URL → bytes → file |
77
+ | `wait <ids…> \| --job \| --run \| --render` | block until assets, a job, a run, or a render settles |
78
+ | `files ls\|cat\|write\|pull\|push` | project memory files as a directory; `push` refuses a file edited server-side since the pull |
79
+ | `probe <path\|id>…` | ffprobe + sha256 in one JSON report |
80
+ | `init [--write]` | the AGENTS.md snippet that teaches a repo's agents to use the CLI |
81
+
82
+ ## Inside a workflow run
83
+
84
+ The sandbox of a Martini workflow run carries a run key in `.martini/config.json`, written when the run's agent
85
+ environment opens and revoked when it closes. Calls made with it go through the run's own supervisor — the same
86
+ budgets, spend fences, and trace as the run's tool calls — and the tool set is the run's. A run that is not
87
+ executing answers `RUN_NOT_ACTIVE` (exit 4).
88
+
89
+ ## Single-file binary
90
+
91
+ `pnpm run build:binary` compiles `dist/bin.js` into `dist/martini-linux-x64` with Bun for environments without
92
+ Node (the agent-environment sandbox). Bun is only needed on the build machine. Every `cli-v<version>` tag builds
93
+ it in CI and publishes it at `https://downloads.martini.film/cli-releases/<version>/martini-linux-x64`
94
+ (`.github/workflows/cli-release.yml`); the npm package is published by hand (`AGENTS.md` → Releasing).
95
+
96
+ Docs: <https://www.martini.film/docs/cli>.
package/dist/api.js ADDED
@@ -0,0 +1,160 @@
1
+ /**
2
+ * The wire: one HTTPS request per call against the API-key surface —
3
+ * `POST /v1/tools/{name}` for every tool, `/v1/tools` for the manifest,
4
+ * `/v1/me`, and the two login routes. Static key, no session. The CLI names
5
+ * itself with `X-Martini-Client` and a User-Agent that also carries the host
6
+ * agent it runs inside, so analytics can tell "the CLI under Claude Code" from
7
+ * "Claude Code over MCP".
8
+ */
9
+ import { detectHostAgent } from './host.js';
10
+ export const CLI_VERSION = '0.1.0';
11
+ export class CliApiError extends Error {
12
+ code;
13
+ status;
14
+ tool;
15
+ constructor(message, details) {
16
+ super(message);
17
+ this.name = 'CliApiError';
18
+ this.code = details.code;
19
+ this.status = details.status;
20
+ this.tool = details.tool ?? null;
21
+ }
22
+ }
23
+ export function userAgent(env = process.env) {
24
+ const host = detectHostAgent(env);
25
+ return `martini-cli/${CLI_VERSION}${host ? ` (${host})` : ''}`;
26
+ }
27
+ export function createApiClient(config, options = {}) {
28
+ const fetchImpl = options.fetch ?? fetch;
29
+ const env = options.env ?? process.env;
30
+ function headers(extra = {}) {
31
+ const base = {
32
+ 'User-Agent': userAgent(env),
33
+ 'X-Martini-Client': `martini-cli/${CLI_VERSION}`,
34
+ ...extra,
35
+ };
36
+ if (config.apiKey)
37
+ base.Authorization = `Bearer ${config.apiKey}`;
38
+ return base;
39
+ }
40
+ async function readError(response, tool) {
41
+ const text = await response.text();
42
+ let body = {};
43
+ try {
44
+ body = JSON.parse(text);
45
+ }
46
+ catch {
47
+ body = { error: text };
48
+ }
49
+ const message = typeof body.error === 'string' && body.error ? body.error : `Request failed (${response.status})`;
50
+ return new CliApiError(message, {
51
+ code: typeof body.code === 'string' ? body.code : 'REQUEST_FAILED',
52
+ status: response.status,
53
+ tool: typeof body.tool === 'string' ? body.tool : (tool ?? null),
54
+ });
55
+ }
56
+ function requireKey() {
57
+ if (!config.apiKey) {
58
+ throw new CliApiError('No Martini API key. Run martini login, or set MARTINI_API_KEY.', {
59
+ code: 'NO_API_KEY',
60
+ status: 0,
61
+ });
62
+ }
63
+ }
64
+ async function requestJson(path, init = {}) {
65
+ const response = await fetchImpl(`${config.apiUrl}${path}`, {
66
+ ...init,
67
+ headers: headers({
68
+ ...(init.body ? { 'Content-Type': 'application/json' } : {}),
69
+ ...init.headers,
70
+ }),
71
+ });
72
+ if (!response.ok)
73
+ throw await readError(response, init.tool);
74
+ if (response.status === 204)
75
+ return undefined;
76
+ return (await response.json());
77
+ }
78
+ return {
79
+ config,
80
+ /** `POST /v1/tools/{name}` → the tool's JSON result. */
81
+ async callTool(name, args, options = {}) {
82
+ requireKey();
83
+ const query = new URLSearchParams();
84
+ if (options.select?.length)
85
+ query.set('select', options.select.join(','));
86
+ const suffix = query.size > 0 ? `?${query}` : '';
87
+ return requestJson(`/v1/tools/${encodeURIComponent(name)}${suffix}`, {
88
+ method: 'POST',
89
+ body: JSON.stringify(args),
90
+ tool: name,
91
+ ...(options.signal ? { signal: options.signal } : {}),
92
+ });
93
+ },
94
+ /** `POST /v1/tools/{name}?format=raw` → the media bytes of a single-media result. */
95
+ async callToolRaw(name, args) {
96
+ requireKey();
97
+ const response = await fetchImpl(`${config.apiUrl}/v1/tools/${encodeURIComponent(name)}?format=raw`, {
98
+ method: 'POST',
99
+ headers: headers({ 'Content-Type': 'application/json' }),
100
+ body: JSON.stringify(args),
101
+ });
102
+ if (!response.ok)
103
+ throw await readError(response, name);
104
+ const metaHeader = response.headers.get('x-martini-tool-result');
105
+ let meta = null;
106
+ if (metaHeader) {
107
+ try {
108
+ meta = JSON.parse(metaHeader);
109
+ }
110
+ catch {
111
+ meta = metaHeader;
112
+ }
113
+ }
114
+ return {
115
+ bytes: new Uint8Array(await response.arrayBuffer()),
116
+ contentType: response.headers.get('content-type') ?? 'application/octet-stream',
117
+ meta,
118
+ };
119
+ },
120
+ async listTools() {
121
+ requireKey();
122
+ return requestJson('/v1/tools', { method: 'GET' });
123
+ },
124
+ async me() {
125
+ requireKey();
126
+ return requestJson('/v1/me', { method: 'GET' });
127
+ },
128
+ async startLogin(deviceLabel) {
129
+ return requestJson('/v1/cli/login', { method: 'POST', body: JSON.stringify({ deviceLabel }) });
130
+ },
131
+ async pollLogin(pollToken) {
132
+ return requestJson(`/v1/cli/login/${encodeURIComponent(pollToken)}`, { method: 'GET' });
133
+ },
134
+ /** A plain GET of an absolute URL (presigned downloads), with no Martini headers. */
135
+ async fetchBytes(url) {
136
+ const response = await fetchImpl(url);
137
+ if (!response.ok) {
138
+ throw new CliApiError(`Download failed (${response.status}).`, {
139
+ code: 'DOWNLOAD_FAILED',
140
+ status: response.status,
141
+ });
142
+ }
143
+ return {
144
+ bytes: new Uint8Array(await response.arrayBuffer()),
145
+ contentType: response.headers.get('content-type') ?? 'application/octet-stream',
146
+ };
147
+ },
148
+ /** A plain PUT of bytes to a presigned URL with the exact headers the server signed. */
149
+ async putBytes(url, bytes, putHeaders) {
150
+ const response = await fetchImpl(url, { method: 'PUT', headers: putHeaders, body: bytes });
151
+ if (!response.ok) {
152
+ throw new CliApiError(`Upload PUT failed (${response.status}).`, {
153
+ code: 'UPLOAD_PUT_FAILED',
154
+ status: response.status,
155
+ });
156
+ }
157
+ },
158
+ };
159
+ }
160
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
package/dist/args.js ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Argument parsing without a framework: `martini <command> [positionals] [--flag value | --flag=value | --bool]`.
3
+ * Repeated flags collect into arrays. Everything after `--` is positional.
4
+ */
5
+ export function parseArgs(argv) {
6
+ const flags = new Map();
7
+ const positionals = [];
8
+ let command;
9
+ let onlyPositionals = false;
10
+ const push = (name, value) => {
11
+ const existing = flags.get(name);
12
+ if (existing === undefined) {
13
+ flags.set(name, value);
14
+ return;
15
+ }
16
+ if (value === true)
17
+ return;
18
+ if (existing === true) {
19
+ flags.set(name, value);
20
+ return;
21
+ }
22
+ flags.set(name, Array.isArray(existing) ? [...existing, value] : [existing, value]);
23
+ };
24
+ for (let i = 0; i < argv.length; i += 1) {
25
+ const arg = argv[i];
26
+ if (onlyPositionals) {
27
+ positionals.push(arg);
28
+ continue;
29
+ }
30
+ if (arg === '--') {
31
+ onlyPositionals = true;
32
+ continue;
33
+ }
34
+ if (arg.startsWith('--')) {
35
+ const body = arg.slice(2);
36
+ const eq = body.indexOf('=');
37
+ if (eq >= 0) {
38
+ push(body.slice(0, eq), body.slice(eq + 1));
39
+ continue;
40
+ }
41
+ if (body.startsWith('no-')) {
42
+ push(body.slice(3), 'false');
43
+ continue;
44
+ }
45
+ const next = argv[i + 1];
46
+ if (next !== undefined && !next.startsWith('--')) {
47
+ push(body, next);
48
+ i += 1;
49
+ }
50
+ else {
51
+ push(body, true);
52
+ }
53
+ continue;
54
+ }
55
+ if (command === undefined)
56
+ command = arg;
57
+ else
58
+ positionals.push(arg);
59
+ }
60
+ return { command, positionals, flags };
61
+ }
62
+ /** One value for a flag, or undefined; an array flag yields its last value. */
63
+ export function flagString(flags, name) {
64
+ const value = flags.get(name);
65
+ if (value === undefined || value === true)
66
+ return undefined;
67
+ return Array.isArray(value) ? value[value.length - 1] : value;
68
+ }
69
+ export function flagBoolean(flags, name) {
70
+ const value = flags.get(name);
71
+ if (value === undefined)
72
+ return undefined;
73
+ if (value === true)
74
+ return true;
75
+ const last = Array.isArray(value) ? value[value.length - 1] : value;
76
+ return last !== 'false' && last !== '0' && last !== 'no';
77
+ }
78
+ export function flagList(flags, name) {
79
+ const value = flags.get(name);
80
+ if (value === undefined || value === true)
81
+ return [];
82
+ return Array.isArray(value) ? value : [value];
83
+ }
84
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
package/dist/bin.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { main } from './cli.js';
3
+ const code = await main({ argv: process.argv.slice(2) });
4
+ process.exitCode = code;
5
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAE/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;AACxD,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAA"}
package/dist/cli.js ADDED
@@ -0,0 +1,163 @@
1
+ /**
2
+ * The dispatcher. A command is either one of the compound commands (what no
3
+ * single tool does) or any tool from the manifest by its MCP name — the same
4
+ * vocabulary agents already know from the MCP, so nothing has to be translated
5
+ * (docs/plans/agent-cli.md, decision 18).
6
+ */
7
+ import { createApiClient } from './api.js';
8
+ import { flagBoolean, flagString, parseArgs } from './args.js';
9
+ import { download, upload, wait } from './commands/assets.js';
10
+ import { selectedFields, timeoutMs, wantsWait } from './commands/context.js';
11
+ import { files } from './commands/files.js';
12
+ import { login, logout, whoami } from './commands/login.js';
13
+ import { init, models, probe, tools, version } from './commands/tools.js';
14
+ import { resolveConfig } from './config.js';
15
+ import { renderHelp, renderToolHelp } from './help.js';
16
+ import { findTool, loadManifest } from './manifest.js';
17
+ import { EXIT, printBytes, printError, printResult } from './output.js';
18
+ import { ArgumentError, buildArguments } from './schema.js';
19
+ import { producedAssetIds, waitForAssets, waitForDelivery } from './wait.js';
20
+ export const COMPOUND_COMMANDS = [
21
+ login,
22
+ logout,
23
+ whoami,
24
+ tools,
25
+ models,
26
+ upload,
27
+ download,
28
+ wait,
29
+ files,
30
+ probe,
31
+ init,
32
+ version,
33
+ ];
34
+ /** Flags the dispatcher owns; a tool never sees them as arguments. */
35
+ export const GLOBAL_FLAG_NAMES = new Set([
36
+ 'help',
37
+ 'version',
38
+ 'fields',
39
+ 'out',
40
+ 'wait',
41
+ 'timeout',
42
+ 'quiet',
43
+ 'raw',
44
+ 'project',
45
+ 'canvas',
46
+ 'run',
47
+ 'api-key',
48
+ 'api-url',
49
+ 'profile',
50
+ ]);
51
+ /** Single-item generation and rendering block by default; batches fan out and `martini wait` later (decision 5). */
52
+ const WAIT_BY_DEFAULT = new Set([
53
+ 'create_node_and_generate',
54
+ 'generate',
55
+ 'render_timeline',
56
+ 'enhance_draft',
57
+ 'upscale_assets',
58
+ 'render_blender_take',
59
+ ]);
60
+ const RENDER_TOOLS = new Set(['render_timeline']);
61
+ export async function main(options) {
62
+ const env = options.env ?? process.env;
63
+ const cwd = options.cwd ?? process.cwd();
64
+ const output = {
65
+ ...(options.stdout ? { stdout: options.stdout } : {}),
66
+ ...(options.stderr ? { stderr: options.stderr } : {}),
67
+ ...(options.isTTY !== undefined ? { isTTY: options.isTTY } : {}),
68
+ };
69
+ const parsed = parseArgs(options.argv);
70
+ const manifest = options.manifest ?? loadManifest();
71
+ try {
72
+ if (parsed.command === undefined ||
73
+ parsed.command === 'help' ||
74
+ (flagBoolean(parsed.flags, 'help') && !parsed.command)) {
75
+ printResult(renderHelp(manifest, COMPOUND_COMMANDS), output);
76
+ return EXIT.ok;
77
+ }
78
+ if (parsed.command === '--version' || (flagBoolean(parsed.flags, 'version') && parsed.command === undefined)) {
79
+ parsed.command = 'version';
80
+ }
81
+ const compound = COMPOUND_COMMANDS.find(command => command.name === parsed.command);
82
+ const tool = compound ? undefined : findTool(parsed.command, manifest);
83
+ if (!compound && !tool) {
84
+ throw new ArgumentError(`Unknown command "${parsed.command}". Run martini --help for the list.`);
85
+ }
86
+ if (flagBoolean(parsed.flags, 'help')) {
87
+ printResult(tool ? renderToolHelp(tool) : `${compound.usage}\n\n${compound.summary}\n`, output);
88
+ return EXIT.ok;
89
+ }
90
+ const config = resolveConfig(parsed.flags, { env, cwd });
91
+ const client = (options.createClient ??
92
+ (resolved => createApiClient(resolved, { ...(options.fetch ? { fetch: options.fetch } : {}), env })))(config);
93
+ const out = flagString(parsed.flags, 'out');
94
+ if (out)
95
+ output.out = out;
96
+ output.quiet = flagBoolean(parsed.flags, 'quiet') ?? false;
97
+ const context = {
98
+ client,
99
+ config,
100
+ manifest,
101
+ flags: parsed.flags,
102
+ positionals: parsed.positionals,
103
+ output,
104
+ env,
105
+ cwd,
106
+ now: options.now ?? Date.now,
107
+ sleep: options.sleep ?? (ms => new Promise(resolve => setTimeout(resolve, ms))),
108
+ };
109
+ if (compound) {
110
+ const result = await compound.run(context);
111
+ printResult(result, output);
112
+ return EXIT.ok;
113
+ }
114
+ printResult(await runTool(tool, context, parsed.flags), output);
115
+ return EXIT.ok;
116
+ }
117
+ catch (error) {
118
+ return printError(error, output);
119
+ }
120
+ }
121
+ async function runTool(tool, context, flags) {
122
+ const args = buildArguments(tool, flags, {
123
+ ignore: GLOBAL_FLAG_NAMES,
124
+ context: {
125
+ ...(context.config.projectId ? { projectId: context.config.projectId } : {}),
126
+ ...(context.config.canvasId ? { canvasId: context.config.canvasId } : {}),
127
+ ...(context.config.runId ? { runId: context.config.runId } : {}),
128
+ },
129
+ });
130
+ if (flagBoolean(flags, 'raw')) {
131
+ const raw = await context.client.callToolRaw(tool.name, args);
132
+ printBytes(raw.bytes, { ...context.output, contentType: raw.contentType });
133
+ // The bytes are the result; nothing else goes to the file or stdout.
134
+ delete context.output.out;
135
+ context.output.quiet = true;
136
+ return raw.meta;
137
+ }
138
+ const select = selectedFields(context);
139
+ const result = await context.client.callTool(tool.name, args, select.length ? { select } : {});
140
+ if (!wantsWait(context, WAIT_BY_DEFAULT.has(tool.name)))
141
+ return result;
142
+ const projectId = typeof args.projectId === 'string' ? args.projectId : context.config.projectId;
143
+ if (!projectId)
144
+ return result;
145
+ const waitOptions = { timeoutMs: timeoutMs(context), now: context.now, sleep: context.sleep };
146
+ if (RENDER_TOOLS.has(tool.name)) {
147
+ const renderId = result?.renderId;
148
+ if (typeof renderId === 'string') {
149
+ const delivery = await waitForDelivery(context.client, projectId, { renderId }, waitOptions);
150
+ return { ...result, delivery };
151
+ }
152
+ return result;
153
+ }
154
+ const ids = producedAssetIds(result);
155
+ if (ids.length === 0)
156
+ return result;
157
+ const assets = await waitForAssets(context.client, projectId, ids, waitOptions);
158
+ return {
159
+ ...(typeof result === 'object' && result ? result : { result }),
160
+ waited: assets,
161
+ };
162
+ }
163
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}