@pixerate/editor 0.164.0 → 0.166.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/dist/agent/index.cjs +54 -39
- package/dist/agent/index.js +24 -9
- package/dist/animation/index.cjs +6 -5
- package/dist/animation/index.js +5 -4
- package/dist/animation-editor/index.cjs +65 -64
- package/dist/animation-editor/index.js +8 -7
- package/dist/bridge/cli.cjs +3 -3
- package/dist/bridge/cli.js +2 -2
- package/dist/bridge/index.cjs +3 -3
- package/dist/bridge/index.js +2 -2
- package/dist/canvas/index.cjs +89 -87
- package/dist/canvas/index.js +11 -9
- package/dist/chart/controller.d.cts +60 -2
- package/dist/chart/controller.d.ts +60 -2
- package/dist/chart/index.cjs +657 -163
- package/dist/chart/index.d.cts +3 -0
- package/dist/chart/index.d.ts +3 -0
- package/dist/chart/index.js +512 -18
- package/dist/chart/layout-families.d.cts +14 -0
- package/dist/chart/layout-families.d.ts +14 -0
- package/dist/chart/layout-shared.d.cts +5 -0
- package/dist/chart/layout-shared.d.ts +5 -0
- package/dist/chart/links.d.cts +34 -0
- package/dist/chart/links.d.ts +34 -0
- package/dist/chart/mermaid.d.cts +9 -6
- package/dist/chart/mermaid.d.ts +9 -6
- package/dist/chart/race.d.cts +26 -0
- package/dist/chart/race.d.ts +26 -0
- package/dist/chart/schemas.d.cts +5 -0
- package/dist/chart/schemas.d.ts +5 -0
- package/dist/chart/spec.d.cts +3 -2
- package/dist/chart/spec.d.ts +3 -2
- package/dist/chart/style.d.cts +33 -0
- package/dist/chart/style.d.ts +33 -0
- package/dist/chart/types.d.cts +28 -2
- package/dist/chart/types.d.ts +28 -2
- package/dist/{chunk-ZVNAMTFO.cjs → chunk-3FSUJIXN.cjs} +18 -174
- package/dist/{chunk-RQCMSEM5.cjs → chunk-4QUUHTGJ.cjs} +2 -2
- package/dist/{chunk-CIPIESX4.cjs → chunk-4ZC5QJE2.cjs} +3 -3
- package/dist/{chunk-S6X2QRVU.cjs → chunk-5UEFBM2M.cjs} +1 -138
- package/dist/{chunk-5FNGLV2D.js → chunk-5UNQDC3Q.js} +18 -3
- package/dist/{chunk-YSAGBIRW.cjs → chunk-6FYIFGBW.cjs} +16 -16
- package/dist/{chunk-QYZGBVNC.js → chunk-7272D3K2.js} +10 -8
- package/dist/{chunk-462WGGXX.cjs → chunk-AMX23CSN.cjs} +27 -16
- package/dist/{chunk-3VLOOO3G.js → chunk-BDIM6NVW.js} +1 -1
- package/dist/{chunk-R3P2M7HU.cjs → chunk-BPX4Z3N3.cjs} +355 -207
- package/dist/{chunk-D54JHQK2.cjs → chunk-CHLV7UFP.cjs} +51 -51
- package/dist/{chunk-OXERWBKE.js → chunk-DFCAR7AW.js} +3 -3
- package/dist/{chunk-GZ2FM3ZB.js → chunk-DKNEQX7T.js} +6 -162
- package/dist/{chunk-JCXMJUQO.cjs → chunk-EGZM52EO.cjs} +3 -3
- package/dist/{chunk-ES3UEVUT.cjs → chunk-EUIDTZNQ.cjs} +112 -110
- package/dist/{chunk-H3OEM3Q2.js → chunk-F6R67I3A.js} +1 -1
- package/dist/{chunk-3NEZJCBY.js → chunk-FR432ROA.js} +349 -201
- package/dist/chunk-HIDFL5LQ.js +484 -0
- package/dist/{chunk-22KLZZGH.cjs → chunk-HXOBOHH2.cjs} +8 -8
- package/dist/{chunk-MKTDELCD.js → chunk-I5MRJW7B.js} +1 -1
- package/dist/{chunk-SDHZG5TF.js → chunk-ILP77UD6.js} +160 -2
- package/dist/{chunk-Z4P2RBMJ.js → chunk-ITANXMZD.js} +177 -3
- package/dist/chunk-KGRZMHZB.js +204 -0
- package/dist/{chunk-SET6KJOP.js → chunk-LPIKXPBM.js} +1 -1
- package/dist/{chunk-BQWGN5WH.js → chunk-M2TPMYJE.js} +1 -1
- package/dist/{chunk-GTELFJRE.cjs → chunk-M5GLQQWG.cjs} +2 -2
- package/dist/{chunk-4VU4CP7R.js → chunk-MHLU6GRJ.js} +1 -138
- package/dist/{chunk-NZD2MZJC.cjs → chunk-MZFZSVUJ.cjs} +38 -23
- package/dist/{chunk-DAPQGA55.js → chunk-NQQDGGXY.js} +2 -2
- package/dist/chunk-O6OGNDND.js +164 -0
- package/dist/{chunk-PA3IMPPS.cjs → chunk-OVYQAYGH.cjs} +81 -81
- package/dist/{chunk-YXOW456B.js → chunk-PPEDZ5WR.js} +1 -1
- package/dist/{chunk-24M7VD6M.cjs → chunk-S4EIAIEW.cjs} +7 -7
- package/dist/{chunk-M4MIZPQI.cjs → chunk-SJ2CPTQC.cjs} +189 -15
- package/dist/{chunk-YGG7WDWT.cjs → chunk-SZWVMB3B.cjs} +24 -18
- package/dist/chunk-TFF2GTGN.cjs +153 -0
- package/dist/chunk-TTCJPX4U.cjs +204 -0
- package/dist/{chunk-SBQVEBSU.cjs → chunk-UUUTEVX6.cjs} +242 -68
- package/dist/{chunk-WI7QJA7A.cjs → chunk-UXETV2NC.cjs} +161 -3
- package/dist/{chunk-GKNEJ6EN.cjs → chunk-V5L2G22R.cjs} +321 -107
- package/dist/{chunk-TALQONZ5.js → chunk-VB2CY6EG.js} +3 -3
- package/dist/{chunk-QY4KUDMY.js → chunk-VRXXAXUT.js} +2 -2
- package/dist/chunk-VU6WQSMB.cjs +164 -0
- package/dist/{chunk-NHLYK3AX.js → chunk-XBQX76CT.js} +182 -8
- package/dist/{chunk-5AARIS3R.cjs → chunk-XCDGM7TD.cjs} +37 -37
- package/dist/{chunk-POR54B55.js → chunk-XNU45TYA.js} +7 -1
- package/dist/{chunk-EVXQNQND.js → chunk-XZB3TJ6K.js} +16 -5
- package/dist/chunk-YBAPT7NL.js +153 -0
- package/dist/{chunk-SZA42R4N.js → chunk-YUFTVNLX.js} +230 -16
- package/dist/chunk-Z2UQYMPS.cjs +484 -0
- package/dist/color/index.cjs +5 -3
- package/dist/color/index.js +12 -10
- package/dist/diagram/index.cjs +55 -243
- package/dist/diagram/index.js +12 -200
- package/dist/export/index.cjs +7 -6
- package/dist/export/index.js +6 -5
- package/dist/extensions/index.cjs +12 -9
- package/dist/extensions/index.js +11 -8
- package/dist/gradient/index.cjs +29 -27
- package/dist/gradient/index.js +6 -4
- package/dist/image-editor/index.cjs +644 -643
- package/dist/image-editor/index.js +7 -6
- package/dist/index.cjs +21 -18
- package/dist/index.js +14 -11
- package/dist/paint-editor/index.cjs +19 -18
- package/dist/paint-editor/index.js +7 -6
- package/dist/parameters/index.cjs +2 -2
- package/dist/parameters/index.js +1 -1
- package/dist/persistence/assetWrites.d.cts +22 -0
- package/dist/persistence/assetWrites.d.ts +22 -0
- package/dist/persistence/assets.d.cts +71 -0
- package/dist/persistence/assets.d.ts +71 -0
- package/dist/persistence/documentStore.d.cts +17 -1
- package/dist/persistence/documentStore.d.ts +17 -1
- package/dist/persistence/documentTools.d.cts +5 -1
- package/dist/persistence/documentTools.d.ts +5 -1
- package/dist/persistence/editorAutosave.d.cts +7 -0
- package/dist/persistence/editorAutosave.d.ts +7 -0
- package/dist/persistence/index.cjs +141 -21
- package/dist/persistence/index.js +130 -10
- package/dist/persistence/storage.d.cts +13 -1
- package/dist/persistence/storage.d.ts +13 -1
- package/dist/spreadsheet/index.cjs +3 -3
- package/dist/spreadsheet/index.js +2 -2
- package/dist/tokens/index.cjs +11 -3
- package/dist/tokens/index.d.cts +1 -0
- package/dist/tokens/index.d.ts +1 -0
- package/dist/tokens/index.js +10 -2
- package/dist/tokens/style.d.cts +36 -0
- package/dist/tokens/style.d.ts +36 -0
- package/dist/tools/index.cjs +15 -3
- package/dist/tools/index.d.cts +2 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +14 -2
- package/dist/tools/style-tools.d.cts +19 -0
- package/dist/tools/style-tools.d.ts +19 -0
- package/dist/tools/style.d.cts +212 -0
- package/dist/tools/style.d.ts +212 -0
- package/dist/tools/view.d.cts +6 -0
- package/dist/tools/view.d.ts +6 -0
- package/dist/typography/index.cjs +8 -6
- package/dist/typography/index.js +5 -3
- package/dist/vector/index.cjs +953 -952
- package/dist/vector/index.js +7 -6
- package/dist/video-editor/index.cjs +8 -7
- package/dist/video-editor/index.js +6 -5
- package/package.json +1 -1
- package/skills/pixerate-chart/SKILL.md +20 -2
- package/dist/chunk-ERAGQL2N.cjs +0 -68
- package/dist/chunk-KMU6QJB7.js +0 -68
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseSkillFrontmatter
|
|
3
|
+
} from "./chunk-XZB3TJ6K.js";
|
|
4
|
+
import {
|
|
5
|
+
readingTime
|
|
6
|
+
} from "./chunk-6DXDUVSL.js";
|
|
7
|
+
import {
|
|
8
|
+
validateJsonSchema
|
|
9
|
+
} from "./chunk-V2ZCJRDM.js";
|
|
10
|
+
import {
|
|
11
|
+
isUnsafeJsonKey,
|
|
12
|
+
stripPrototypeKeys
|
|
13
|
+
} from "./chunk-HF5QZS7Z.js";
|
|
14
|
+
|
|
15
|
+
// src/tools/script.ts
|
|
16
|
+
function toolResultValue(result) {
|
|
17
|
+
if (result.structuredContent) return result.structuredContent;
|
|
18
|
+
const text = result.content.find((b) => b.type === "text");
|
|
19
|
+
if (!text?.text) return void 0;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(text.text);
|
|
22
|
+
} catch {
|
|
23
|
+
return text.text;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function toolResultError(result) {
|
|
27
|
+
const text = result.content.find((b) => b.type === "text");
|
|
28
|
+
return text?.text ?? "The tool failed.";
|
|
29
|
+
}
|
|
30
|
+
var realWait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
31
|
+
async function runToolScript(source, script, options = {}) {
|
|
32
|
+
const control = options.control ?? { speed: 1, stopped: false };
|
|
33
|
+
const wait = options.wait ?? realWait;
|
|
34
|
+
const pause = (ms) => Number.isFinite(control.speed) ? wait(ms / Math.max(0.1, control.speed)) : Promise.resolve();
|
|
35
|
+
const emit = options.onEvent ?? (() => {
|
|
36
|
+
});
|
|
37
|
+
const ctx = { results: {}, last: void 0 };
|
|
38
|
+
const finish = (ok) => {
|
|
39
|
+
if (control.stopped) options.playback?.stop();
|
|
40
|
+
emit({ type: "done", ok, stopped: control.stopped });
|
|
41
|
+
return { ok, ctx };
|
|
42
|
+
};
|
|
43
|
+
for (let i = 0; i < script.steps.length; i++) {
|
|
44
|
+
if (control.stopped) return finish(false);
|
|
45
|
+
const step = script.steps[i];
|
|
46
|
+
if (step.say) {
|
|
47
|
+
emit({ type: "say", step: i, text: step.say });
|
|
48
|
+
options.playback?.say(step.say, options.actor ? { actor: options.actor } : {});
|
|
49
|
+
await pause(readingTime(step.say));
|
|
50
|
+
}
|
|
51
|
+
if (!step.tool) continue;
|
|
52
|
+
if (control.stopped) return finish(false);
|
|
53
|
+
let args;
|
|
54
|
+
try {
|
|
55
|
+
args = typeof step.args === "function" ? step.args(ctx) : step.args ?? {};
|
|
56
|
+
} catch (error) {
|
|
57
|
+
emit({ type: "error", step: i, message: error instanceof Error ? error.message : String(error) });
|
|
58
|
+
return finish(false);
|
|
59
|
+
}
|
|
60
|
+
emit({ type: "call", step: i, tool: step.tool, args });
|
|
61
|
+
const result = await source.callTool(step.tool, args, options.actor ? { actor: options.actor } : {});
|
|
62
|
+
emit({ type: "result", step: i, tool: step.tool, result });
|
|
63
|
+
if (result.isError) {
|
|
64
|
+
emit({ type: "error", step: i, message: toolResultError(result) });
|
|
65
|
+
return finish(false);
|
|
66
|
+
}
|
|
67
|
+
ctx.last = toolResultValue(result);
|
|
68
|
+
if (step.as) ctx.results[step.as] = ctx.last;
|
|
69
|
+
await pause(350);
|
|
70
|
+
}
|
|
71
|
+
return finish(true);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/tools/style.ts
|
|
75
|
+
var STYLE_SKILL_NAME = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
76
|
+
var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
77
|
+
function parseStyleDomains(markdown) {
|
|
78
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(markdown);
|
|
79
|
+
const line = match?.[1].split(/\r?\n/).find((l) => /^domains:/.test(l));
|
|
80
|
+
if (!line) return void 0;
|
|
81
|
+
const raw = line.slice("domains:".length).trim().replace(/^\[|\]$/g, "");
|
|
82
|
+
return raw.split(",").map((d) => d.trim().replace(/^(['"])(.*)\1$/, "$2")).filter(Boolean);
|
|
83
|
+
}
|
|
84
|
+
function memoryStyleStore(initial = {}, state = {}) {
|
|
85
|
+
const files = /* @__PURE__ */ new Map();
|
|
86
|
+
const states = new Map(Object.entries(state));
|
|
87
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
88
|
+
const notify = () => listeners.forEach((l) => l());
|
|
89
|
+
for (const [path, text] of Object.entries(initial)) {
|
|
90
|
+
const [dir, ...rest] = path.replace(/\\/g, "/").replace(/^\.?\//, "").split("/");
|
|
91
|
+
if (!dir || !rest.length) continue;
|
|
92
|
+
if (!files.has(dir)) files.set(dir, /* @__PURE__ */ new Map());
|
|
93
|
+
files.get(dir).set(rest.join("/"), text);
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
list: () => [.../* @__PURE__ */ new Set([...files.keys(), ...states.keys()])].sort().map((name) => ({ name, ...states.get(name) })),
|
|
97
|
+
read: (name, file) => files.get(name)?.get(file),
|
|
98
|
+
files: (name) => [...files.get(name)?.keys() ?? []].sort(),
|
|
99
|
+
subscribe(listener) {
|
|
100
|
+
listeners.add(listener);
|
|
101
|
+
return () => listeners.delete(listener);
|
|
102
|
+
},
|
|
103
|
+
set(name, skillFiles) {
|
|
104
|
+
files.set(name, new Map(Object.entries(skillFiles)));
|
|
105
|
+
notify();
|
|
106
|
+
},
|
|
107
|
+
remove(name) {
|
|
108
|
+
files.delete(name);
|
|
109
|
+
states.delete(name);
|
|
110
|
+
notify();
|
|
111
|
+
},
|
|
112
|
+
setState(name, next) {
|
|
113
|
+
if (next) states.set(name, next);
|
|
114
|
+
else states.delete(name);
|
|
115
|
+
notify();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function resolveTokens(value, tokens, path, errors) {
|
|
120
|
+
if (Array.isArray(value)) return value.map((v, i) => resolveTokens(v, tokens, `${path}[${i}]`, errors));
|
|
121
|
+
if (!isPlainObject(value)) return value;
|
|
122
|
+
if ("$token" in value) {
|
|
123
|
+
const token = value.$token;
|
|
124
|
+
const mode = value.mode;
|
|
125
|
+
if (typeof token !== "string" || !token || mode !== void 0 && typeof mode !== "string" || Object.keys(value).some((k) => k !== "$token" && k !== "mode")) {
|
|
126
|
+
errors.push(`${path || "profile"}: a token reference is { "$token": "<variable name or id>", "mode"?: "<mode>" }.`);
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
if (!tokens) {
|
|
130
|
+
errors.push(`${path}: "${token}" is a token reference, but this host has no design tokens to resolve it.`);
|
|
131
|
+
return void 0;
|
|
132
|
+
}
|
|
133
|
+
const resolved = tokens.resolve({ token, ...mode ? { mode } : {} });
|
|
134
|
+
if (!resolved.ok) errors.push(`${path}: ${resolved.message}`);
|
|
135
|
+
return resolved.ok ? resolved.value : void 0;
|
|
136
|
+
}
|
|
137
|
+
const out = {};
|
|
138
|
+
for (const [k, v] of Object.entries(value)) out[k] = resolveTokens(v, tokens, path ? `${path}.${k}` : k, errors);
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
function checkListErrors(list, domain) {
|
|
142
|
+
if (list === void 0) return [];
|
|
143
|
+
if (!Array.isArray(list)) return ['checks: expected a list of check ids or { "id": ..., options } objects.'];
|
|
144
|
+
const errors = [];
|
|
145
|
+
list.forEach((entry, i) => {
|
|
146
|
+
const id = typeof entry === "string" ? entry : isPlainObject(entry) ? entry.id : void 0;
|
|
147
|
+
if (typeof id !== "string" || !id) {
|
|
148
|
+
errors.push(`checks[${i}]: expected a check id or { "id": ..., options }.`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const check = domain.checks.find((c) => c.id === id);
|
|
152
|
+
if (!check || typeof entry === "string") return;
|
|
153
|
+
const { id: _id, ...options } = entry;
|
|
154
|
+
const schema = check.optionsSchema ?? { type: "object", properties: {}, additionalProperties: false };
|
|
155
|
+
for (const e of validateJsonSchema(options, schema)) errors.push(`checks[${i}] (${id})${e.path}: ${e.message}`);
|
|
156
|
+
});
|
|
157
|
+
return errors;
|
|
158
|
+
}
|
|
159
|
+
function mergeProfile(target, value, layer, skill, sources, locked, issues, prefix = "") {
|
|
160
|
+
for (const [key, next] of Object.entries(value)) {
|
|
161
|
+
if (isUnsafeJsonKey(key) || next === void 0) continue;
|
|
162
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
163
|
+
const lockedBy = [...locked.entries()].find(([p]) => p === path || path.startsWith(`${p}.`) || p.startsWith(`${path}.`));
|
|
164
|
+
if (isPlainObject(next)) {
|
|
165
|
+
if (!isPlainObject(target[key])) {
|
|
166
|
+
if (lockedBy && lockedBy[1] !== layer.id && target[key] !== void 0) {
|
|
167
|
+
issues.push({ skill, layer: layer.id, message: `"${path}" is locked by the ${lockedBy[1]} layer, so this skill's value is ignored.` });
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
target[key] = {};
|
|
171
|
+
delete sources[path];
|
|
172
|
+
}
|
|
173
|
+
mergeProfile(target[key], next, layer, skill, sources, locked, issues, path);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (lockedBy && lockedBy[1] !== layer.id) {
|
|
177
|
+
issues.push({ skill, layer: layer.id, message: `"${path}" is locked by the ${lockedBy[1]} layer, so this skill's value is ignored.` });
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
target[key] = Array.isArray(next) ? structuredClone(next) : next;
|
|
181
|
+
for (const p of Object.keys(sources)) if (p.startsWith(`${path}.`)) delete sources[p];
|
|
182
|
+
sources[path] = layer.id;
|
|
183
|
+
if (layer.locked) locked.set(path, layer.id);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function createStyleResolver(options) {
|
|
187
|
+
const layers = [...options.layers];
|
|
188
|
+
const domains = [...options.domains];
|
|
189
|
+
const ids = /* @__PURE__ */ new Set();
|
|
190
|
+
for (const layer of layers) {
|
|
191
|
+
if (ids.has(layer.id)) throw new Error(`Two style layers are called "${layer.id}"; give each layer its own id.`);
|
|
192
|
+
ids.add(layer.id);
|
|
193
|
+
}
|
|
194
|
+
const domainIds = domains.map((d) => d.id);
|
|
195
|
+
const requireDomain = (id) => {
|
|
196
|
+
const domain = domains.find((d) => d.id === id);
|
|
197
|
+
if (!domain) throw new Error(`There is no house-style domain "${id}"; expected one of ${domainIds.map((d) => `"${d}"`).join(", ") || "(none registered)"}.`);
|
|
198
|
+
return domain;
|
|
199
|
+
};
|
|
200
|
+
async function load() {
|
|
201
|
+
const issues = [];
|
|
202
|
+
const entries = await Promise.all(layers.map(async (layer) => [...await layer.store.list()]));
|
|
203
|
+
const names = [...new Set(entries.flat().map((e) => e.name))];
|
|
204
|
+
const skills = [];
|
|
205
|
+
for (const name of names) {
|
|
206
|
+
if (!STYLE_SKILL_NAME.test(name)) {
|
|
207
|
+
issues.push({ skill: name, message: `"${name}" is not a valid skill name (lowercase letters, digits and hyphens, at most 64).` });
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
const copies = [];
|
|
211
|
+
for (let i = 0; i < layers.length; i++) {
|
|
212
|
+
const text = await layers[i].store.read(name, "SKILL.md");
|
|
213
|
+
if (text !== void 0) copies.push({ index: i, text });
|
|
214
|
+
}
|
|
215
|
+
if (!copies.length) continue;
|
|
216
|
+
const lockedCopy = copies.find((c) => layers[c.index].locked);
|
|
217
|
+
const winner = lockedCopy ?? copies[copies.length - 1];
|
|
218
|
+
const layer = layers[winner.index];
|
|
219
|
+
const skillIssues = [];
|
|
220
|
+
for (const c of copies) {
|
|
221
|
+
if (c.index > winner.index) skillIssues.push(`The ${layers[c.index].id} layer's copy is ignored: the ${layer.id} layer is locked.`);
|
|
222
|
+
}
|
|
223
|
+
let enabled = true;
|
|
224
|
+
let order = 0;
|
|
225
|
+
for (let i = 0; i < layers.length; i++) {
|
|
226
|
+
const entry = entries[i].find((e) => e.name === name);
|
|
227
|
+
if (!entry) continue;
|
|
228
|
+
if (i === winner.index && entry.order !== void 0) order = entry.order;
|
|
229
|
+
if (entry.enabled === void 0) continue;
|
|
230
|
+
if (layer.required && i !== winner.index) {
|
|
231
|
+
if (entry.enabled === false) skillIssues.push(`The ${layers[i].id} layer cannot switch it off: the ${layer.id} layer requires it.`);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
enabled = entry.enabled;
|
|
235
|
+
}
|
|
236
|
+
const { description = "", body } = parseSkillFrontmatter(winner.text);
|
|
237
|
+
const named = parseStyleDomains(winner.text);
|
|
238
|
+
const applies = /* @__PURE__ */ new Set();
|
|
239
|
+
for (const d of named ?? domainIds) {
|
|
240
|
+
if (domainIds.includes(d)) applies.add(d);
|
|
241
|
+
else skillIssues.push(`It names an unknown domain "${d}"; the domains here are ${domainIds.join(", ")}.`);
|
|
242
|
+
}
|
|
243
|
+
const profiles = /* @__PURE__ */ new Map();
|
|
244
|
+
for (const domain of domains) {
|
|
245
|
+
const raw = await layer.store.read(name, `${domain.id}.json`);
|
|
246
|
+
if (raw === void 0) continue;
|
|
247
|
+
const file = `${domain.id}.json`;
|
|
248
|
+
if (!applies.has(domain.id)) {
|
|
249
|
+
skillIssues.push(`${file} is left out: the skill's domains do not include ${domain.id}.`);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
let parsed;
|
|
253
|
+
try {
|
|
254
|
+
parsed = stripPrototypeKeys(JSON.parse(raw));
|
|
255
|
+
} catch (error) {
|
|
256
|
+
skillIssues.push(`${file} is not valid JSON: ${error.message}`);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (!isPlainObject(parsed)) {
|
|
260
|
+
skillIssues.push(`${file} must hold a JSON object.`);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const errors = [];
|
|
264
|
+
const resolved = resolveTokens(parsed, options.tokens, "", errors);
|
|
265
|
+
const { checks, ...rest } = resolved;
|
|
266
|
+
errors.push(...validateJsonSchema(rest, domain.profileSchema).map((e) => `${e.path || "(profile)"}: ${e.message}`));
|
|
267
|
+
errors.push(...checkListErrors(checks, domain));
|
|
268
|
+
if (errors.length) {
|
|
269
|
+
skillIssues.push(`${file} is left out: ${errors.join(" ")}`);
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
profiles.set(domain.id, resolved);
|
|
273
|
+
}
|
|
274
|
+
skills.push({
|
|
275
|
+
info: {
|
|
276
|
+
name,
|
|
277
|
+
description,
|
|
278
|
+
layer: layer.id,
|
|
279
|
+
domains: [...applies],
|
|
280
|
+
profiles: [...profiles.keys()],
|
|
281
|
+
enabled,
|
|
282
|
+
order,
|
|
283
|
+
issues: skillIssues
|
|
284
|
+
},
|
|
285
|
+
layerIndex: winner.index,
|
|
286
|
+
body: body.trim(),
|
|
287
|
+
profiles,
|
|
288
|
+
applies
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
skills.sort((a, b) => a.layerIndex - b.layerIndex || a.info.order - b.info.order || a.info.name.localeCompare(b.info.name));
|
|
292
|
+
return { skills, issues };
|
|
293
|
+
}
|
|
294
|
+
async function resolve(domainId) {
|
|
295
|
+
requireDomain(domainId);
|
|
296
|
+
const { skills, issues: loadIssues } = await load();
|
|
297
|
+
const issues = [...loadIssues];
|
|
298
|
+
const profile = {};
|
|
299
|
+
const sources = {};
|
|
300
|
+
const locked = /* @__PURE__ */ new Map();
|
|
301
|
+
const applied = [];
|
|
302
|
+
for (const skill of skills) {
|
|
303
|
+
if (!skill.applies.has(domainId)) continue;
|
|
304
|
+
for (const message of skill.info.issues) issues.push({ skill: skill.info.name, layer: skill.info.layer, message });
|
|
305
|
+
if (!skill.info.enabled) continue;
|
|
306
|
+
applied.push({ name: skill.info.name, description: skill.info.description, layer: skill.info.layer, body: skill.body });
|
|
307
|
+
const own = skill.profiles.get(domainId);
|
|
308
|
+
if (own) mergeProfile(profile, own, layers[skill.layerIndex], skill.info.name, sources, locked, issues);
|
|
309
|
+
}
|
|
310
|
+
return { domain: domainId, skills: applied, profile, sources, issues };
|
|
311
|
+
}
|
|
312
|
+
async function winnerLayer(name) {
|
|
313
|
+
const copies = [];
|
|
314
|
+
for (let i = 0; i < layers.length; i++) if (await layers[i].store.read(name, "SKILL.md") !== void 0) copies.push(i);
|
|
315
|
+
if (!copies.length) return void 0;
|
|
316
|
+
return layers[copies.find((i) => layers[i].locked) ?? copies[copies.length - 1]];
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
layers,
|
|
320
|
+
domains,
|
|
321
|
+
async list(opts = {}) {
|
|
322
|
+
if (opts.domain !== void 0) requireDomain(opts.domain);
|
|
323
|
+
const { skills } = await load();
|
|
324
|
+
return skills.filter((s) => opts.domain === void 0 || s.applies.has(opts.domain)).map((s) => s.info);
|
|
325
|
+
},
|
|
326
|
+
resolve,
|
|
327
|
+
async readFile(name, file) {
|
|
328
|
+
const layer = await winnerLayer(name);
|
|
329
|
+
return layer ? layer.store.read(name, file) : void 0;
|
|
330
|
+
},
|
|
331
|
+
async files(name) {
|
|
332
|
+
const layer = await winnerLayer(name);
|
|
333
|
+
return layer ? [...await layer.store.files(name)] : void 0;
|
|
334
|
+
},
|
|
335
|
+
async check(domainId, state) {
|
|
336
|
+
const domain = requireDomain(domainId);
|
|
337
|
+
const style = await resolve(domainId);
|
|
338
|
+
return { ...runStyleChecks(domain, state, style), style };
|
|
339
|
+
},
|
|
340
|
+
subscribe(listener) {
|
|
341
|
+
const offs = [...layers.map((l) => l.store.subscribe?.(listener)), options.tokens?.subscribe?.(listener)];
|
|
342
|
+
return () => offs.forEach((off) => off?.());
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function runStyleChecks(domain, state, style) {
|
|
347
|
+
const report = { findings: [], ran: [], skipped: [] };
|
|
348
|
+
const list = Array.isArray(style.profile.checks) ? style.profile.checks : [];
|
|
349
|
+
const layer = style.sources.checks;
|
|
350
|
+
for (const entry of list) {
|
|
351
|
+
const id = typeof entry === "string" ? entry : isPlainObject(entry) && typeof entry.id === "string" ? entry.id : void 0;
|
|
352
|
+
if (!id) continue;
|
|
353
|
+
const check = domain.checks.find((c) => c.id === id);
|
|
354
|
+
if (!check) {
|
|
355
|
+
report.skipped.push({ check: id, reason: `There is no "${id}" check for ${domain.id}; it has ${domain.checks.map((c) => `"${c.id}"`).join(", ")}.` });
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const { id: _id, ...options } = isPlainObject(entry) ? entry : { id };
|
|
359
|
+
try {
|
|
360
|
+
for (const f of check.run(state, style.profile, options)) report.findings.push({ ...f, check: id, ...layer ? { layer } : {} });
|
|
361
|
+
report.ran.push(id);
|
|
362
|
+
} catch (error) {
|
|
363
|
+
report.skipped.push({ check: id, reason: `The check could not run: ${error.message}` });
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return report;
|
|
367
|
+
}
|
|
368
|
+
var escapeAttribute = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
369
|
+
function renderStyle(style) {
|
|
370
|
+
if (!style.skills.length) return `No house style applies to ${style.domain}.`;
|
|
371
|
+
const blocks = style.skills.map((s) => {
|
|
372
|
+
const body = s.body.replace(/<(\/?)style_skill/gi, "<$1style_skill");
|
|
373
|
+
return `<style_skill name="${escapeAttribute(s.name)}" layer="${escapeAttribute(s.layer)}">
|
|
374
|
+
${body}
|
|
375
|
+
</style_skill>`;
|
|
376
|
+
});
|
|
377
|
+
const profile = Object.keys(style.profile).length ? `
|
|
378
|
+
|
|
379
|
+
Merged ${style.domain} profile:
|
|
380
|
+
${JSON.stringify(style.profile, null, 2)}` : "";
|
|
381
|
+
return `${blocks.join("\n\n")}${profile}`;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/tools/style-tools.ts
|
|
385
|
+
var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
386
|
+
function createStyleToolProvider(styles, options = {}) {
|
|
387
|
+
const domainIds = styles.domains.map((d) => d.id);
|
|
388
|
+
const DOMAIN = {
|
|
389
|
+
type: "string",
|
|
390
|
+
enum: domainIds,
|
|
391
|
+
description: `Editor domain: ${styles.domains.map((d) => `"${d.id}" (${d.title})`).join(", ")}.`
|
|
392
|
+
};
|
|
393
|
+
const listStyles = {
|
|
394
|
+
name: "list_styles",
|
|
395
|
+
title: "List house styles",
|
|
396
|
+
description: "Lists the house-style skills here, general layer first: name, description, layer (org, workspace, user, ...), the domains it applies to, which domains it has a profile for, whether it is on, and issues that leave all or part of it out. Read one domain with get_style.",
|
|
397
|
+
inputSchema: {
|
|
398
|
+
type: "object",
|
|
399
|
+
properties: { domain: { ...DOMAIN, description: `Only skills that apply to this domain (default: all). ${DOMAIN.description}` } },
|
|
400
|
+
additionalProperties: false
|
|
401
|
+
},
|
|
402
|
+
annotations: { title: "List house styles", ...READ },
|
|
403
|
+
handler: async ({ domain }) => {
|
|
404
|
+
const skills = await styles.list(domain ? { domain } : {});
|
|
405
|
+
return { skills, domains: domainIds };
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
const getStyle = {
|
|
409
|
+
name: "get_style",
|
|
410
|
+
title: "Get house style",
|
|
411
|
+
description: "Returns the house style for one editor domain: each applicable skill's preferences as a <style_skill> block naming its layer, the merged profile (structured rules such as the palette, with design-token references already resolved), which layer set each profile field, and issues. Call it before you make or change work in that domain, then check the result with the domain's check_<domain>_style tool. House style is a preference: the user's instructions and the domain skill come first.",
|
|
412
|
+
inputSchema: { type: "object", properties: { domain: DOMAIN }, required: ["domain"], additionalProperties: false },
|
|
413
|
+
annotations: { title: "Get house style", ...READ },
|
|
414
|
+
handler: async ({ domain }) => {
|
|
415
|
+
const style = await styles.resolve(domain);
|
|
416
|
+
return {
|
|
417
|
+
content: [{ type: "text", text: renderStyle(style) }],
|
|
418
|
+
structuredContent: { domain, skills: style.skills.map(({ name, description, layer }) => ({ name, description, layer })), profile: style.profile, sources: style.sources, issues: style.issues }
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
const getStyleFile = {
|
|
423
|
+
name: "get_style_file",
|
|
424
|
+
title: "Read a house-style file",
|
|
425
|
+
description: 'Returns one file of a house-style skill as text, for longer guidance its preferences point to (e.g. "references/tone.md") or its raw profile ("chart.json", before tokens are resolved). list_styles names the skills; an unknown file fails with the list of its files.',
|
|
426
|
+
inputSchema: {
|
|
427
|
+
type: "object",
|
|
428
|
+
properties: {
|
|
429
|
+
name: { type: "string", minLength: 1, description: "Skill name, as list_styles returns it." },
|
|
430
|
+
file: { type: "string", minLength: 1, description: 'Path inside the skill folder, e.g. "references/tone.md" or "SKILL.md".' }
|
|
431
|
+
},
|
|
432
|
+
required: ["name", "file"],
|
|
433
|
+
additionalProperties: false
|
|
434
|
+
},
|
|
435
|
+
annotations: { title: "Read a house-style file", ...READ },
|
|
436
|
+
handler: async ({ name, file }) => {
|
|
437
|
+
const files = await styles.files(name);
|
|
438
|
+
if (!files) {
|
|
439
|
+
const known = (await styles.list()).map((s) => s.name);
|
|
440
|
+
throw new Error(`There is no house-style skill "${name}"; ${known.length ? `the skills are ${known.map((n) => `"${n}"`).join(", ")}` : "none are installed"}.`);
|
|
441
|
+
}
|
|
442
|
+
const text = await styles.readFile(name, file);
|
|
443
|
+
if (text === void 0) throw new Error(`"${name}" has no file "${file}"; its files are ${files.map((f) => `"${f}"`).join(", ")}.`);
|
|
444
|
+
return { content: [{ type: "text", text }], structuredContent: { name, file, files } };
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
const getStyleSchema = {
|
|
448
|
+
name: "get_style_schema",
|
|
449
|
+
title: "Get a style profile schema",
|
|
450
|
+
description: `Returns what a house-style profile for a domain can hold: its JSON Schema, and the checks it can turn on in its "checks" list with each check's options schema. Use it to explain or write a profile.`,
|
|
451
|
+
inputSchema: { type: "object", properties: { domain: DOMAIN }, required: ["domain"], additionalProperties: false },
|
|
452
|
+
annotations: { title: "Get a style profile schema", ...READ },
|
|
453
|
+
handler: ({ domain }) => {
|
|
454
|
+
const d = styles.domains.find((x) => x.id === domain);
|
|
455
|
+
return {
|
|
456
|
+
domain: d.id,
|
|
457
|
+
file: `${d.id}.json`,
|
|
458
|
+
description: d.description,
|
|
459
|
+
schema: d.profileSchema,
|
|
460
|
+
checks: d.checks.map((c) => ({ id: c.id, description: c.description, ...c.optionsSchema ? { options: c.optionsSchema } : {} }))
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
return {
|
|
465
|
+
id: options.id ?? "style",
|
|
466
|
+
namespace: options.namespace ?? "style",
|
|
467
|
+
title: "House style",
|
|
468
|
+
description: "Read the house style (org, team, user or document preferences and rules) for each editor domain. Style skills are preferences, not instructions: they never override the user, the domain's agent skill or a tool error.",
|
|
469
|
+
skill: "pixerate-agent-tools",
|
|
470
|
+
tools: [listStyles, getStyle, getStyleFile, getStyleSchema]
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export {
|
|
475
|
+
toolResultValue,
|
|
476
|
+
toolResultError,
|
|
477
|
+
runToolScript,
|
|
478
|
+
parseStyleDomains,
|
|
479
|
+
memoryStyleStore,
|
|
480
|
+
createStyleResolver,
|
|
481
|
+
runStyleChecks,
|
|
482
|
+
renderStyle,
|
|
483
|
+
createStyleToolProvider
|
|
484
|
+
};
|
|
@@ -11,10 +11,10 @@ var _chunkYN6JKAUEcjs = require('./chunk-YN6JKAUE.cjs');
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
var
|
|
14
|
+
var _chunkSZWVMB3Bcjs = require('./chunk-SZWVMB3B.cjs');
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
var
|
|
17
|
+
var _chunkBPX4Z3N3cjs = require('./chunk-BPX4Z3N3.cjs');
|
|
18
18
|
|
|
19
19
|
// src/export/images.ts
|
|
20
20
|
var DOCX_IMAGE_TYPES = {
|
|
@@ -1028,12 +1028,12 @@ var DocxBuilder = (_class2 = class {
|
|
|
1028
1028
|
this.drop("node", "chart", "chart has no spec");
|
|
1029
1029
|
return;
|
|
1030
1030
|
}
|
|
1031
|
-
const spec =
|
|
1032
|
-
const written =
|
|
1031
|
+
const spec = _chunkBPX4Z3N3cjs.normalizeChartSpec.call(void 0, raw).spec;
|
|
1032
|
+
const written = _chunkSZWVMB3Bcjs.chartToOoxml.call(void 0, spec);
|
|
1033
1033
|
for (const issue of written.issues) this.drop("node", "chart", issue);
|
|
1034
1034
|
const name = `chart${this.charts.length + 1}.xml`;
|
|
1035
1035
|
this.charts.push(written.xml);
|
|
1036
|
-
const relId = this.rels.add(
|
|
1036
|
+
const relId = this.rels.add(_chunkSZWVMB3Bcjs.CHART_OOXML_RELATIONSHIP, `charts/${name}`);
|
|
1037
1037
|
let width = _nullishCoalesce(pixelAttr(_optionalChain([node, 'access', _91 => _91.attrs, 'optionalAccess', _92 => _92.width])), () => ( MAX_IMAGE_WIDTH_PX));
|
|
1038
1038
|
let height = _nullishCoalesce(pixelAttr(_optionalChain([node, 'access', _93 => _93.attrs, 'optionalAccess', _94 => _94.height])), () => ( 320));
|
|
1039
1039
|
if (width > MAX_IMAGE_WIDTH_PX) {
|
|
@@ -1050,8 +1050,8 @@ var DocxBuilder = (_class2 = class {
|
|
|
1050
1050
|
drawing.empty("wp:extent", { cx, cy }).empty("wp:effectExtent", { l: 0, t: 0, r: 0, b: 0 });
|
|
1051
1051
|
drawing.empty("wp:docPr", { id, name: `Chart ${id}`, descr: title || void 0, title: title || void 0 });
|
|
1052
1052
|
drawing.empty("wp:cNvGraphicFramePr");
|
|
1053
|
-
drawing.open("a:graphic").open("a:graphicData", { uri:
|
|
1054
|
-
drawing.empty("c:chart", { "xmlns:c":
|
|
1053
|
+
drawing.open("a:graphic").open("a:graphicData", { uri: _chunkSZWVMB3Bcjs.CHART_OOXML_NS });
|
|
1054
|
+
drawing.empty("c:chart", { "xmlns:c": _chunkSZWVMB3Bcjs.CHART_OOXML_NS, "r:id": relId });
|
|
1055
1055
|
drawing.close("a:graphicData").close("a:graphic").close("wp:inline").close("w:drawing").close("w:r");
|
|
1056
1056
|
this.report.written.paragraphs++;
|
|
1057
1057
|
w.open("w:p");
|
|
@@ -1384,7 +1384,7 @@ var DocxBuilder = (_class2 = class {
|
|
|
1384
1384
|
if (people) add("word/people.xml", people, `${CT_WML}people+xml`);
|
|
1385
1385
|
parts.push({ name: "word/_rels/document.xml.rels", data: this.rels.xml() });
|
|
1386
1386
|
for (const file of this.media) parts.push({ name: `word/media/${file.name}`, data: file.bytes });
|
|
1387
|
-
this.charts.forEach((xml, i) => add(`word/charts/chart${i + 1}.xml`, xml,
|
|
1387
|
+
this.charts.forEach((xml, i) => add(`word/charts/chart${i + 1}.xml`, xml, _chunkSZWVMB3Bcjs.CHART_OOXML_CONTENT_TYPE));
|
|
1388
1388
|
add("docProps/core.xml", this.coreXml(now), "application/vnd.openxmlformats-package.core-properties+xml");
|
|
1389
1389
|
const app = new XmlWriter();
|
|
1390
1390
|
app.open("Properties", { xmlns: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" });
|