@pixerate/editor 0.139.1 → 0.140.1
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 +25 -4
- package/dist/agent/formatTools.d.cts +15 -0
- package/dist/agent/formatTools.d.ts +15 -0
- package/dist/agent/index.cjs +408 -49
- package/dist/agent/index.js +375 -16
- package/dist/agent/providers.d.cts +5 -3
- package/dist/agent/providers.d.ts +5 -3
- package/dist/animation-editor/effect-tools.d.cts +1 -1
- package/dist/animation-editor/effect-tools.d.ts +1 -1
- package/dist/animation-editor/index.cjs +250 -116
- package/dist/animation-editor/index.js +228 -94
- package/dist/animation-editor/instructions.d.cts +1 -1
- package/dist/animation-editor/instructions.d.ts +1 -1
- package/dist/animation-editor/parse.d.cts +3 -1
- package/dist/animation-editor/parse.d.ts +3 -1
- package/dist/animation-editor/tools.d.cts +8 -3
- package/dist/animation-editor/tools.d.ts +8 -3
- package/dist/bridge/cli.cjs +4 -3
- package/dist/bridge/cli.js +3 -2
- package/dist/bridge/index.cjs +8 -3
- package/dist/bridge/index.d.cts +7 -0
- package/dist/bridge/index.d.ts +7 -0
- package/dist/bridge/index.js +9 -4
- package/dist/bridge/skills.d.cts +9 -0
- package/dist/bridge/skills.d.ts +9 -0
- package/dist/canvas/effect-tools.d.cts +1 -1
- package/dist/canvas/effect-tools.d.ts +1 -1
- package/dist/canvas/index.cjs +22 -17
- package/dist/canvas/index.js +8 -3
- package/dist/chart/file-tools.d.cts +1 -1
- package/dist/chart/file-tools.d.ts +1 -1
- package/dist/chart/index.cjs +7 -1
- package/dist/chart/index.js +7 -1
- package/dist/chart/tools.d.cts +1 -1
- package/dist/chart/tools.d.ts +1 -1
- package/dist/chunk-2BSBFBOA.cjs +46 -0
- package/dist/{chunk-SWZTQWY7.js → chunk-2INPJDNY.js} +1 -1
- package/dist/{chunk-CCKP4XAN.cjs → chunk-34RQAGWI.cjs} +27 -7
- package/dist/{chunk-HXCBQ7A6.cjs → chunk-3AJMR7EG.cjs} +7 -4
- package/dist/{chunk-BKMU3V6K.js → chunk-5ED73EC6.js} +8 -1
- package/dist/{chunk-NKBUVQJW.cjs → chunk-5WOY52O6.cjs} +15 -15
- package/dist/{chunk-VRIR53SW.js → chunk-6GAYGQDC.js} +10 -8
- package/dist/{chunk-HZZXBTLB.js → chunk-6IN474P4.js} +25 -5
- package/dist/{chunk-KHMVB3SJ.js → chunk-7KWJEYIK.js} +4 -1
- package/dist/{chunk-R47NQICB.cjs → chunk-AGCD3EHB.cjs} +47 -10
- package/dist/{chunk-6I63VZ45.js → chunk-CXXKJBQZ.js} +5 -1
- package/dist/{chunk-6NXVDJDR.cjs → chunk-G43MNQ4C.cjs} +5 -5
- package/dist/chunk-HDK3T2QS.cjs +1159 -0
- package/dist/chunk-HF5QZS7Z.js +46 -0
- package/dist/{chunk-S7I3RI5Z.cjs → chunk-HMGWFXEC.cjs} +27 -24
- package/dist/{chunk-6NCBFBXA.js → chunk-IQ6KKXOU.js} +1 -1
- package/dist/{chunk-T6Y5FV7G.cjs → chunk-L434J57V.cjs} +10 -8
- package/dist/{chunk-UCRL6JEV.cjs → chunk-L5OWG2NA.cjs} +8 -3
- package/dist/{chunk-CZRWP6IW.cjs → chunk-N2FGYZ4Q.cjs} +8 -1
- package/dist/{chunk-GUPQ5BNA.cjs → chunk-PUR6BZFA.cjs} +112 -111
- package/dist/chunk-RB62U6MS.js +1159 -0
- package/dist/{chunk-3V746PF4.cjs → chunk-RUZQMYXH.cjs} +4 -1
- package/dist/{chunk-HGHXGCKG.cjs → chunk-SVFEVKLF.cjs} +1 -1
- package/dist/{chunk-PCNCT4ZY.js → chunk-UMS6YFA6.js} +40 -3
- package/dist/{chunk-4LGWAJDI.js → chunk-V5OOP74P.js} +5 -2
- package/dist/{chunk-BWT4IWLK.cjs → chunk-VKF3PWKR.cjs} +7 -7
- package/dist/{chunk-PQMADRCI.js → chunk-WBJ6BG4R.js} +23 -22
- package/dist/{chunk-WIYAOZZU.js → chunk-WHKNYFM2.js} +7 -2
- package/dist/{chunk-TBSPPVTT.js → chunk-XCK7QK5D.js} +1 -1
- package/dist/{chunk-F652BKMS.cjs → chunk-YN6JKAUE.cjs} +6 -2
- package/dist/{chunk-YTGF4TJR.js → chunk-ZLZKGHSZ.js} +5 -2
- package/dist/{chunk-USU2FL3N.js → chunk-ZNHB5RG6.js} +1 -1
- package/dist/commands/agentTools.d.cts +1 -1
- package/dist/commands/agentTools.d.ts +1 -1
- package/dist/commands/index.cjs +3 -0
- package/dist/commands/index.js +3 -0
- package/dist/compare/index.cjs +4 -3
- package/dist/compare/index.js +3 -2
- package/dist/diagram/index.cjs +3 -0
- package/dist/diagram/index.js +3 -0
- package/dist/diagram/tools.d.cts +1 -1
- package/dist/diagram/tools.d.ts +1 -1
- package/dist/effects/index.cjs +32 -32
- package/dist/effects/index.js +1 -1
- package/dist/effects/tools.d.cts +5 -1
- package/dist/effects/tools.d.ts +5 -1
- package/dist/export/index.cjs +4 -3
- package/dist/export/index.js +3 -2
- package/dist/extensions/index.cjs +11 -8
- package/dist/extensions/index.d.cts +1 -0
- package/dist/extensions/index.d.ts +1 -0
- package/dist/extensions/index.js +10 -7
- package/dist/extensions/safe-merge-attributes.d.cts +10 -0
- package/dist/extensions/safe-merge-attributes.d.ts +10 -0
- package/dist/generation/index.cjs +7 -1
- package/dist/generation/index.js +7 -1
- package/dist/image-editor/index.cjs +25 -18
- package/dist/image-editor/index.js +10 -3
- package/dist/image-editor/provider-effect-tools.d.cts +1 -1
- package/dist/image-editor/provider-effect-tools.d.ts +1 -1
- package/dist/image-editor/tools.d.cts +1 -1
- package/dist/image-editor/tools.d.ts +1 -1
- package/dist/index.cjs +42 -29
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +22 -9
- package/dist/paint-editor/effect-tools.d.cts +1 -1
- package/dist/paint-editor/effect-tools.d.ts +1 -1
- package/dist/paint-editor/index.cjs +18 -8
- package/dist/paint-editor/index.js +13 -3
- package/dist/paint-editor/tools.d.cts +1 -1
- package/dist/paint-editor/tools.d.ts +1 -1
- package/dist/persistence/index.cjs +3 -2
- package/dist/persistence/index.js +2 -1
- package/dist/serializers/index.cjs +5 -4
- package/dist/serializers/index.js +4 -3
- package/dist/tools/bridge-client.d.cts +3 -3
- package/dist/tools/bridge-client.d.ts +3 -3
- package/dist/tools/capture.d.cts +5 -1
- package/dist/tools/capture.d.ts +5 -1
- package/dist/tools/definitions.d.cts +2 -2
- package/dist/tools/definitions.d.ts +2 -2
- package/dist/tools/index.cjs +39 -5
- package/dist/tools/index.d.cts +4 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +39 -5
- package/dist/tools/mcp-server.d.cts +24 -6
- package/dist/tools/mcp-server.d.ts +24 -6
- package/dist/tools/registry.d.cts +81 -6
- package/dist/tools/registry.d.ts +81 -6
- package/dist/tools/safe-json.d.cts +27 -0
- package/dist/tools/safe-json.d.ts +27 -0
- package/dist/tools/search.d.cts +30 -0
- package/dist/tools/search.d.ts +30 -0
- package/dist/tools/skills.d.cts +26 -0
- package/dist/tools/skills.d.ts +26 -0
- package/dist/tools/view.d.cts +95 -0
- package/dist/tools/view.d.ts +95 -0
- package/dist/vector/effect-tools.d.cts +1 -1
- package/dist/vector/effect-tools.d.ts +1 -1
- package/dist/vector/index.cjs +13 -7
- package/dist/vector/index.js +8 -2
- package/dist/video-editor/effect-tools.d.cts +1 -1
- package/dist/video-editor/effect-tools.d.ts +1 -1
- package/dist/video-editor/index.cjs +275 -269
- package/dist/video-editor/index.js +8 -2
- package/dist/video-editor/tools.d.cts +1 -1
- package/dist/video-editor/tools.d.ts +1 -1
- package/package.json +31 -29
- package/skills/README.md +8 -3
- package/skills/pixerate-agent-tools/SKILL.md +33 -7
- package/skills/pixerate-animation-editor/SKILL.md +7 -0
- package/skills/pixerate-rich-text/SKILL.md +18 -4
- package/dist/chunk-5RRYDFU2.js +0 -466
- package/dist/chunk-SPVIXXIB.cjs +0 -466
- /package/dist/{chunk-SMJK5HBJ.js → chunk-K73HMKQP.js} +0 -0
- /package/dist/{chunk-DDF6WQ62.cjs → chunk-LACYURUW.cjs} +0 -0
|
@@ -343,7 +343,10 @@ function createEffectToolProvider(host) {
|
|
|
343
343
|
];
|
|
344
344
|
return {
|
|
345
345
|
id: host.id,
|
|
346
|
-
...host.namespace ? { namespace: host.namespace } : {},
|
|
346
|
+
...host.namespace !== void 0 ? { namespace: host.namespace } : {},
|
|
347
|
+
...host.title ? { title: host.title } : {},
|
|
348
|
+
...host.description ? { description: host.description } : {},
|
|
349
|
+
...host.skill ? { skill: host.skill } : {},
|
|
347
350
|
tools: () => {
|
|
348
351
|
const extra = _nullishCoalesce(_optionalChain([host, 'access', _5 => _5.extraTools, 'optionalCall', _6 => _6(context)]), () => ( []));
|
|
349
352
|
if (host.readOnlyReason()) return [...readTools(), ...extra.filter((t) => _optionalChain([t, 'access', _7 => _7.annotations, 'optionalAccess', _8 => _8.readOnlyHint]))];
|
|
@@ -287,7 +287,7 @@ var MCP_TOOL_CANVAS_LAYOUT = {
|
|
|
287
287
|
name: "canvas_layout",
|
|
288
288
|
title: "Lay out the canvas",
|
|
289
289
|
annotations: { title: "Lay out the canvas", ...IDEMPOTENT_ANNOTATIONS },
|
|
290
|
-
description: "Arranges the canvas graph
|
|
290
|
+
description: "Arranges the canvas nodes automatically in a layered graph layout that follows the edges, so nodes line up and do not overlap. Nodes that already have a position stay put unless incremental is false.",
|
|
291
291
|
inputSchema: {
|
|
292
292
|
type: "object",
|
|
293
293
|
properties: {
|
|
@@ -3,12 +3,41 @@ import {
|
|
|
3
3
|
TOOL_BRIDGE_PROTOCOL,
|
|
4
4
|
ToolRegistry,
|
|
5
5
|
createMcpServer
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RB62U6MS.js";
|
|
7
7
|
|
|
8
8
|
// src/bridge/index.ts
|
|
9
9
|
import { createServer } from "http";
|
|
10
10
|
import { createInterface } from "readline";
|
|
11
11
|
|
|
12
|
+
// src/bridge/skills.ts
|
|
13
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
14
|
+
import { dirname, join, relative, sep } from "path";
|
|
15
|
+
import { fileURLToPath } from "url";
|
|
16
|
+
function defaultSkillsDir() {
|
|
17
|
+
let dir = typeof __dirname === "string" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
for (let i = 0; i < 5; i++) {
|
|
19
|
+
const candidate = join(dir, "skills");
|
|
20
|
+
if (existsSync(join(candidate, "pixerate-agent-tools", "SKILL.md"))) return candidate;
|
|
21
|
+
const parent = dirname(dir);
|
|
22
|
+
if (parent === dir) break;
|
|
23
|
+
dir = parent;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function loadSkillFiles(dir = defaultSkillsDir()) {
|
|
28
|
+
const files = {};
|
|
29
|
+
if (!dir || !existsSync(dir)) return files;
|
|
30
|
+
const walk = (current) => {
|
|
31
|
+
for (const name of readdirSync(current)) {
|
|
32
|
+
const path = join(current, name);
|
|
33
|
+
if (statSync(path).isDirectory()) walk(path);
|
|
34
|
+
else if (name.endsWith(".md") && current !== dir) files[relative(dir, path).split(sep).join("/")] = readFileSync(path, "utf8");
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
walk(dir);
|
|
38
|
+
return files;
|
|
39
|
+
}
|
|
40
|
+
|
|
12
41
|
// src/bridge/websocket.ts
|
|
13
42
|
import { createHash } from "crypto";
|
|
14
43
|
var GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
@@ -163,7 +192,8 @@ var EDITOR_ARG = {
|
|
|
163
192
|
type: "string",
|
|
164
193
|
description: 'Editor id (e.g. "e1") or part of its name, from list_editors. Default: the most recently active editor that has this tool.'
|
|
165
194
|
};
|
|
166
|
-
var BRIDGE_INSTRUCTIONS = "Tools come from editors open in a browser. Call list_editors to see them; when several are open, pass `editor` (an id or part of a name) to pick one, otherwise the most recently active editor that has the tool answers. If no editor is connected, ask the user to open the app and connect it to the bridge.";
|
|
195
|
+
var BRIDGE_INSTRUCTIONS = "Tools come from editors open in a browser. Call list_editors to see them; when several are open, pass `editor` (an id or part of a name) to pick one, otherwise the most recently active editor that has the tool answers. If no editor is connected, ask the user to open the app and connect it to the bridge. Tool names are `<toolset>__<tool>`; when an editor offers list_toolsets and search_tools, use them to find tools that are not listed yet.";
|
|
196
|
+
var SKILL_INSTRUCTIONS = "Each editor's tools are documented by an agent skill (pixerate-chart, pixerate-video-editor, ...), served here as MCP prompts and as resources at skill://<skill>/SKILL.md. Read pixerate-agent-tools and the skill for the editor at hand before working with its tools.";
|
|
167
197
|
async function createToolBridge(options) {
|
|
168
198
|
const log = options.log ?? ((message) => process.stderr.write(`[${options.name}] ${message}
|
|
169
199
|
`));
|
|
@@ -251,6 +281,8 @@ async function createToolBridge(options) {
|
|
|
251
281
|
};
|
|
252
282
|
registry.register({
|
|
253
283
|
id: "bridge",
|
|
284
|
+
// Forwarded tools keep the names their pages gave them.
|
|
285
|
+
namespace: "",
|
|
254
286
|
tools: () => [listEditors, ...forwardedTools()],
|
|
255
287
|
subscribe: (notify) => {
|
|
256
288
|
listeners.add(notify);
|
|
@@ -347,10 +379,13 @@ async function createToolBridge(options) {
|
|
|
347
379
|
let output = null;
|
|
348
380
|
const write = (message) => output?.write(`${JSON.stringify(message)}
|
|
349
381
|
`);
|
|
382
|
+
const skills = options.skills === false ? {} : options.skills ?? loadSkillFiles();
|
|
383
|
+
const hasSkills = Object.keys(skills).length > 0;
|
|
350
384
|
const mcp = createMcpServer(registry, {
|
|
351
385
|
name: options.name,
|
|
352
386
|
version: options.version ?? "0.1.0",
|
|
353
|
-
instructions: [options.instructions, BRIDGE_INSTRUCTIONS].filter(Boolean).join("\n\n"),
|
|
387
|
+
instructions: [options.instructions, BRIDGE_INSTRUCTIONS, hasSkills ? SKILL_INSTRUCTIONS : ""].filter(Boolean).join("\n\n"),
|
|
388
|
+
...hasSkills ? { skills } : {},
|
|
354
389
|
send: write
|
|
355
390
|
});
|
|
356
391
|
let lines = null;
|
|
@@ -395,6 +430,8 @@ async function createToolBridge(options) {
|
|
|
395
430
|
}
|
|
396
431
|
|
|
397
432
|
export {
|
|
433
|
+
defaultSkillsDir,
|
|
434
|
+
loadSkillFiles,
|
|
398
435
|
isLocalOrigin,
|
|
399
436
|
createToolBridge
|
|
400
437
|
};
|
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
createReviewId,
|
|
8
8
|
getTrackedChanges,
|
|
9
9
|
resolveTrackedChanges
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-6IN474P4.js";
|
|
11
|
+
import {
|
|
12
|
+
stripPrototypeKeys
|
|
13
|
+
} from "./chunk-HF5QZS7Z.js";
|
|
11
14
|
|
|
12
15
|
// src/compare/diff.ts
|
|
13
16
|
var EQUAL = 0;
|
|
@@ -286,7 +289,7 @@ function toNode(source, schema) {
|
|
|
286
289
|
const node = source;
|
|
287
290
|
return node.type.schema === schema ? node : schema.nodeFromJSON(node.toJSON());
|
|
288
291
|
}
|
|
289
|
-
return schema.nodeFromJSON(source);
|
|
292
|
+
return schema.nodeFromJSON(stripPrototypeKeys(source));
|
|
290
293
|
}
|
|
291
294
|
function newAttributes(ctx) {
|
|
292
295
|
return {
|
|
@@ -7,7 +7,7 @@ var _chunkPY4GWSE2cjs = require('./chunk-PY4GWSE2.cjs');
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkRUZQMYXHcjs = require('./chunk-RUZQMYXH.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
var _chunkWOFXZ3XUcjs = require('./chunk-WOFXZ3XU.cjs');
|
|
@@ -1174,12 +1174,12 @@ function videoEffectLayerKey(layer, width, height) {
|
|
|
1174
1174
|
}
|
|
1175
1175
|
function mixEffectPixels(a, b, k) {
|
|
1176
1176
|
if (k >= 1) return b;
|
|
1177
|
-
const out =
|
|
1177
|
+
const out = _chunkRUZQMYXHcjs.createEffectPixels.call(void 0, a.width, a.height);
|
|
1178
1178
|
for (let i = 0; i < out.data.length; i++) out.data[i] = a.data[i] + (b.data[i] - a.data[i]) * k;
|
|
1179
1179
|
return out;
|
|
1180
1180
|
}
|
|
1181
1181
|
function overEffectPixels(base, top, opacity = 1) {
|
|
1182
|
-
const out =
|
|
1182
|
+
const out = _chunkRUZQMYXHcjs.createEffectPixels.call(void 0, base.width, base.height);
|
|
1183
1183
|
const o = out.data;
|
|
1184
1184
|
const b = base.data;
|
|
1185
1185
|
const t = top.data;
|
|
@@ -1224,7 +1224,7 @@ var VideoEffectsEngine = (_class2 = class {
|
|
|
1224
1224
|
__init10() {this.generation = 0}
|
|
1225
1225
|
|
|
1226
1226
|
constructor(options = {}) {;_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this);_class2.prototype.__init7.call(this);_class2.prototype.__init8.call(this);_class2.prototype.__init9.call(this);_class2.prototype.__init10.call(this);
|
|
1227
|
-
this.slot = _nullishCoalesce(options.slot, () => ( new (0,
|
|
1227
|
+
this.slot = _nullishCoalesce(options.slot, () => ( new (0, _chunkRUZQMYXHcjs.EffectsSlot)()));
|
|
1228
1228
|
this.maxEntries = _nullishCoalesce(options.maxEntries, () => ( 120));
|
|
1229
1229
|
this.toImage = _nullishCoalesce(options.toImage, () => ( defaultToImage));
|
|
1230
1230
|
this.pool = new (0, _chunkPY4GWSE2cjs.EffectRendererPool)({ maxRenderers: options.maxRenderers });
|
|
@@ -1366,7 +1366,7 @@ function checkVideoEffectPlace(d, place) {
|
|
|
1366
1366
|
if (d.kind === "motion" || !d.uses.some((u) => allowed.includes(u))) {
|
|
1367
1367
|
const where = place === "clip" ? "on a clip" : place === "transition" ? "as a transition" : "as an effect clip";
|
|
1368
1368
|
const instead = d.uses.includes("transition") ? "set_video_effect_transition" : d.uses.some((u) => VIDEO_EFFECT_PLACES.generator.includes(u)) ? "add_video_effect_clip" : d.uses.some((u) => u === "filter") ? "apply_effect" : null;
|
|
1369
|
-
throw new (0,
|
|
1369
|
+
throw new (0, _chunkRUZQMYXHcjs.EffectUnsupportedError)(
|
|
1370
1370
|
`"${d.id}" (${d.name}) is a ${d.uses.join(" / ")} effect and cannot be used ${where}, which takes ${allowed.join(" or ")} effects${instead ? `; use ${instead} instead` : ""}. search_effects with use "${allowed[0]}" lists ones that fit.`,
|
|
1371
1371
|
d.id
|
|
1372
1372
|
);
|
|
@@ -1387,12 +1387,12 @@ function checkVideoEffectValues(d, values, options = {}) {
|
|
|
1387
1387
|
else if (type !== "number" && type !== "integer") errors.push({ path: `/${k}`, message: "only number controls can be keyframed." });
|
|
1388
1388
|
else for (const [i, key] of v.keys.entries()) for (const e of _chunkWOFXZ3XUcjs.validateJsonSchema.call(void 0, key.v, schema)) errors.push({ path: `/${k}/keys/${i}/v`, message: e.message });
|
|
1389
1389
|
}
|
|
1390
|
-
for (const e of
|
|
1390
|
+
for (const e of _chunkRUZQMYXHcjs.effectValueErrors.call(void 0, d, plain)) {
|
|
1391
1391
|
const name = e.path.split("/")[1];
|
|
1392
1392
|
const about = name && _optionalChain([d, 'access', _46 => _46.controls, 'access', _47 => _47.properties, 'access', _48 => _48[name], 'optionalAccess', _49 => _49.description]);
|
|
1393
1393
|
errors.push(about ? { path: e.path, message: `${e.message} (${about})` } : e);
|
|
1394
1394
|
}
|
|
1395
|
-
if (errors.length) throw new (0,
|
|
1395
|
+
if (errors.length) throw new (0, _chunkRUZQMYXHcjs.EffectControlError)(d.id, errors);
|
|
1396
1396
|
return { ..._nullishCoalesce(options.base, () => ( d.defaults)), ..._nullishCoalesce(values, () => ( {})) };
|
|
1397
1397
|
}
|
|
1398
1398
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compareDocuments
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-V5OOP74P.js";
|
|
4
4
|
import {
|
|
5
5
|
DEFAULT_STYLES,
|
|
6
6
|
NORMAL_STYLE_ID,
|
|
7
7
|
createStyleRegistry,
|
|
8
8
|
isValidStyleId
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CXXKJBQZ.js";
|
|
10
10
|
import {
|
|
11
11
|
CHART_OOXML_NS,
|
|
12
12
|
chartFromOoxml
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
searchDocument,
|
|
35
35
|
sliceContainsTable,
|
|
36
36
|
syncInitialContent
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-6GAYGQDC.js";
|
|
38
38
|
import {
|
|
39
39
|
chartDataToTable
|
|
40
40
|
} from "./chunk-RN767PO6.js";
|
|
@@ -46,20 +46,21 @@ import {
|
|
|
46
46
|
rtfToPlainText,
|
|
47
47
|
sanitizeImportedHtml,
|
|
48
48
|
serializeRichClipboardPayload
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-ZLZKGHSZ.js";
|
|
50
50
|
import {
|
|
51
51
|
escapeHtml,
|
|
52
52
|
htmlToPlainText,
|
|
53
53
|
markdownToTipTapHtml,
|
|
54
54
|
plainTextToSlice
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-2INPJDNY.js";
|
|
56
56
|
import {
|
|
57
57
|
CommentStore,
|
|
58
58
|
TRACK_CHANGES_SKIP_META,
|
|
59
59
|
TrackChanges,
|
|
60
60
|
createReviewId,
|
|
61
|
+
safeMergeAttributes,
|
|
61
62
|
trackChangesPluginKey
|
|
62
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-6IN474P4.js";
|
|
63
64
|
import {
|
|
64
65
|
readZip
|
|
65
66
|
} from "./chunk-CIQIM2IP.js";
|
|
@@ -409,7 +410,7 @@ var TemplateSuggestions = Extension2.create({
|
|
|
409
410
|
});
|
|
410
411
|
|
|
411
412
|
// src/extensions/loading-node.ts
|
|
412
|
-
import { Node as Node2
|
|
413
|
+
import { Node as Node2 } from "@tiptap/core";
|
|
413
414
|
var LoadingNode = Node2.create({
|
|
414
415
|
name: "loadingNode",
|
|
415
416
|
group: "inline",
|
|
@@ -438,7 +439,7 @@ var LoadingNode = Node2.create({
|
|
|
438
439
|
renderHTML({ HTMLAttributes }) {
|
|
439
440
|
return [
|
|
440
441
|
"span",
|
|
441
|
-
|
|
442
|
+
safeMergeAttributes(HTMLAttributes, {
|
|
442
443
|
"data-type": "loading",
|
|
443
444
|
class: "inline-flex items-center px-1.5 py-0.5 text-xs text-muted-foreground animate-pulse"
|
|
444
445
|
}),
|
|
@@ -1870,7 +1871,7 @@ var Image2 = BaseImage.extend({
|
|
|
1870
1871
|
});
|
|
1871
1872
|
|
|
1872
1873
|
// src/extensions/comments.ts
|
|
1873
|
-
import { Mark as Mark3
|
|
1874
|
+
import { Mark as Mark3 } from "@tiptap/core";
|
|
1874
1875
|
import { Plugin as Plugin6, PluginKey as PluginKey3, TextSelection } from "@tiptap/pm/state";
|
|
1875
1876
|
import { Decoration as Decoration3, DecorationSet as DecorationSet3 } from "@tiptap/pm/view";
|
|
1876
1877
|
var commentsPluginKey = new PluginKey3("comments");
|
|
@@ -1966,7 +1967,7 @@ var Comments = Mark3.create({
|
|
|
1966
1967
|
return [{ tag: "span[data-comment-id]" }];
|
|
1967
1968
|
},
|
|
1968
1969
|
renderHTML({ HTMLAttributes }) {
|
|
1969
|
-
return ["span",
|
|
1970
|
+
return ["span", safeMergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
|
|
1970
1971
|
},
|
|
1971
1972
|
addCommands() {
|
|
1972
1973
|
const store = () => this.storage.store;
|
|
@@ -4383,7 +4384,7 @@ var Outline = Extension11.create({
|
|
|
4383
4384
|
});
|
|
4384
4385
|
|
|
4385
4386
|
// src/extensions/document-structure/table-of-contents.ts
|
|
4386
|
-
import { Node as Node3
|
|
4387
|
+
import { Node as Node3 } from "@tiptap/core";
|
|
4387
4388
|
import {
|
|
4388
4389
|
Plugin as Plugin11,
|
|
4389
4390
|
PluginKey as PluginKey8,
|
|
@@ -4625,7 +4626,7 @@ var TableOfContents = Node3.create({
|
|
|
4625
4626
|
] : ["p", { class: "toc-empty" }, this.options.emptyText];
|
|
4626
4627
|
return [
|
|
4627
4628
|
"nav",
|
|
4628
|
-
|
|
4629
|
+
safeMergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
4629
4630
|
"data-type": "table-of-contents",
|
|
4630
4631
|
"aria-label": node.attrs.title || "Table of contents",
|
|
4631
4632
|
class: "pixerate-toc"
|
|
@@ -4710,7 +4711,7 @@ var TableOfContents = Node3.create({
|
|
|
4710
4711
|
});
|
|
4711
4712
|
|
|
4712
4713
|
// src/extensions/document-structure/footnotes.ts
|
|
4713
|
-
import { Node as Node4
|
|
4714
|
+
import { Node as Node4 } from "@tiptap/core";
|
|
4714
4715
|
import {
|
|
4715
4716
|
NodeSelection,
|
|
4716
4717
|
Plugin as Plugin12,
|
|
@@ -4879,7 +4880,7 @@ var FootnoteReference = Node4.create({
|
|
|
4879
4880
|
const id = node.attrs.id;
|
|
4880
4881
|
return [
|
|
4881
4882
|
"sup",
|
|
4882
|
-
|
|
4883
|
+
safeMergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
4883
4884
|
"data-type": "footnote-reference",
|
|
4884
4885
|
class: "pixerate-footnote-ref",
|
|
4885
4886
|
...id ? { id: `fnref-${id}` } : {}
|
|
@@ -5028,7 +5029,7 @@ var Footnotes = Node4.create({
|
|
|
5028
5029
|
renderHTML({ HTMLAttributes }) {
|
|
5029
5030
|
return [
|
|
5030
5031
|
"section",
|
|
5031
|
-
|
|
5032
|
+
safeMergeAttributes(HTMLAttributes, {
|
|
5032
5033
|
"data-type": "footnotes",
|
|
5033
5034
|
class: "pixerate-footnotes",
|
|
5034
5035
|
role: "doc-endnotes"
|
|
@@ -5080,7 +5081,7 @@ var Footnote = Node4.create({
|
|
|
5080
5081
|
renderHTML({ HTMLAttributes }) {
|
|
5081
5082
|
return [
|
|
5082
5083
|
"li",
|
|
5083
|
-
|
|
5084
|
+
safeMergeAttributes(HTMLAttributes, {
|
|
5084
5085
|
"data-type": "footnote",
|
|
5085
5086
|
class: "pixerate-footnote"
|
|
5086
5087
|
}),
|
|
@@ -5103,7 +5104,7 @@ var Footnote = Node4.create({
|
|
|
5103
5104
|
});
|
|
5104
5105
|
|
|
5105
5106
|
// src/extensions/document-structure/bookmarks.ts
|
|
5106
|
-
import { Mark as Mark4
|
|
5107
|
+
import { Mark as Mark4 } from "@tiptap/core";
|
|
5107
5108
|
import { TextSelection as TextSelection5 } from "@tiptap/pm/state";
|
|
5108
5109
|
var BOOKMARK = "bookmark";
|
|
5109
5110
|
function getBookmarks(doc) {
|
|
@@ -5172,7 +5173,7 @@ var Bookmark = Mark4.create({
|
|
|
5172
5173
|
renderHTML({ HTMLAttributes }) {
|
|
5173
5174
|
return [
|
|
5174
5175
|
"span",
|
|
5175
|
-
|
|
5176
|
+
safeMergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
|
5176
5177
|
class: "pixerate-bookmark"
|
|
5177
5178
|
}),
|
|
5178
5179
|
0
|
|
@@ -5243,7 +5244,7 @@ var Bookmark = Mark4.create({
|
|
|
5243
5244
|
});
|
|
5244
5245
|
|
|
5245
5246
|
// src/extensions/document-structure/cross-reference.ts
|
|
5246
|
-
import { Node as Node5
|
|
5247
|
+
import { Node as Node5 } from "@tiptap/core";
|
|
5247
5248
|
import {
|
|
5248
5249
|
Plugin as Plugin13,
|
|
5249
5250
|
PluginKey as PluginKey10,
|
|
@@ -5347,7 +5348,7 @@ var CrossReference = Node5.create({
|
|
|
5347
5348
|
const href = !broken && targetType === "heading" && targetId ? { href: `#${targetId}` } : {};
|
|
5348
5349
|
return [
|
|
5349
5350
|
"a",
|
|
5350
|
-
|
|
5351
|
+
safeMergeAttributes(this.options.HTMLAttributes, HTMLAttributes, href, {
|
|
5351
5352
|
"data-type": "cross-reference",
|
|
5352
5353
|
class: broken ? "pixerate-cross-reference is-broken" : "pixerate-cross-reference"
|
|
5353
5354
|
}),
|
|
@@ -5862,7 +5863,7 @@ function safeClipboard(get) {
|
|
|
5862
5863
|
}
|
|
5863
5864
|
|
|
5864
5865
|
// src/extensions/paragraph-styles/extension.ts
|
|
5865
|
-
import { Extension as Extension13, Mark as Mark5
|
|
5866
|
+
import { Extension as Extension13, Mark as Mark5 } from "@tiptap/core";
|
|
5866
5867
|
import { Plugin as Plugin15, PluginKey as PluginKey12 } from "@tiptap/pm/state";
|
|
5867
5868
|
var STYLE_ID_ATTRIBUTE = "styleId";
|
|
5868
5869
|
var CHARACTER_STYLE_MARK_NAME = "characterStyle";
|
|
@@ -6024,7 +6025,7 @@ var CharacterStyle = Mark5.create({
|
|
|
6024
6025
|
return [{ tag: "span[data-char-style]" }];
|
|
6025
6026
|
},
|
|
6026
6027
|
renderHTML({ HTMLAttributes }) {
|
|
6027
|
-
return ["span",
|
|
6028
|
+
return ["span", safeMergeAttributes(HTMLAttributes), 0];
|
|
6028
6029
|
}
|
|
6029
6030
|
});
|
|
6030
6031
|
var ParagraphStyles = Extension13.create({
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isUnsafeJsonKey,
|
|
3
|
+
stripPrototypeKeys
|
|
4
|
+
} from "./chunk-HF5QZS7Z.js";
|
|
5
|
+
|
|
1
6
|
// src/persistence/migrate.ts
|
|
2
7
|
function hasLoadProblems(report) {
|
|
3
8
|
return report.problems.length > 0 || report.readOnly !== null;
|
|
@@ -23,7 +28,7 @@ function toObject(json) {
|
|
|
23
28
|
return void 0;
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
|
-
return isObject(value) ? deepClone(value) : void 0;
|
|
31
|
+
return isObject(value) ? stripPrototypeKeys(deepClone(value)) : void 0;
|
|
27
32
|
}
|
|
28
33
|
function migrateDocument(json, options) {
|
|
29
34
|
const versionKey = options.versionKey ?? "version";
|
|
@@ -106,7 +111,7 @@ function loadSections(doc, sections, options = {}) {
|
|
|
106
111
|
}
|
|
107
112
|
const unknown = {};
|
|
108
113
|
for (const key of Object.keys(source)) {
|
|
109
|
-
if (!(key in sections) && !ignore.has(key)) unknown[key] = source[key];
|
|
114
|
+
if (!(key in sections) && !ignore.has(key) && !isUnsafeJsonKey(key)) unknown[key] = source[key];
|
|
110
115
|
}
|
|
111
116
|
return { value, problems, unknown };
|
|
112
117
|
}
|
|
@@ -287,7 +287,7 @@ var MCP_TOOL_CANVAS_LAYOUT = {
|
|
|
287
287
|
name: "canvas_layout",
|
|
288
288
|
title: "Lay out the canvas",
|
|
289
289
|
annotations: { title: "Lay out the canvas", ...IDEMPOTENT_ANNOTATIONS },
|
|
290
|
-
description: "Arranges the canvas graph
|
|
290
|
+
description: "Arranges the canvas nodes automatically in a layered graph layout that follows the edges, so nodes line up and do not overlap. Nodes that already have a position stay put unless incremental is false.",
|
|
291
291
|
inputSchema: {
|
|
292
292
|
type: "object",
|
|
293
293
|
properties: {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
|
|
2
|
+
|
|
3
|
+
var _chunk2BSBFBOAcjs = require('./chunk-2BSBFBOA.cjs');
|
|
4
|
+
|
|
5
|
+
// src/extensions/paragraph-styles/registry.ts
|
|
2
6
|
var MAX_CHAIN = 32;
|
|
3
7
|
var STYLE_ID = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
|
|
4
8
|
var UNSAFE_CSS = /[;{}<>\\]|\/\*|url\s*\(|expression\s*\(|@import|javascript:/i;
|
|
@@ -154,7 +158,7 @@ function overlay(base, patch) {
|
|
|
154
158
|
if (!patch) return base;
|
|
155
159
|
const out = { ...base };
|
|
156
160
|
Object.entries(patch).forEach(([key, value]) => {
|
|
157
|
-
if (value !== void 0 && value !== null) out[key] = value;
|
|
161
|
+
if (value !== void 0 && value !== null && !_chunk2BSBFBOAcjs.isUnsafeJsonKey.call(void 0, key)) out[key] = value;
|
|
158
162
|
});
|
|
159
163
|
return out;
|
|
160
164
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
escapeHtml,
|
|
3
3
|
sanitizeHtml
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2INPJDNY.js";
|
|
5
|
+
import {
|
|
6
|
+
stripPrototypeKeys
|
|
7
|
+
} from "./chunk-HF5QZS7Z.js";
|
|
5
8
|
|
|
6
9
|
// src/serializers/html.ts
|
|
7
10
|
var DROP_WITH_CONTENT_REGEX = /<(script|style|template|noscript|iframe|object|embed|head|title|svg|math|textarea|select|button)\b[^>]*>[\s\S]*?<\/\1\s*>/gi;
|
|
@@ -263,7 +266,7 @@ function parseRichClipboardPayload(data, schema) {
|
|
|
263
266
|
if (!payload || payload.version !== 1) return null;
|
|
264
267
|
if (payload.schema !== getSchemaSignature(schema)) return null;
|
|
265
268
|
if (!payload.slice) return null;
|
|
266
|
-
return Slice.fromJSON(schema, payload.slice);
|
|
269
|
+
return Slice.fromJSON(schema, stripPrototypeKeys(payload.slice));
|
|
267
270
|
} catch {
|
|
268
271
|
return null;
|
|
269
272
|
}
|
|
@@ -3,7 +3,7 @@ import type { CommandRegistry } from './registry.cjs';
|
|
|
3
3
|
export interface CommandToolProviderOptions<TContext = any> {
|
|
4
4
|
/** Provider id (default `commands`). */
|
|
5
5
|
id?: string;
|
|
6
|
-
/**
|
|
6
|
+
/** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
|
|
7
7
|
namespace?: string;
|
|
8
8
|
/** Context for enablement and runs (default: the registry's). */
|
|
9
9
|
context?: TContext | (() => TContext);
|
|
@@ -3,7 +3,7 @@ import type { CommandRegistry } from './registry.js';
|
|
|
3
3
|
export interface CommandToolProviderOptions<TContext = any> {
|
|
4
4
|
/** Provider id (default `commands`). */
|
|
5
5
|
id?: string;
|
|
6
|
-
/**
|
|
6
|
+
/** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
|
|
7
7
|
namespace?: string;
|
|
8
8
|
/** Context for enablement and runs (default: the registry's). */
|
|
9
9
|
context?: TContext | (() => TContext);
|
package/dist/commands/index.cjs
CHANGED
|
@@ -768,6 +768,9 @@ function createCommandToolProvider(registry, options = {}) {
|
|
|
768
768
|
return {
|
|
769
769
|
id: _nullishCoalesce(options.id, () => ( "commands")),
|
|
770
770
|
namespace: options.namespace,
|
|
771
|
+
title: "Commands",
|
|
772
|
+
description: "The app's commands (menu and keyboard actions) with their params schemas: list them, run one, or run several as one undo step.",
|
|
773
|
+
skill: "pixerate-agent-tools",
|
|
771
774
|
tools: () => [listCommands, runCommandTool(), runCommands],
|
|
772
775
|
subscribe: (notify) => registry.subscribe(notify)
|
|
773
776
|
};
|
package/dist/commands/index.js
CHANGED
|
@@ -768,6 +768,9 @@ function createCommandToolProvider(registry, options = {}) {
|
|
|
768
768
|
return {
|
|
769
769
|
id: options.id ?? "commands",
|
|
770
770
|
namespace: options.namespace,
|
|
771
|
+
title: "Commands",
|
|
772
|
+
description: "The app's commands (menu and keyboard actions) with their params schemas: list them, run one, or run several as one undo step.",
|
|
773
|
+
skill: "pixerate-agent-tools",
|
|
771
774
|
tools: () => [listCommands, runCommandTool(), runCommands],
|
|
772
775
|
subscribe: (notify) => registry.subscribe(notify)
|
|
773
776
|
};
|
package/dist/compare/index.cjs
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
var
|
|
8
|
-
require('../chunk-
|
|
7
|
+
var _chunkHMGWFXECcjs = require('../chunk-HMGWFXEC.cjs');
|
|
8
|
+
require('../chunk-34RQAGWI.cjs');
|
|
9
|
+
require('../chunk-2BSBFBOA.cjs');
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
exports.compareDocuments =
|
|
15
|
+
exports.compareDocuments = _chunkHMGWFXECcjs.compareDocuments; exports.compareHtml = _chunkHMGWFXECcjs.compareHtml; exports.diffChanges = _chunkHMGWFXECcjs.diffChanges; exports.diffSequences = _chunkHMGWFXECcjs.diffSequences;
|
package/dist/compare/index.js
CHANGED
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
compareHtml,
|
|
5
5
|
diffChanges,
|
|
6
6
|
diffSequences
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-V5OOP74P.js";
|
|
8
|
+
import "../chunk-6IN474P4.js";
|
|
9
|
+
import "../chunk-HF5QZS7Z.js";
|
|
9
10
|
export {
|
|
10
11
|
compareDocuments,
|
|
11
12
|
compareHtml,
|
package/dist/diagram/index.cjs
CHANGED
|
@@ -2076,6 +2076,9 @@ function createDiagramToolProvider(controller, options = {}) {
|
|
|
2076
2076
|
return {
|
|
2077
2077
|
id: _nullishCoalesce(options.id, () => ( "diagram")),
|
|
2078
2078
|
namespace: options.namespace,
|
|
2079
|
+
title: "Diagram editor",
|
|
2080
|
+
description: "Mermaid diagrams: nodes, edges and groups, shapes and styles, direction and layout, Mermaid import and export, rendering.",
|
|
2081
|
+
skill: "pixerate-diagram",
|
|
2079
2082
|
tools: () => readOnlyReason() ? reads : [...reads, ...writes],
|
|
2080
2083
|
subscribe: (notify) => {
|
|
2081
2084
|
let last = readOnlyReason();
|
package/dist/diagram/index.js
CHANGED
|
@@ -2076,6 +2076,9 @@ function createDiagramToolProvider(controller, options = {}) {
|
|
|
2076
2076
|
return {
|
|
2077
2077
|
id: options.id ?? "diagram",
|
|
2078
2078
|
namespace: options.namespace,
|
|
2079
|
+
title: "Diagram editor",
|
|
2080
|
+
description: "Mermaid diagrams: nodes, edges and groups, shapes and styles, direction and layout, Mermaid import and export, rendering.",
|
|
2081
|
+
skill: "pixerate-diagram",
|
|
2079
2082
|
tools: () => readOnlyReason() ? reads : [...reads, ...writes],
|
|
2080
2083
|
subscribe: (notify) => {
|
|
2081
2084
|
let last = readOnlyReason();
|
package/dist/diagram/tools.d.cts
CHANGED
|
@@ -6,7 +6,7 @@ import { type MermaidDocument, type Point } from './types.cjs';
|
|
|
6
6
|
export interface DiagramToolProviderOptions {
|
|
7
7
|
/** Provider id (unique per registry). Default `diagram`. */
|
|
8
8
|
id?: string;
|
|
9
|
-
/**
|
|
9
|
+
/** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
|
|
10
10
|
namespace?: string;
|
|
11
11
|
/**
|
|
12
12
|
* The diagram cannot be edited: write tools are hidden and `get_diagram` says why. A
|
package/dist/diagram/tools.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type MermaidDocument, type Point } from './types.js';
|
|
|
6
6
|
export interface DiagramToolProviderOptions {
|
|
7
7
|
/** Provider id (unique per registry). Default `diagram`. */
|
|
8
8
|
id?: string;
|
|
9
|
-
/**
|
|
9
|
+
/** Tool-name prefix (`<namespace>__<name>`); defaults to the provider id, `''` for bare names. */
|
|
10
10
|
namespace?: string;
|
|
11
11
|
/**
|
|
12
12
|
* The diagram cannot be edited: write tools are hidden and `get_diagram` says why. A
|