@pixerate/editor 0.265.0 → 0.266.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/dist/agent/index.cjs +4 -3
- package/dist/agent/index.js +3 -2
- package/dist/animation-editor/index.cjs +59 -59
- package/dist/animation-editor/index.js +3 -3
- package/dist/brushes/index.cjs +56 -56
- package/dist/brushes/index.js +3 -3
- package/dist/brushes/presets.d.cts +3 -3
- package/dist/brushes/presets.d.ts +3 -3
- package/dist/brushes/resolve.d.cts +1 -1
- package/dist/brushes/resolve.d.ts +1 -1
- package/dist/{brushstrokeRender-JQ2XQRUD.cjs → brushstrokeRender-FSUWXUZY.cjs} +15 -15
- package/dist/{brushstrokeRender-4UB6NRJW.js → brushstrokeRender-KD453OBX.js} +3 -3
- package/dist/canvas/index.cjs +15 -14
- package/dist/canvas/index.js +3 -2
- package/dist/{chunk-Q6RVVJW6.js → chunk-3C33YTNN.js} +1 -1
- package/dist/{chunk-NOP4Y5AB.cjs → chunk-3SBLVGOM.cjs} +23 -23
- package/dist/{chunk-TMDDMJCR.js → chunk-472INMWH.js} +4 -2
- package/dist/{chunk-ZS7LB2MV.js → chunk-4ODRXQRW.js} +1 -1
- package/dist/chunk-55ALHYJY.js +289 -0
- package/dist/{chunk-NHA26O5X.cjs → chunk-7KNW3WXZ.cjs} +14 -12
- package/dist/{chunk-O53MOGXG.cjs → chunk-AQZQWXEU.cjs} +35 -35
- package/dist/{chunk-J4SGJCPW.js → chunk-CIJBSUM5.js} +1133 -1806
- package/dist/{chunk-XDNWQMHY.js → chunk-DXYHQ2VN.js} +1 -1
- package/dist/chunk-E2Z4UARJ.cjs +289 -0
- package/dist/{chunk-BLR4KWYQ.js → chunk-EZOJBP4D.js} +1 -1
- package/dist/chunk-HAEB3MZD.js +664 -0
- package/dist/chunk-KIJIONZF.cjs +664 -0
- package/dist/{chunk-Z2Z2OHRM.js → chunk-LK4SXL3V.js} +1 -1
- package/dist/{chunk-DGXTEPCU.cjs → chunk-MVUQSK5J.cjs} +86 -86
- package/dist/{chunk-LPFQHVCO.js → chunk-PXXXRCME.js} +1 -284
- package/dist/{chunk-T7QSEKDY.cjs → chunk-QJVOJUTD.cjs} +4 -287
- package/dist/{chunk-WY23AUCA.js → chunk-R44Y3EFS.js} +1 -1
- package/dist/{chunk-677777GH.cjs → chunk-RFJZGTHA.cjs} +1137 -1810
- package/dist/{chunk-7PW6VCNW.js → chunk-T2LDTEXK.js} +1 -1
- package/dist/{chunk-7NQOGWLM.cjs → chunk-TOID45I2.cjs} +1 -1
- package/dist/{chunk-DEBIFWY6.cjs → chunk-VRK322ZC.cjs} +2 -2
- package/dist/{chunk-5OE4ZZ6V.cjs → chunk-WLUVZKVD.cjs} +30 -30
- package/dist/{chunk-ZHRVCW3M.cjs → chunk-XRXFVRGY.cjs} +10 -10
- package/dist/commands/index.cjs +26 -656
- package/dist/commands/index.js +18 -648
- package/dist/image-editor/index.cjs +786 -786
- package/dist/image-editor/index.js +4 -4
- package/dist/paint-editor/brush-model.d.cts +273 -0
- package/dist/paint-editor/brush-model.d.ts +273 -0
- package/dist/paint-editor/brushes.d.cts +6 -270
- package/dist/paint-editor/brushes.d.ts +6 -270
- package/dist/paint-editor/index.cjs +79 -79
- package/dist/paint-editor/index.js +5 -5
- package/dist/paint-editor/ui.d.cts +1 -1
- package/dist/paint-editor/ui.d.ts +1 -1
- package/dist/vector/contract.d.cts +52 -0
- package/dist/vector/contract.d.ts +52 -0
- package/dist/vector/index.cjs +1167 -969
- package/dist/vector/index.d.cts +1 -0
- package/dist/vector/index.d.ts +1 -0
- package/dist/vector/index.js +203 -5
- package/package.json +1 -1
package/dist/commands/index.js
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CommandRegistry,
|
|
3
|
+
CommandRegistryError,
|
|
4
|
+
DEFAULT_RECENT_LIMIT,
|
|
5
|
+
createCommandRegistry,
|
|
6
|
+
createCommandToolProvider,
|
|
7
|
+
defineCommand,
|
|
8
|
+
exactBonus,
|
|
9
|
+
fuzzyMatch,
|
|
10
|
+
fuzzyScore,
|
|
11
|
+
pushRecent,
|
|
12
|
+
rankCommands
|
|
13
|
+
} from "../chunk-HAEB3MZD.js";
|
|
1
14
|
import {
|
|
2
15
|
DEFAULT_HISTORY_SHORTCUTS,
|
|
3
16
|
createArrangeCommands,
|
|
@@ -9,7 +22,8 @@ import {
|
|
|
9
22
|
hasVariantCommands,
|
|
10
23
|
matchHistoryShortcut,
|
|
11
24
|
planFreehandPlayback
|
|
12
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-472INMWH.js";
|
|
26
|
+
import "../chunk-55ALHYJY.js";
|
|
13
27
|
import {
|
|
14
28
|
PLATFORMS,
|
|
15
29
|
ShortcutMap,
|
|
@@ -27,387 +41,14 @@ import {
|
|
|
27
41
|
parseChord,
|
|
28
42
|
shortcutCode,
|
|
29
43
|
toShortcutBindings
|
|
30
|
-
} from "../chunk-
|
|
31
|
-
import
|
|
32
|
-
derivePlaybackSteps
|
|
33
|
-
} from "../chunk-EHTX34RE.js";
|
|
44
|
+
} from "../chunk-PXXXRCME.js";
|
|
45
|
+
import "../chunk-EHTX34RE.js";
|
|
34
46
|
import {
|
|
35
47
|
createFormatCommands,
|
|
36
48
|
formatCommandsFor
|
|
37
49
|
} from "../chunk-NZ3CTY7K.js";
|
|
38
50
|
import "../chunk-IVSWRVB4.js";
|
|
39
|
-
import
|
|
40
|
-
validateJsonSchema
|
|
41
|
-
} from "../chunk-V2ZCJRDM.js";
|
|
42
|
-
|
|
43
|
-
// src/commands/registry.ts
|
|
44
|
-
var CommandRegistryError = class extends Error {
|
|
45
|
-
code;
|
|
46
|
-
constructor(code, message) {
|
|
47
|
-
super(message);
|
|
48
|
-
this.name = "CommandRegistryError";
|
|
49
|
-
this.code = code;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
var COMMAND_ID_REGEX = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
53
|
-
function enablement(result) {
|
|
54
|
-
if (result === void 0 || result === true) return { enabled: true };
|
|
55
|
-
if (result === false) return { enabled: false, reason: "This command is not available right now." };
|
|
56
|
-
return { enabled: false, reason: String(result) };
|
|
57
|
-
}
|
|
58
|
-
function unknownParams(spec, params) {
|
|
59
|
-
const keys = Object.keys(params).filter((k) => params[k] !== void 0);
|
|
60
|
-
if (keys.length === 0) return null;
|
|
61
|
-
const schema = spec.params;
|
|
62
|
-
if (schema && schema.additionalProperties !== void 0 && schema.additionalProperties !== false) return null;
|
|
63
|
-
const accepted = Object.keys(schema?.properties ?? {});
|
|
64
|
-
const bad = keys.find((k) => !accepted.includes(k));
|
|
65
|
-
if (!bad) return null;
|
|
66
|
-
return `Unknown parameter "${bad}" for command "${spec.id}"; expected ${accepted.length ? accepted.map((k) => `"${k}"`).join(", ") : "no parameters"}.`;
|
|
67
|
-
}
|
|
68
|
-
var isThenable = (value) => !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
69
|
-
var CommandRegistry = class {
|
|
70
|
-
/** Shortcut bindings of the registered commands (plus any user overrides). */
|
|
71
|
-
shortcuts;
|
|
72
|
-
commands = /* @__PURE__ */ new Map();
|
|
73
|
-
listeners = /* @__PURE__ */ new Set();
|
|
74
|
-
options;
|
|
75
|
-
version = 0;
|
|
76
|
-
// Set while register/unregister change the shortcut map, so they notify once.
|
|
77
|
-
muted = false;
|
|
78
|
-
constructor(options = {}) {
|
|
79
|
-
this.options = options;
|
|
80
|
-
this.shortcuts = new ShortcutMap([], options.shortcuts);
|
|
81
|
-
this.shortcuts.subscribe(() => {
|
|
82
|
-
if (!this.muted) this.notify();
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
/** Monotonic counter bumped on every change (useful as a snapshot key). */
|
|
86
|
-
getVersion() {
|
|
87
|
-
return this.version;
|
|
88
|
-
}
|
|
89
|
-
/** The default context. */
|
|
90
|
-
get context() {
|
|
91
|
-
const ctx = this.options.context;
|
|
92
|
-
return typeof ctx === "function" ? ctx() : ctx;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Registers a command (or several) and returns a function that unregisters it.
|
|
96
|
-
* Throws a `CommandRegistryError` for a duplicate or invalid id, or invalid chord text.
|
|
97
|
-
*/
|
|
98
|
-
register(spec) {
|
|
99
|
-
const specs = Array.isArray(spec) ? spec : [spec];
|
|
100
|
-
const seen = /* @__PURE__ */ new Set();
|
|
101
|
-
for (const s of specs) {
|
|
102
|
-
if (!s || typeof s.id !== "string" || !COMMAND_ID_REGEX.test(s.id)) {
|
|
103
|
-
throw new CommandRegistryError("invalid_command", `Invalid command id "${s?.id}".`);
|
|
104
|
-
}
|
|
105
|
-
if (typeof s.run !== "function") {
|
|
106
|
-
throw new CommandRegistryError("invalid_command", `Command "${s.id}" has no run function.`);
|
|
107
|
-
}
|
|
108
|
-
if (this.commands.has(s.id) || seen.has(s.id)) {
|
|
109
|
-
throw new CommandRegistryError("duplicate_command", `Command "${s.id}" is already registered.`);
|
|
110
|
-
}
|
|
111
|
-
seen.add(s.id);
|
|
112
|
-
}
|
|
113
|
-
const bindings = specs.map((s) => toShortcutBindings(s.id, s.shortcut, s.scope));
|
|
114
|
-
const unbinds = [];
|
|
115
|
-
this.muted = true;
|
|
116
|
-
try {
|
|
117
|
-
for (const b of bindings) unbinds.push(this.shortcuts.bind(b));
|
|
118
|
-
} catch (error) {
|
|
119
|
-
unbinds.forEach((u) => u());
|
|
120
|
-
throw new CommandRegistryError("invalid_command", error instanceof Error ? error.message : String(error));
|
|
121
|
-
} finally {
|
|
122
|
-
this.muted = false;
|
|
123
|
-
}
|
|
124
|
-
specs.forEach((s, i) => this.commands.set(s.id, { spec: s, unbind: unbinds[i] }));
|
|
125
|
-
this.notify();
|
|
126
|
-
let registered = true;
|
|
127
|
-
return () => {
|
|
128
|
-
if (!registered) return;
|
|
129
|
-
registered = false;
|
|
130
|
-
let changed = false;
|
|
131
|
-
for (const s of specs) {
|
|
132
|
-
const entry = this.commands.get(s.id);
|
|
133
|
-
if (entry && entry.spec === s) {
|
|
134
|
-
this.commands.delete(s.id);
|
|
135
|
-
this.unbindQuietly(entry);
|
|
136
|
-
changed = true;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (changed) this.notify();
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
/** Removes a command by id. Returns whether it was registered. */
|
|
143
|
-
unregister(id) {
|
|
144
|
-
const entry = this.commands.get(id);
|
|
145
|
-
if (!entry) return false;
|
|
146
|
-
this.commands.delete(id);
|
|
147
|
-
this.unbindQuietly(entry);
|
|
148
|
-
this.notify();
|
|
149
|
-
return true;
|
|
150
|
-
}
|
|
151
|
-
unbindQuietly(entry) {
|
|
152
|
-
this.muted = true;
|
|
153
|
-
try {
|
|
154
|
-
entry.unbind();
|
|
155
|
-
} finally {
|
|
156
|
-
this.muted = false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
has(id) {
|
|
160
|
-
return this.commands.has(id);
|
|
161
|
-
}
|
|
162
|
-
get(id) {
|
|
163
|
-
return this.commands.get(id)?.spec;
|
|
164
|
-
}
|
|
165
|
-
/** Registered ids in registration order. */
|
|
166
|
-
ids() {
|
|
167
|
-
return [...this.commands.keys()];
|
|
168
|
-
}
|
|
169
|
-
/** Whether `id` can run now (`{ enabled, reason }`); `params` are the targets a caller named. */
|
|
170
|
-
isEnabled(id, params, context = this.context) {
|
|
171
|
-
const spec = this.get(id);
|
|
172
|
-
if (!spec) return { enabled: false, reason: `Unknown command "${id}".` };
|
|
173
|
-
if (!spec.enabled) return { enabled: true };
|
|
174
|
-
try {
|
|
175
|
-
return enablement(spec.enabled(context, params));
|
|
176
|
-
} catch (error) {
|
|
177
|
-
return { enabled: false, reason: error instanceof Error ? error.message : String(error) };
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
/** Commands for menus, palettes and agents, with their current enablement. */
|
|
181
|
-
list(options = {}) {
|
|
182
|
-
const scopes = options.scope === void 0 ? null : typeof options.scope === "string" ? [options.scope] : options.scope;
|
|
183
|
-
const context = "context" in options ? options.context : this.context;
|
|
184
|
-
const platform = this.shortcuts.platform;
|
|
185
|
-
const out = [];
|
|
186
|
-
for (const { spec } of this.commands.values()) {
|
|
187
|
-
if (spec.hidden && !options.includeHidden) continue;
|
|
188
|
-
if (scopes && spec.scope !== void 0 && !scopes.includes(spec.scope)) continue;
|
|
189
|
-
const { enabled, reason } = this.isEnabled(spec.id, void 0, context);
|
|
190
|
-
if (options.enabledOnly && !enabled) continue;
|
|
191
|
-
out.push({
|
|
192
|
-
id: spec.id,
|
|
193
|
-
label: spec.label,
|
|
194
|
-
...spec.group !== void 0 ? { group: spec.group } : {},
|
|
195
|
-
...spec.keywords ? { keywords: spec.keywords } : {},
|
|
196
|
-
...spec.description !== void 0 ? { description: spec.description } : {},
|
|
197
|
-
...spec.params ? { params: spec.params } : {},
|
|
198
|
-
...spec.scope !== void 0 ? { scope: spec.scope } : {},
|
|
199
|
-
shortcuts: this.shortcuts.forCommand(spec.id, platform),
|
|
200
|
-
enabled,
|
|
201
|
-
...enabled ? {} : { disabledReason: reason },
|
|
202
|
-
undoable: !!spec.undoable,
|
|
203
|
-
readOnly: !!spec.readOnly
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
return out;
|
|
207
|
-
}
|
|
208
|
-
check(id, params, context) {
|
|
209
|
-
const spec = this.get(id);
|
|
210
|
-
if (!spec) return { ok: false, id, code: "unknown_command", message: `Unknown command "${id}".` };
|
|
211
|
-
const input = params ?? {};
|
|
212
|
-
if (typeof input !== "object" || Array.isArray(input)) {
|
|
213
|
-
return { ok: false, id, code: "invalid_params", message: `Parameters for command "${id}" must be an object.` };
|
|
214
|
-
}
|
|
215
|
-
const unknown = unknownParams(spec, input);
|
|
216
|
-
if (unknown) return { ok: false, id, code: "invalid_params", message: unknown };
|
|
217
|
-
if (spec.params) {
|
|
218
|
-
const details = validateJsonSchema(input, spec.params);
|
|
219
|
-
if (details.length > 0) {
|
|
220
|
-
return {
|
|
221
|
-
ok: false,
|
|
222
|
-
id,
|
|
223
|
-
code: "invalid_params",
|
|
224
|
-
message: `Invalid parameters for command "${id}": ${details.map((d) => `${d.path} ${d.message}`).join("; ")}`,
|
|
225
|
-
details
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
const { enabled, reason } = this.isEnabled(id, params === void 0 ? void 0 : input, context);
|
|
230
|
-
if (!enabled) return { ok: false, id, code: "disabled", message: reason ?? "Disabled." };
|
|
231
|
-
return { spec, params: input };
|
|
232
|
-
}
|
|
233
|
-
/** The history `undoable` commands (and atomic agent batches) record into, if any. */
|
|
234
|
-
get history() {
|
|
235
|
-
return this.options.history;
|
|
236
|
-
}
|
|
237
|
-
invoke(spec, params, context) {
|
|
238
|
-
const history = this.options.history;
|
|
239
|
-
if (!spec.undoable || !history) return spec.run(context, params);
|
|
240
|
-
let value;
|
|
241
|
-
history.batch(spec.label, () => {
|
|
242
|
-
value = spec.run(context, params);
|
|
243
|
-
});
|
|
244
|
-
return value;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Runs a command synchronously and returns a structured result; never throws.
|
|
248
|
-
* A command whose `run` returns a promise yields `{ ok: true, result: promise }`
|
|
249
|
-
* (use `executeAsync` to await it and catch its rejection).
|
|
250
|
-
*/
|
|
251
|
-
execute(id, params, context = this.context) {
|
|
252
|
-
const checked = this.check(id, params, context);
|
|
253
|
-
if ("ok" in checked) return checked;
|
|
254
|
-
try {
|
|
255
|
-
const result = this.invoke(checked.spec, checked.params, context);
|
|
256
|
-
this.notify();
|
|
257
|
-
return { ok: true, id, result };
|
|
258
|
-
} catch (error) {
|
|
259
|
-
this.notify();
|
|
260
|
-
return { ok: false, id, code: "failed", message: error instanceof Error ? error.message : String(error) };
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
/** Like `execute`, but awaits async commands (rejections become `failed` results). */
|
|
264
|
-
async executeAsync(id, params, context = this.context) {
|
|
265
|
-
const outcome = this.execute(id, params, context);
|
|
266
|
-
if (!outcome.ok || !isThenable(outcome.result)) return outcome;
|
|
267
|
-
try {
|
|
268
|
-
const result = await outcome.result;
|
|
269
|
-
this.notify();
|
|
270
|
-
return { ok: true, id, result };
|
|
271
|
-
} catch (error) {
|
|
272
|
-
this.notify();
|
|
273
|
-
return { ok: false, id, code: "failed", message: error instanceof Error ? error.message : String(error) };
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Resolves a keydown event to a command (see `ShortcutMap.resolve`) and runs it when
|
|
278
|
-
* enabled, calling `preventDefault()`. Disabled commands leave the event alone, so the
|
|
279
|
-
* browser or a focused editor can still handle it. Returns the result, or `null`.
|
|
280
|
-
*/
|
|
281
|
-
handleKeyDown(event, options = {}) {
|
|
282
|
-
if (event.defaultPrevented) return null;
|
|
283
|
-
const match = this.shortcuts.resolve(event, options);
|
|
284
|
-
if (!match) return null;
|
|
285
|
-
const context = "context" in options ? options.context : this.context;
|
|
286
|
-
if (!this.isEnabled(match.command, void 0, context).enabled) return null;
|
|
287
|
-
event.preventDefault?.();
|
|
288
|
-
return this.execute(match.command, void 0, context);
|
|
289
|
-
}
|
|
290
|
-
/** Display-ready primary shortcut of a command (`⇧⌘Z` / `Ctrl+Shift+Z`), or `undefined`. */
|
|
291
|
-
shortcutFor(id, platform = this.shortcuts.platform) {
|
|
292
|
-
return this.shortcuts.forCommand(id, platform)[0];
|
|
293
|
-
}
|
|
294
|
-
/**
|
|
295
|
-
* Subscribes to changes: commands registered or removed, shortcut overrides, executed
|
|
296
|
-
* commands and `invalidate()` calls (e.g. when enablement inputs change).
|
|
297
|
-
*/
|
|
298
|
-
subscribe(listener) {
|
|
299
|
-
this.listeners.add(listener);
|
|
300
|
-
return () => {
|
|
301
|
-
this.listeners.delete(listener);
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
/** Tells subscribers that enablement may have changed (e.g. the selection changed). */
|
|
305
|
-
invalidate() {
|
|
306
|
-
this.notify();
|
|
307
|
-
}
|
|
308
|
-
notify() {
|
|
309
|
-
this.version++;
|
|
310
|
-
for (const listener of Array.from(this.listeners)) {
|
|
311
|
-
try {
|
|
312
|
-
listener();
|
|
313
|
-
} catch (error) {
|
|
314
|
-
console.error("[CommandRegistry] Error in listener:", error);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
function createCommandRegistry(options) {
|
|
320
|
-
return new CommandRegistry(options);
|
|
321
|
-
}
|
|
322
|
-
function defineCommand(spec) {
|
|
323
|
-
return spec;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// src/commands/palette.ts
|
|
327
|
-
var WORD_SEPARATORS = /* @__PURE__ */ new Set([" ", "-", "_", ".", "/", ":", "\u203A", "("]);
|
|
328
|
-
function fuzzyMatch(query, text) {
|
|
329
|
-
const q = query.trim().toLowerCase();
|
|
330
|
-
if (!q) return { score: 0, indices: [] };
|
|
331
|
-
const t = text.toLowerCase();
|
|
332
|
-
let score = 0;
|
|
333
|
-
let ti = 0;
|
|
334
|
-
let last = -2;
|
|
335
|
-
const indices = [];
|
|
336
|
-
for (const qc of q) {
|
|
337
|
-
if (qc === " ") continue;
|
|
338
|
-
let found = false;
|
|
339
|
-
while (ti < t.length) {
|
|
340
|
-
if (t[ti] === qc) {
|
|
341
|
-
score += last === ti - 1 ? 8 : 1;
|
|
342
|
-
if (ti === 0 || WORD_SEPARATORS.has(t[ti - 1])) score += 5;
|
|
343
|
-
last = ti;
|
|
344
|
-
indices.push(ti);
|
|
345
|
-
ti++;
|
|
346
|
-
found = true;
|
|
347
|
-
break;
|
|
348
|
-
}
|
|
349
|
-
ti++;
|
|
350
|
-
}
|
|
351
|
-
if (!found) return null;
|
|
352
|
-
}
|
|
353
|
-
return { score: score - Math.floor(t.length / 8), indices };
|
|
354
|
-
}
|
|
355
|
-
function fuzzyScore(query, text) {
|
|
356
|
-
return fuzzyMatch(query, text)?.score ?? null;
|
|
357
|
-
}
|
|
358
|
-
function exactBonus(query, names) {
|
|
359
|
-
const q = query.trim().toLowerCase();
|
|
360
|
-
if (!q) return 0;
|
|
361
|
-
return names.some((n) => n.replace(/(…|\.\.\.)$/, "").trim().toLowerCase() === q) ? 1e3 : 0;
|
|
362
|
-
}
|
|
363
|
-
var DEFAULT_RECENT_LIMIT = 8;
|
|
364
|
-
function pushRecent(list, id, cap = DEFAULT_RECENT_LIMIT) {
|
|
365
|
-
return [id, ...list.filter((x) => x !== id)].slice(0, Math.max(0, cap));
|
|
366
|
-
}
|
|
367
|
-
function rankCommands(query, entries, options = {}) {
|
|
368
|
-
const recents = options.recents ?? [];
|
|
369
|
-
const disabledLast = options.disabledLast ?? true;
|
|
370
|
-
const q = query.trim();
|
|
371
|
-
let ranked;
|
|
372
|
-
if (!q) {
|
|
373
|
-
const byId = new Map(entries.map((e) => [e.id, e]));
|
|
374
|
-
const recentIds = [...new Set(recents)].filter((id) => byId.has(id)).slice(0, options.recentLimit ?? DEFAULT_RECENT_LIMIT);
|
|
375
|
-
const recentSet = new Set(recentIds);
|
|
376
|
-
ranked = recentIds.map((id, i) => ({ entry: byId.get(id), score: 1e3 - i, labelIndices: [], recent: true, order: i }));
|
|
377
|
-
if ((options.emptyQuery ?? "all") === "all") {
|
|
378
|
-
entries.forEach((entry, i) => {
|
|
379
|
-
if (!recentSet.has(entry.id)) ranked.push({ entry, score: 0, labelIndices: [], recent: false, order: recentIds.length + i });
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
} else {
|
|
383
|
-
ranked = [];
|
|
384
|
-
entries.forEach((entry, order) => {
|
|
385
|
-
const label = fuzzyMatch(q, entry.label);
|
|
386
|
-
const candidates = [];
|
|
387
|
-
if (label) candidates.push(label.score);
|
|
388
|
-
if (entry.group) {
|
|
389
|
-
const grouped = fuzzyScore(q, `${entry.group} ${entry.label}`);
|
|
390
|
-
if (grouped !== null) candidates.push(grouped - 1);
|
|
391
|
-
}
|
|
392
|
-
for (const keyword of entry.keywords ?? []) {
|
|
393
|
-
const s = fuzzyScore(q, keyword);
|
|
394
|
-
if (s !== null) candidates.push(s - 2);
|
|
395
|
-
}
|
|
396
|
-
const byId = fuzzyScore(q, entry.id);
|
|
397
|
-
if (byId !== null) candidates.push(byId - 3);
|
|
398
|
-
if (candidates.length === 0) return;
|
|
399
|
-
const recentIndex = recents.indexOf(entry.id);
|
|
400
|
-
const score = Math.max(...candidates) + exactBonus(q, [entry.label, ...entry.keywords ?? []]) + (recentIndex >= 0 ? Math.max(1, 4 - recentIndex) : 0);
|
|
401
|
-
ranked.push({ entry, score, labelIndices: label?.indices ?? [], recent: false, order });
|
|
402
|
-
});
|
|
403
|
-
ranked.sort((a, b) => b.score - a.score || a.entry.label.length - b.entry.label.length || a.order - b.order);
|
|
404
|
-
}
|
|
405
|
-
if (disabledLast) {
|
|
406
|
-
ranked = [...ranked.filter((r) => r.entry.enabled !== false), ...ranked.filter((r) => r.entry.enabled === false)];
|
|
407
|
-
}
|
|
408
|
-
const out = ranked.map(({ order: _order, ...rest }) => rest);
|
|
409
|
-
return options.limit !== void 0 ? out.slice(0, options.limit) : out;
|
|
410
|
-
}
|
|
51
|
+
import "../chunk-V2ZCJRDM.js";
|
|
411
52
|
|
|
412
53
|
// src/commands/paletteController.ts
|
|
413
54
|
function createCommandPaletteController(registry, options = {}) {
|
|
@@ -560,277 +201,6 @@ function matchPaletteHotkey(event, hotkey, platform) {
|
|
|
560
201
|
return map.resolve(event) !== null;
|
|
561
202
|
}
|
|
562
203
|
|
|
563
|
-
// src/commands/agentTools.ts
|
|
564
|
-
var toJson = (value) => {
|
|
565
|
-
if (value === void 0) return null;
|
|
566
|
-
try {
|
|
567
|
-
return JSON.parse(JSON.stringify(value));
|
|
568
|
-
} catch {
|
|
569
|
-
return String(value);
|
|
570
|
-
}
|
|
571
|
-
};
|
|
572
|
-
function errorResult(result) {
|
|
573
|
-
return {
|
|
574
|
-
isError: true,
|
|
575
|
-
content: [{ type: "text", text: `${result.code}: ${result.message}` }],
|
|
576
|
-
structuredContent: {
|
|
577
|
-
error: { code: result.code, message: result.message, command: result.id, ...result.details ? { details: result.details } : {} }
|
|
578
|
-
}
|
|
579
|
-
};
|
|
580
|
-
}
|
|
581
|
-
function createCommandToolProvider(registry, options = {}) {
|
|
582
|
-
const context = () => {
|
|
583
|
-
const c = options.context;
|
|
584
|
-
if (c === void 0) return registry.context;
|
|
585
|
-
return typeof c === "function" ? c() : c;
|
|
586
|
-
};
|
|
587
|
-
const visible = () => registry.list({ scope: options.scope, context: context() }).filter((e) => !options.exclude?.(e.id));
|
|
588
|
-
const allowed = (id) => registry.has(id) && !options.exclude?.(id) && visible().some((e) => e.id === id);
|
|
589
|
-
function resolveRefs(value, results) {
|
|
590
|
-
if (typeof value === "string") {
|
|
591
|
-
const m = /^\$(\d+|last)((?:\.[\w-]+|\[\d+\])*)$/.exec(value);
|
|
592
|
-
if (!m) return value;
|
|
593
|
-
const index = m[1] === "last" ? results.length - 1 : Number(m[1]);
|
|
594
|
-
if (index < 0 || index >= results.length) throw new Error(`"${value}" refers to step ${m[1]}, but only ${results.length} step${results.length === 1 ? " has" : "s have"} run.`);
|
|
595
|
-
let cur = results[index];
|
|
596
|
-
for (const part of m[2].match(/[\w-]+/g) ?? []) {
|
|
597
|
-
if (cur === null || typeof cur !== "object" || !(part in cur)) throw new Error(`"${value}": step ${index}'s result has no "${part}".`);
|
|
598
|
-
cur = cur[part];
|
|
599
|
-
}
|
|
600
|
-
return cur;
|
|
601
|
-
}
|
|
602
|
-
if (Array.isArray(value)) return value.map((v) => resolveRefs(v, results));
|
|
603
|
-
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, resolveRefs(v, results)]));
|
|
604
|
-
return value;
|
|
605
|
-
}
|
|
606
|
-
async function runOne(id, params) {
|
|
607
|
-
if (!allowed(id)) return { ok: false, id, code: "unknown_command", message: `Unknown command "${id}".` };
|
|
608
|
-
return registry.executeAsync(id, params ?? {}, context());
|
|
609
|
-
}
|
|
610
|
-
function planOne(id, params) {
|
|
611
|
-
const spec = registry.get(id);
|
|
612
|
-
if (!spec) return null;
|
|
613
|
-
const surface = spec.playbackSurface ?? spec.scope ?? (id.includes(".") ? id.slice(0, id.indexOf(".")) : void 0);
|
|
614
|
-
const planned = spec.plan?.(context(), params ?? {});
|
|
615
|
-
const own = !planned ? [] : Array.isArray(planned) ? planned : planned.steps;
|
|
616
|
-
const steps = own.length ? own : derivePlaybackSteps(params);
|
|
617
|
-
return {
|
|
618
|
-
steps,
|
|
619
|
-
...surface ? { surface } : {},
|
|
620
|
-
...planned && !Array.isArray(planned) && planned.surface ? { surface: planned.surface } : {},
|
|
621
|
-
...spec.readOnly ? { readOnly: true } : {}
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
const hasRefs = (value) => typeof value === "string" ? value.startsWith("$") : Array.isArray(value) ? value.some(hasRefs) : !!value && typeof value === "object" && Object.values(value).some(hasRefs);
|
|
625
|
-
const listCommands = {
|
|
626
|
-
name: "list_commands",
|
|
627
|
-
title: "List commands",
|
|
628
|
-
description: "Lists the commands you can run with run_command: id, label, group, params (JSON Schema), shortcuts, and whether each is enabled now (with the reason when it is not).",
|
|
629
|
-
inputSchema: {
|
|
630
|
-
type: "object",
|
|
631
|
-
properties: {
|
|
632
|
-
query: { type: "string", description: "Fuzzy filter on label, keywords, group and id." },
|
|
633
|
-
enabledOnly: { type: "boolean", description: "Only commands that can run now (default false)." }
|
|
634
|
-
},
|
|
635
|
-
additionalProperties: false
|
|
636
|
-
},
|
|
637
|
-
annotations: { title: "List commands", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
638
|
-
handler: ({ query = "", enabledOnly = false }) => {
|
|
639
|
-
let entries = visible();
|
|
640
|
-
if (enabledOnly) entries = entries.filter((e) => e.enabled);
|
|
641
|
-
if (String(query).trim()) entries = rankCommands(String(query), entries, { disabledLast: false }).map((r) => r.entry);
|
|
642
|
-
return {
|
|
643
|
-
commands: entries.map((e) => ({
|
|
644
|
-
id: e.id,
|
|
645
|
-
label: e.label,
|
|
646
|
-
...e.group ? { group: e.group } : {},
|
|
647
|
-
...e.description ? { description: e.description } : {},
|
|
648
|
-
...e.params ? { params: e.params } : {},
|
|
649
|
-
...e.shortcuts.length ? { shortcuts: e.shortcuts } : {},
|
|
650
|
-
enabled: e.enabled,
|
|
651
|
-
...e.disabledReason ? { disabledReason: e.disabledReason } : {},
|
|
652
|
-
readOnly: e.readOnly
|
|
653
|
-
}))
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
};
|
|
657
|
-
const runCommandTool = () => {
|
|
658
|
-
const ids = visible().map((e) => e.id);
|
|
659
|
-
return {
|
|
660
|
-
name: "run_command",
|
|
661
|
-
title: "Run a command",
|
|
662
|
-
description: "Runs one command by id with optional params (see list_commands for each command's params schema). Unknown params are rejected.",
|
|
663
|
-
inputSchema: {
|
|
664
|
-
type: "object",
|
|
665
|
-
properties: {
|
|
666
|
-
id: { type: "string", description: "Command id from list_commands.", ...ids.length ? { enum: ids } : {} },
|
|
667
|
-
params: { type: "object", description: "Command parameters." }
|
|
668
|
-
},
|
|
669
|
-
required: ["id"],
|
|
670
|
-
additionalProperties: false
|
|
671
|
-
},
|
|
672
|
-
annotations: { title: "Run a command", readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
|
|
673
|
-
plan: ({ id, params }) => planOne(String(id), params),
|
|
674
|
-
handler: async ({ id, params }) => {
|
|
675
|
-
const result = await runOne(String(id), params);
|
|
676
|
-
return result.ok ? { id: result.id, ok: true, result: toJson(result.result) } : errorResult(result);
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
};
|
|
680
|
-
const runCommands = {
|
|
681
|
-
name: "run_commands",
|
|
682
|
-
title: "Run several commands",
|
|
683
|
-
description: `Runs several commands in order: {steps: [{id, params?}], stopOnError?: true, atomic?: false, label?}. A param string "$0.id" or "$last.id" is replaced by that path of an earlier step's result, so you can use an id a step created without another round trip. Not atomic by default (each step is its own undo step and steps before a failure stay applied); atomic: true makes the batch one undo step named label and takes everything back if a step fails. Returns {completed, failed, skipped, results: [{id, ok, result | code, message}]}.`,
|
|
684
|
-
inputSchema: {
|
|
685
|
-
type: "object",
|
|
686
|
-
properties: {
|
|
687
|
-
steps: {
|
|
688
|
-
type: "array",
|
|
689
|
-
minItems: 1,
|
|
690
|
-
maxItems: 256,
|
|
691
|
-
description: "Commands to run in order (at most 256).",
|
|
692
|
-
items: {
|
|
693
|
-
type: "object",
|
|
694
|
-
properties: {
|
|
695
|
-
id: { type: "string", description: "Command id." },
|
|
696
|
-
params: { type: "object", description: 'Command parameters; strings like "$0.id" or "$last.series[0]" refer to earlier results.' }
|
|
697
|
-
},
|
|
698
|
-
required: ["id"],
|
|
699
|
-
additionalProperties: false
|
|
700
|
-
}
|
|
701
|
-
},
|
|
702
|
-
stopOnError: { type: "boolean", description: "Stop at the first failing step (default true). Ignored when atomic." },
|
|
703
|
-
atomic: { type: "boolean", description: "Run every step as one undo step, all or nothing (default false). Needs a registry created with a history." },
|
|
704
|
-
label: { type: "string", description: 'Undo step name for an atomic batch (default "Run commands").' }
|
|
705
|
-
},
|
|
706
|
-
required: ["steps"],
|
|
707
|
-
additionalProperties: false
|
|
708
|
-
},
|
|
709
|
-
annotations: {
|
|
710
|
-
title: "Run several commands",
|
|
711
|
-
readOnlyHint: false,
|
|
712
|
-
destructiveHint: true,
|
|
713
|
-
idempotentHint: false,
|
|
714
|
-
openWorldHint: false
|
|
715
|
-
},
|
|
716
|
-
// Plays the steps' own plans one after another, then runs the batch once. Steps whose
|
|
717
|
-
// params refer to earlier results can't be planned before the batch runs and are skipped.
|
|
718
|
-
plan: ({ steps }) => {
|
|
719
|
-
const list = steps ?? [];
|
|
720
|
-
let surface;
|
|
721
|
-
const out = [];
|
|
722
|
-
for (const s of list) {
|
|
723
|
-
if (hasRefs(s.params)) continue;
|
|
724
|
-
const planned = planOne(s.id, s.params);
|
|
725
|
-
if (!planned) continue;
|
|
726
|
-
surface ??= planned.surface;
|
|
727
|
-
if (planned.surface && planned.surface !== surface) continue;
|
|
728
|
-
out.push(...planned.steps.filter((step) => step.type !== "commit"));
|
|
729
|
-
}
|
|
730
|
-
return out.length || surface ? { steps: out.length ? [...out, { type: "commit" }] : [], ...surface ? { surface } : {} } : null;
|
|
731
|
-
},
|
|
732
|
-
handler: async ({ steps, stopOnError = true, atomic = false, label = "Run commands" }) => {
|
|
733
|
-
let completed = 0;
|
|
734
|
-
let failed = 0;
|
|
735
|
-
const results = [];
|
|
736
|
-
const values = [];
|
|
737
|
-
const list = steps;
|
|
738
|
-
const step = (s, run) => {
|
|
739
|
-
let params;
|
|
740
|
-
try {
|
|
741
|
-
params = resolveRefs(s.params, values);
|
|
742
|
-
} catch (error) {
|
|
743
|
-
failed++;
|
|
744
|
-
results.push({ id: s.id, ok: false, code: "invalid_params", message: error.message });
|
|
745
|
-
return false;
|
|
746
|
-
}
|
|
747
|
-
const result = run(s.id, params);
|
|
748
|
-
if (result.ok) {
|
|
749
|
-
completed++;
|
|
750
|
-
const value = toJson(result.result);
|
|
751
|
-
values.push(value);
|
|
752
|
-
results.push({ id: result.id, ok: true, result: value });
|
|
753
|
-
return true;
|
|
754
|
-
}
|
|
755
|
-
failed++;
|
|
756
|
-
values.push(null);
|
|
757
|
-
results.push({ id: result.id, ok: false, code: result.code, message: result.message });
|
|
758
|
-
return false;
|
|
759
|
-
};
|
|
760
|
-
if (atomic) {
|
|
761
|
-
const history = registry.history;
|
|
762
|
-
if (!history) {
|
|
763
|
-
const message = "atomic batches need a CommandRegistry created with { history }; run the steps without atomic, or ask the host to share its history.";
|
|
764
|
-
return { isError: true, content: [{ type: "text", text: message }], structuredContent: { error: { code: "unsupported", message } } };
|
|
765
|
-
}
|
|
766
|
-
const syncRun = (id, params) => {
|
|
767
|
-
if (!allowed(id)) return { ok: false, id, code: "unknown_command", message: `Unknown command "${id}".` };
|
|
768
|
-
const r = registry.execute(id, params ?? {}, context());
|
|
769
|
-
if (r.ok && r.result && typeof r.result.then === "function") return { ok: false, id, code: "failed", message: `"${id}" runs asynchronously and cannot be part of an atomic batch.` };
|
|
770
|
-
return r;
|
|
771
|
-
};
|
|
772
|
-
try {
|
|
773
|
-
history.batch(String(label), () => {
|
|
774
|
-
for (const s of list) if (!step(s, syncRun)) throw new Error("rollback");
|
|
775
|
-
});
|
|
776
|
-
} catch {
|
|
777
|
-
}
|
|
778
|
-
const summary2 = { completed: failed ? 0 : completed, failed, skipped: list.length - completed - failed, rolledBack: failed > 0, results };
|
|
779
|
-
return failed > 0 ? { isError: true, content: [{ type: "text", text: JSON.stringify(summary2) }], structuredContent: summary2 } : summary2;
|
|
780
|
-
}
|
|
781
|
-
for (const s of list) {
|
|
782
|
-
let params;
|
|
783
|
-
try {
|
|
784
|
-
params = resolveRefs(s.params, values);
|
|
785
|
-
} catch (error) {
|
|
786
|
-
failed++;
|
|
787
|
-
values.push(null);
|
|
788
|
-
results.push({ id: s.id, ok: false, code: "invalid_params", message: error.message });
|
|
789
|
-
if (stopOnError) break;
|
|
790
|
-
continue;
|
|
791
|
-
}
|
|
792
|
-
const result = await runOne(s.id, params);
|
|
793
|
-
if (result.ok) {
|
|
794
|
-
completed++;
|
|
795
|
-
const value = toJson(result.result);
|
|
796
|
-
values.push(value);
|
|
797
|
-
results.push({ id: result.id, ok: true, result: value });
|
|
798
|
-
} else {
|
|
799
|
-
failed++;
|
|
800
|
-
values.push(null);
|
|
801
|
-
results.push({ id: result.id, ok: false, code: result.code, message: result.message });
|
|
802
|
-
if (stopOnError) break;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
const summary = { completed, failed, skipped: list.length - completed - failed, results };
|
|
806
|
-
return failed > 0 ? { isError: true, content: [{ type: "text", text: JSON.stringify(summary) }], structuredContent: summary } : summary;
|
|
807
|
-
}
|
|
808
|
-
};
|
|
809
|
-
const picked = (id) => typeof options.tools === "function" ? options.tools(id) : !!options.tools?.includes(id);
|
|
810
|
-
const toolNameOf = (id) => options.toolName?.(id) ?? id.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
811
|
-
const commandTool = (entry) => ({
|
|
812
|
-
name: toolNameOf(entry.id),
|
|
813
|
-
title: entry.label,
|
|
814
|
-
description: `${entry.description ?? entry.label}${entry.readOnly ? "" : ` (Runs the "${entry.id}" command; refused with the reason when it cannot run now.)`}`,
|
|
815
|
-
inputSchema: entry.params ?? { type: "object", properties: {}, additionalProperties: false },
|
|
816
|
-
annotations: { title: entry.label, readOnlyHint: entry.readOnly, destructiveHint: !entry.readOnly, idempotentHint: entry.readOnly, openWorldHint: false },
|
|
817
|
-
plan: (args) => planOne(entry.id, args),
|
|
818
|
-
handler: async (args) => {
|
|
819
|
-
const result = await runOne(entry.id, args);
|
|
820
|
-
return result.ok ? toJson(result.result) : errorResult(result);
|
|
821
|
-
}
|
|
822
|
-
});
|
|
823
|
-
return {
|
|
824
|
-
id: options.id ?? "commands",
|
|
825
|
-
namespace: options.namespace,
|
|
826
|
-
title: "Commands",
|
|
827
|
-
description: "The app's commands (menu and keyboard actions) with their params schemas: list them, run one, or run several as one undo step.",
|
|
828
|
-
skill: "pixerate-agent-tools",
|
|
829
|
-
tools: () => [listCommands, runCommandTool(), runCommands, ...options.tools ? visible().filter((e) => picked(e.id)).map(commandTool) : []],
|
|
830
|
-
subscribe: (notify) => registry.subscribe(notify)
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
|
|
834
204
|
// src/commands/animation.ts
|
|
835
205
|
var EASING_DESCRIPTION = "Easing preset (linear, ease, ease-in, ease-out, ease-in-out, ease-in-back, ease-out-back, spring, hold) or a CSS cubic-bezier(x1, y1, x2, y2).";
|
|
836
206
|
var VALUES = {
|