@pixerate/editor 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -13
- package/THIRD_PARTY_NOTICES.md +88 -0
- package/dist/agent/index.cjs +86 -111
- package/dist/agent/index.cjs.map +1 -1
- package/dist/agent/index.d.cts +69 -211
- package/dist/agent/index.d.ts +69 -211
- package/dist/agent/index.js +77 -102
- package/dist/agent/index.js.map +1 -1
- package/dist/arrangeShortcuts-B8O3f8-P.d.cts +184 -0
- package/dist/arrangeShortcuts-sLlD2rSX.d.ts +184 -0
- package/dist/canvas/index.cjs +2112 -60
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +712 -181
- package/dist/canvas/index.d.ts +712 -181
- package/dist/canvas/index.js +2105 -53
- package/dist/canvas/index.js.map +1 -1
- package/dist/chunk-26BVFKHU.cjs +453 -0
- package/dist/chunk-26BVFKHU.cjs.map +1 -0
- package/dist/chunk-2H7ZHPEJ.js +762 -0
- package/dist/chunk-2H7ZHPEJ.js.map +1 -0
- package/dist/chunk-7DWMJCAT.js +453 -0
- package/dist/chunk-7DWMJCAT.js.map +1 -0
- package/dist/{chunk-TVRC4KVT.cjs → chunk-AA4ZEVCC.cjs} +845 -90
- package/dist/chunk-AA4ZEVCC.cjs.map +1 -0
- package/dist/chunk-ARRTP33I.js +101 -0
- package/dist/chunk-ARRTP33I.js.map +1 -0
- package/dist/{chunk-LA7PEGU3.cjs → chunk-CL37JGFW.cjs} +4 -4
- package/dist/{chunk-LA7PEGU3.cjs.map → chunk-CL37JGFW.cjs.map} +1 -1
- package/dist/chunk-CPOKFNBG.cjs +101 -0
- package/dist/chunk-CPOKFNBG.cjs.map +1 -0
- package/dist/chunk-G2I4QJOT.cjs +762 -0
- package/dist/chunk-G2I4QJOT.cjs.map +1 -0
- package/dist/{chunk-4QPLEUL2.cjs → chunk-GVSMRPHB.cjs} +1046 -54
- package/dist/chunk-GVSMRPHB.cjs.map +1 -0
- package/dist/{chunk-KYRZDWM4.js → chunk-JJDLPEWL.js} +2 -2
- package/dist/{chunk-GVW4P7BG.js → chunk-K3R5NG2D.js} +448 -54
- package/dist/chunk-K3R5NG2D.js.map +1 -0
- package/dist/{chunk-3TYMNULT.js → chunk-MJZBNWG7.js} +807 -52
- package/dist/chunk-MJZBNWG7.js.map +1 -0
- package/dist/{chunk-A7DKIA72.js → chunk-QBJ22YZR.js} +1059 -93
- package/dist/chunk-QBJ22YZR.js.map +1 -0
- package/dist/{chunk-CYFJCKC4.js → chunk-QGHGJ56O.js} +997 -5
- package/dist/chunk-QGHGJ56O.js.map +1 -0
- package/dist/{chunk-JYRIOFEN.cjs → chunk-RIKBJLS2.cjs} +1064 -98
- package/dist/chunk-RIKBJLS2.cjs.map +1 -0
- package/dist/{chunk-U6NDQFOK.cjs → chunk-XDMXXC4Z.cjs} +569 -175
- package/dist/chunk-XDMXXC4Z.cjs.map +1 -0
- package/dist/commands/index.cjs +860 -0
- package/dist/commands/index.cjs.map +1 -0
- package/dist/commands/index.d.cts +592 -0
- package/dist/commands/index.d.ts +592 -0
- package/dist/commands/index.js +860 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/{controller-OUdxPY-X.d.ts → controller-pePCJLT1.d.cts} +216 -11
- package/dist/{controller-OUdxPY-X.d.cts → controller-pePCJLT1.d.ts} +216 -11
- package/dist/extensions/index.cjs +14 -4
- package/dist/extensions/index.cjs.map +1 -1
- package/dist/extensions/index.d.cts +3 -3
- package/dist/extensions/index.d.ts +3 -3
- package/dist/extensions/index.js +13 -3
- package/dist/history/index.cjs +12 -2
- package/dist/history/index.cjs.map +1 -1
- package/dist/history/index.d.cts +211 -7
- package/dist/history/index.d.ts +211 -7
- package/dist/history/index.js +13 -3
- package/dist/image-editor/index.cjs +418 -13
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +154 -3
- package/dist/image-editor/index.d.ts +154 -3
- package/dist/image-editor/index.js +417 -12
- package/dist/image-editor/index.js.map +1 -1
- package/dist/{index-k3mFbPx_.d.cts → index-CCr_z9kF.d.cts} +3 -3
- package/dist/{index-Ng1pG7JE.d.ts → index-Ck6ajwXh.d.ts} +3 -3
- package/dist/index.cjs +275 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +296 -47
- package/dist/index.d.ts +296 -47
- package/dist/index.js +266 -74
- package/dist/index.js.map +1 -1
- package/dist/registry-D5-R90p0.d.cts +209 -0
- package/dist/registry-D5-R90p0.d.ts +209 -0
- package/dist/{registry-iAHbqkYt.d.cts → registry-GJI4gToU.d.cts} +15 -4
- package/dist/{registry-iAHbqkYt.d.ts → registry-GJI4gToU.d.ts} +15 -4
- package/dist/serializers/index.cjs +3 -3
- package/dist/serializers/index.d.cts +1 -1
- package/dist/serializers/index.d.ts +1 -1
- package/dist/serializers/index.js +2 -2
- package/dist/spreadsheet/index.cjs +23 -3
- package/dist/spreadsheet/index.cjs.map +1 -1
- package/dist/spreadsheet/index.d.cts +97 -10
- package/dist/spreadsheet/index.d.ts +97 -10
- package/dist/spreadsheet/index.js +22 -2
- package/dist/{track-changes-G8JcWB8b.d.cts → track-changes-BSF58RK0.d.cts} +92 -9
- package/dist/{track-changes-G8JcWB8b.d.ts → track-changes-BSF58RK0.d.ts} +92 -9
- package/dist/{types-DMe0vFB1.d.cts → types-DX4Mh4SL.d.cts} +1 -1
- package/dist/{types-DMe0vFB1.d.ts → types-DX4Mh4SL.d.ts} +1 -1
- package/dist/types-GT5a5YAX.d.cts +86 -0
- package/dist/types-GT5a5YAX.d.ts +86 -0
- package/package.json +8 -2
- package/dist/chunk-2TWGLC5K.cjs +0 -262
- package/dist/chunk-2TWGLC5K.cjs.map +0 -1
- package/dist/chunk-3TYMNULT.js.map +0 -1
- package/dist/chunk-4QPLEUL2.cjs.map +0 -1
- package/dist/chunk-A7DKIA72.js.map +0 -1
- package/dist/chunk-CYFJCKC4.js.map +0 -1
- package/dist/chunk-GVW4P7BG.js.map +0 -1
- package/dist/chunk-JYRIOFEN.cjs.map +0 -1
- package/dist/chunk-KAADNAPF.js +0 -262
- package/dist/chunk-KAADNAPF.js.map +0 -1
- package/dist/chunk-TVRC4KVT.cjs.map +0 -1
- package/dist/chunk-U6NDQFOK.cjs.map +0 -1
- package/dist/types-BZgcDsC5.d.cts +0 -42
- package/dist/types-BZgcDsC5.d.ts +0 -42
- /package/dist/{chunk-KYRZDWM4.js.map → chunk-JJDLPEWL.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/commands/registry.ts","../../src/commands/palette.ts","../../src/commands/paletteController.ts","../../src/commands/agentTools.ts","../../src/commands/builtins.ts"],"sourcesContent":["// Portions ported from filmcraft-main/crates/engine/src/commands.rs and crates/engine/src/lib.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport { validateJsonSchema, type JsonSchema, type SchemaValidationError } from '../agent/schema.js';\nimport type { KeyboardEventLike, Platform } from './chords.js';\nimport {\n\tShortcutMap,\n\ttoShortcutBindings,\n\ttype ShortcutInput,\n\ttype ShortcutMapOptions,\n\ttype ShortcutResolveOptions\n} from './shortcuts.js';\n\n/** Object JSON Schema describing a command's parameters. */\nexport type CommandParamsSchema = JsonSchema & { type: 'object' };\n\n/**\n * Metadata and implementation of one command. Menus, shortcuts, the palette and agent\n * tools all run commands by id, so every entry point shares enablement and validation.\n */\nexport interface CommandSpec<TContext = any, TParams = any, TResult = unknown> {\n\t/** Unique id, e.g. `history.undo` or `canvas.alignLeft`. */\n\tid: string;\n\tlabel: string;\n\t/** Group / menu name shown next to the label, e.g. `Edit` or `Arrange`. */\n\tgroup?: string;\n\t/** Extra search terms for the palette. */\n\tkeywords?: readonly string[];\n\tdescription?: string;\n\t/** Object JSON Schema for `params`. Unknown keys are rejected unless `additionalProperties` allows them. */\n\tparams?: CommandParamsSchema;\n\t/** Default shortcut(s): platform-neutral chord text such as `Mod+Shift+Z`. */\n\tshortcut?: ShortcutInput;\n\t/** Scope the command (and its shortcuts) belong to, e.g. `canvas`. Omit for global commands. */\n\tscope?: string;\n\t/**\n\t * Whether the command can run: `true` (or `undefined`), `false`, or a reason string\n\t * (\"Nothing to undo\"). Receives the params a caller named, so a command acting on the\n\t * selection can still run on targets passed explicitly (`params` is `undefined` for menus).\n\t */\n\tenabled?: (context: TContext, params: TParams | undefined) => boolean | string | undefined;\n\trun: (context: TContext, params: TParams) => TResult;\n\t/**\n\t * Runs inside the registry's `history.batch(label, …)`, so all history entries the\n\t * command records become one undo step and a throw rolls back its partial changes.\n\t */\n\tundoable?: boolean;\n\t/** The command only reads state (agent tools mark it read-only). */\n\treadOnly?: boolean;\n\t/** Hide from the palette and `list()` unless `includeHidden` (still runnable by id). */\n\thidden?: boolean;\n}\n\nexport type CommandErrorCode = 'unknown_command' | 'disabled' | 'invalid_params' | 'failed';\n\nexport type CommandResult<T = unknown> =\n\t| { ok: true; id: string; result: T }\n\t| { ok: false; id: string; code: CommandErrorCode; message: string; details?: SchemaValidationError[] };\n\n/** A command as listed for menus, palettes and agents. */\nexport interface CommandEntry {\n\tid: string;\n\tlabel: string;\n\tgroup?: string;\n\tkeywords?: readonly string[];\n\tdescription?: string;\n\tparams?: CommandParamsSchema;\n\tscope?: string;\n\t/** Canonical chord text bound on the registry's platform (first = primary). */\n\tshortcuts: string[];\n\tenabled: boolean;\n\t/** Why the command is disabled (only when `enabled` is false). */\n\tdisabledReason?: string;\n\tundoable: boolean;\n\treadOnly: boolean;\n}\n\nexport interface CommandListOptions<TContext = any> {\n\t/** Only global commands plus commands of these scopes. */\n\tscope?: string | readonly string[];\n\tenabledOnly?: boolean;\n\tincludeHidden?: boolean;\n\t/** Context for the enablement check (default: the registry's context). */\n\tcontext?: TContext;\n}\n\n/** Minimal history surface (`HistoryManager` satisfies it). */\nexport interface CommandHistoryTarget {\n\tbatch(name: string, fn: () => void): void;\n}\n\nexport interface CommandRegistryOptions<TContext = any> {\n\t/** Default context passed to `enabled` / `run` (a value or a getter). */\n\tcontext?: TContext | (() => TContext);\n\t/** Wraps `undoable` commands in one history step (see `CommandSpec.undoable`). */\n\thistory?: CommandHistoryTarget;\n\t/** Options for the registry's `ShortcutMap`. */\n\tshortcuts?: ShortcutMapOptions;\n}\n\nexport class CommandRegistryError extends Error {\n\treadonly code: 'duplicate_command' | 'invalid_command';\n\n\tconstructor(code: CommandRegistryError['code'], message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'CommandRegistryError';\n\t\tthis.code = code;\n\t}\n}\n\nconst COMMAND_ID_REGEX = /^[A-Za-z0-9_.:-]{1,128}$/;\n\ninterface Registered {\n\tspec: CommandSpec;\n\tunbind: () => void;\n}\n\nfunction enablement(result: boolean | string | undefined): { enabled: boolean; reason?: string } {\n\tif (result === undefined || result === true) return { enabled: true };\n\tif (result === false) return { enabled: false, reason: 'This command is not available right now.' };\n\treturn { enabled: false, reason: String(result) };\n}\n\n/** Errors for params the command does not accept, naming the accepted keys. */\nfunction unknownParams(spec: CommandSpec, params: Record<string, unknown>): string | null {\n\tconst keys = Object.keys(params).filter((k) => params[k] !== undefined);\n\tif (keys.length === 0) return null;\n\tconst schema = spec.params;\n\tif (schema && schema.additionalProperties !== undefined && schema.additionalProperties !== false) return null;\n\tconst accepted = Object.keys(schema?.properties ?? {});\n\tconst bad = keys.find((k) => !accepted.includes(k));\n\tif (!bad) return null;\n\treturn `Unknown parameter \"${bad}\" for command \"${spec.id}\"; expected ${\n\t\taccepted.length ? accepted.map((k) => `\"${k}\"`).join(', ') : 'no parameters'\n\t}.`;\n}\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> =>\n\t!!value && (typeof value === 'object' || typeof value === 'function') && typeof (value as any).then === 'function';\n\n/**\n * Registry of commands: one id per action, shared by shortcuts (`shortcuts`), the\n * command palette (`list` + `rankCommands`) and agent tools (`createCommandToolProvider`).\n */\nexport class CommandRegistry<TContext = any> {\n\t/** Shortcut bindings of the registered commands (plus any user overrides). */\n\treadonly shortcuts: ShortcutMap;\n\n\tprivate readonly commands = new Map<string, Registered>();\n\tprivate readonly listeners = new Set<() => void>();\n\tprivate readonly options: CommandRegistryOptions<TContext>;\n\tprivate version = 0;\n\t// Set while register/unregister change the shortcut map, so they notify once.\n\tprivate muted = false;\n\n\tconstructor(options: CommandRegistryOptions<TContext> = {}) {\n\t\tthis.options = options;\n\t\tthis.shortcuts = new ShortcutMap([], options.shortcuts);\n\t\tthis.shortcuts.subscribe(() => {\n\t\t\tif (!this.muted) this.notify();\n\t\t});\n\t}\n\n\t/** Monotonic counter bumped on every change (useful as a snapshot key). */\n\tgetVersion(): number {\n\t\treturn this.version;\n\t}\n\n\t/** The default context. */\n\tget context(): TContext {\n\t\tconst ctx = this.options.context;\n\t\treturn (typeof ctx === 'function' ? (ctx as () => TContext)() : ctx) as TContext;\n\t}\n\n\t/**\n\t * Registers a command (or several) and returns a function that unregisters it.\n\t * Throws a `CommandRegistryError` for a duplicate or invalid id, or invalid chord text.\n\t */\n\tregister(spec: CommandSpec<TContext> | readonly CommandSpec<TContext>[]): () => void {\n\t\tconst specs = (Array.isArray(spec) ? spec : [spec]) as CommandSpec<TContext>[];\n\t\tconst seen = new Set<string>();\n\t\tfor (const s of specs) {\n\t\t\tif (!s || typeof s.id !== 'string' || !COMMAND_ID_REGEX.test(s.id)) {\n\t\t\t\tthrow new CommandRegistryError('invalid_command', `Invalid command id \"${s?.id}\".`);\n\t\t\t}\n\t\t\tif (typeof s.run !== 'function') {\n\t\t\t\tthrow new CommandRegistryError('invalid_command', `Command \"${s.id}\" has no run function.`);\n\t\t\t}\n\t\t\tif (this.commands.has(s.id) || seen.has(s.id)) {\n\t\t\t\tthrow new CommandRegistryError('duplicate_command', `Command \"${s.id}\" is already registered.`);\n\t\t\t}\n\t\t\tseen.add(s.id);\n\t\t}\n\t\t// Parse every chord before registering anything, so a bad shortcut registers nothing.\n\t\tconst bindings = specs.map((s) => toShortcutBindings(s.id, s.shortcut, s.scope));\n\t\tconst unbinds: Array<() => void> = [];\n\t\tthis.muted = true;\n\t\ttry {\n\t\t\tfor (const b of bindings) unbinds.push(this.shortcuts.bind(b));\n\t\t} catch (error) {\n\t\t\tunbinds.forEach((u) => u());\n\t\t\tthrow new CommandRegistryError('invalid_command', error instanceof Error ? error.message : String(error));\n\t\t} finally {\n\t\t\tthis.muted = false;\n\t\t}\n\t\tspecs.forEach((s, i) => this.commands.set(s.id, { spec: s, unbind: unbinds[i] }));\n\t\tthis.notify();\n\t\tlet registered = true;\n\t\treturn () => {\n\t\t\tif (!registered) return;\n\t\t\tregistered = false;\n\t\t\tlet changed = false;\n\t\t\tfor (const s of specs) {\n\t\t\t\tconst entry = this.commands.get(s.id);\n\t\t\t\tif (entry && entry.spec === s) {\n\t\t\t\t\tthis.commands.delete(s.id);\n\t\t\t\t\tthis.unbindQuietly(entry);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (changed) this.notify();\n\t\t};\n\t}\n\n\t/** Removes a command by id. Returns whether it was registered. */\n\tunregister(id: string): boolean {\n\t\tconst entry = this.commands.get(id);\n\t\tif (!entry) return false;\n\t\tthis.commands.delete(id);\n\t\tthis.unbindQuietly(entry);\n\t\tthis.notify();\n\t\treturn true;\n\t}\n\n\tprivate unbindQuietly(entry: Registered) {\n\t\tthis.muted = true;\n\t\ttry {\n\t\t\tentry.unbind();\n\t\t} finally {\n\t\t\tthis.muted = false;\n\t\t}\n\t}\n\n\thas(id: string): boolean {\n\t\treturn this.commands.has(id);\n\t}\n\n\tget(id: string): CommandSpec<TContext> | undefined {\n\t\treturn this.commands.get(id)?.spec;\n\t}\n\n\t/** Registered ids in registration order. */\n\tids(): string[] {\n\t\treturn [...this.commands.keys()];\n\t}\n\n\t/** Whether `id` can run now (`{ enabled, reason }`); `params` are the targets a caller named. */\n\tisEnabled(id: string, params?: unknown, context: TContext = this.context): { enabled: boolean; reason?: string } {\n\t\tconst spec = this.get(id);\n\t\tif (!spec) return { enabled: false, reason: `Unknown command \"${id}\".` };\n\t\tif (!spec.enabled) return { enabled: true };\n\t\ttry {\n\t\t\treturn enablement(spec.enabled(context, params as any));\n\t\t} catch (error) {\n\t\t\treturn { enabled: false, reason: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t}\n\n\t/** Commands for menus, palettes and agents, with their current enablement. */\n\tlist(options: CommandListOptions<TContext> = {}): CommandEntry[] {\n\t\tconst scopes = options.scope === undefined ? null : typeof options.scope === 'string' ? [options.scope] : options.scope;\n\t\tconst context = 'context' in options ? (options.context as TContext) : this.context;\n\t\tconst platform = this.shortcuts.platform;\n\t\tconst out: CommandEntry[] = [];\n\t\tfor (const { spec } of this.commands.values()) {\n\t\t\tif (spec.hidden && !options.includeHidden) continue;\n\t\t\tif (scopes && spec.scope !== undefined && !scopes.includes(spec.scope)) continue;\n\t\t\tconst { enabled, reason } = this.isEnabled(spec.id, undefined, context);\n\t\t\tif (options.enabledOnly && !enabled) continue;\n\t\t\tout.push({\n\t\t\t\tid: spec.id,\n\t\t\t\tlabel: spec.label,\n\t\t\t\t...(spec.group !== undefined ? { group: spec.group } : {}),\n\t\t\t\t...(spec.keywords ? { keywords: spec.keywords } : {}),\n\t\t\t\t...(spec.description !== undefined ? { description: spec.description } : {}),\n\t\t\t\t...(spec.params ? { params: spec.params } : {}),\n\t\t\t\t...(spec.scope !== undefined ? { scope: spec.scope } : {}),\n\t\t\t\tshortcuts: this.shortcuts.forCommand(spec.id, platform),\n\t\t\t\tenabled,\n\t\t\t\t...(enabled ? {} : { disabledReason: reason }),\n\t\t\t\tundoable: !!spec.undoable,\n\t\t\t\treadOnly: !!spec.readOnly\n\t\t\t});\n\t\t}\n\t\treturn out;\n\t}\n\n\tprivate check(id: string, params: unknown, context: TContext): CommandResult<never> | { spec: CommandSpec<TContext>; params: any } {\n\t\tconst spec = this.get(id);\n\t\tif (!spec) return { ok: false, id, code: 'unknown_command', message: `Unknown command \"${id}\".` };\n\t\tconst input = params ?? {};\n\t\tif (typeof input !== 'object' || Array.isArray(input)) {\n\t\t\treturn { ok: false, id, code: 'invalid_params', message: `Parameters for command \"${id}\" must be an object.` };\n\t\t}\n\t\tconst unknown = unknownParams(spec, input as Record<string, unknown>);\n\t\tif (unknown) return { ok: false, id, code: 'invalid_params', message: unknown };\n\t\tif (spec.params) {\n\t\t\tconst details = validateJsonSchema(input, spec.params);\n\t\t\tif (details.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\tid,\n\t\t\t\t\tcode: 'invalid_params',\n\t\t\t\t\tmessage: `Invalid parameters for command \"${id}\": ${details.map((d) => `${d.path} ${d.message}`).join('; ')}`,\n\t\t\t\t\tdetails\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tconst { enabled, reason } = this.isEnabled(id, params === undefined ? undefined : input, context);\n\t\tif (!enabled) return { ok: false, id, code: 'disabled', message: reason ?? 'Disabled.' };\n\t\treturn { spec, params: input };\n\t}\n\n\tprivate invoke(spec: CommandSpec<TContext>, params: any, context: TContext): unknown {\n\t\tconst history = this.options.history;\n\t\tif (!spec.undoable || !history) return spec.run(context, params);\n\t\tlet value: unknown;\n\t\t// `batch` rolls back already-recorded steps and rethrows when `run` throws.\n\t\thistory.batch(spec.label, () => {\n\t\t\tvalue = spec.run(context, params);\n\t\t});\n\t\treturn value;\n\t}\n\n\t/**\n\t * Runs a command synchronously and returns a structured result; never throws.\n\t * A command whose `run` returns a promise yields `{ ok: true, result: promise }`\n\t * (use `executeAsync` to await it and catch its rejection).\n\t */\n\texecute<T = unknown>(id: string, params?: unknown, context: TContext = this.context): CommandResult<T> {\n\t\tconst checked = this.check(id, params, context);\n\t\tif ('ok' in checked) return checked;\n\t\ttry {\n\t\t\tconst result = this.invoke(checked.spec, checked.params, context);\n\t\t\tthis.notify();\n\t\t\treturn { ok: true, id, result: result as T };\n\t\t} catch (error) {\n\t\t\tthis.notify();\n\t\t\treturn { ok: false, id, code: 'failed', message: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t}\n\n\t/** Like `execute`, but awaits async commands (rejections become `failed` results). */\n\tasync executeAsync<T = unknown>(id: string, params?: unknown, context: TContext = this.context): Promise<CommandResult<T>> {\n\t\tconst outcome = this.execute<T>(id, params, context);\n\t\tif (!outcome.ok || !isThenable(outcome.result)) return outcome;\n\t\ttry {\n\t\t\tconst result = await outcome.result;\n\t\t\tthis.notify();\n\t\t\treturn { ok: true, id, result: result as T };\n\t\t} catch (error) {\n\t\t\tthis.notify();\n\t\t\treturn { ok: false, id, code: 'failed', message: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t}\n\n\t/**\n\t * Resolves a keydown event to a command (see `ShortcutMap.resolve`) and runs it when\n\t * enabled, calling `preventDefault()`. Disabled commands leave the event alone, so the\n\t * browser or a focused editor can still handle it. Returns the result, or `null`.\n\t */\n\thandleKeyDown(\n\t\tevent: KeyboardEventLike,\n\t\toptions: ShortcutResolveOptions & { context?: TContext } = {}\n\t): CommandResult | null {\n\t\tif (event.defaultPrevented) return null;\n\t\tconst match = this.shortcuts.resolve(event, options);\n\t\tif (!match) return null;\n\t\tconst context = 'context' in options ? (options.context as TContext) : this.context;\n\t\tif (!this.isEnabled(match.command, undefined, context).enabled) return null;\n\t\tevent.preventDefault?.();\n\t\treturn this.execute(match.command, undefined, context);\n\t}\n\n\t/** Display-ready primary shortcut of a command (`⇧⌘Z` / `Ctrl+Shift+Z`), or `undefined`. */\n\tshortcutFor(id: string, platform: Platform = this.shortcuts.platform): string | undefined {\n\t\treturn this.shortcuts.forCommand(id, platform)[0];\n\t}\n\n\t/**\n\t * Subscribes to changes: commands registered or removed, shortcut overrides, executed\n\t * commands and `invalidate()` calls (e.g. when enablement inputs change).\n\t */\n\tsubscribe(listener: () => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\t/** Tells subscribers that enablement may have changed (e.g. the selection changed). */\n\tinvalidate(): void {\n\t\tthis.notify();\n\t}\n\n\tprivate notify(): void {\n\t\tthis.version++;\n\t\tfor (const listener of Array.from(this.listeners)) {\n\t\t\ttry {\n\t\t\t\tlistener();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[CommandRegistry] Error in listener:', error);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function createCommandRegistry<TContext = any>(options?: CommandRegistryOptions<TContext>): CommandRegistry<TContext> {\n\treturn new CommandRegistry<TContext>(options);\n}\n\n/** Identity helper that types a command spec. */\nexport function defineCommand<TContext = any, TParams = any, TResult = unknown>(\n\tspec: CommandSpec<TContext, TParams, TResult>\n): CommandSpec<TContext, TParams, TResult> {\n\treturn spec;\n}\n","// Portions ported from photocraft-main/crates/ui-egui/src/palette.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/** The fields `rankCommands` searches (a `CommandEntry` satisfies it). */\nexport interface RankableCommand {\n\tid: string;\n\tlabel: string;\n\tgroup?: string;\n\tkeywords?: readonly string[];\n\tenabled?: boolean;\n}\n\nexport interface FuzzyMatch {\n\tscore: number;\n\t/** Indices of the matched characters in the text (for highlighting). */\n\tindices: number[];\n}\n\nconst WORD_SEPARATORS = new Set([' ', '-', '_', '.', '/', ':', '›', '(']);\n\n/**\n * Subsequence fuzzy match: every query character must appear in order. Consecutive\n * matches score 8, others 1; a match at a word start adds 5; longer texts lose\n * `length / 8`. Case-insensitive. Returns `null` when the query does not match.\n */\nexport function fuzzyMatch(query: string, text: string): FuzzyMatch | null {\n\tconst q = query.trim().toLowerCase();\n\tif (!q) return { score: 0, indices: [] };\n\tconst t = text.toLowerCase();\n\tlet score = 0;\n\tlet ti = 0;\n\tlet last = -2;\n\tconst indices: number[] = [];\n\tfor (const qc of q) {\n\t\tif (qc === ' ') continue;\n\t\tlet found = false;\n\t\twhile (ti < t.length) {\n\t\t\tif (t[ti] === qc) {\n\t\t\t\tscore += last === ti - 1 ? 8 : 1;\n\t\t\t\tif (ti === 0 || WORD_SEPARATORS.has(t[ti - 1])) score += 5;\n\t\t\t\tlast = ti;\n\t\t\t\tindices.push(ti);\n\t\t\t\tti++;\n\t\t\t\tfound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tti++;\n\t\t}\n\t\tif (!found) return null;\n\t}\n\treturn { score: score - Math.floor(t.length / 8), indices };\n}\n\n/** `fuzzyMatch(query, text)?.score ?? null`. */\nexport function fuzzyScore(query: string, text: string): number | null {\n\treturn fuzzyMatch(query, text)?.score ?? null;\n}\n\n/**\n * Bonus that puts a command whose name is exactly the query ahead of every fuzzy match\n * (\"undo\" finds Undo before \"Undo Selection Change\"). Trailing ellipses are ignored.\n */\nexport function exactBonus(query: string, names: readonly string[]): number {\n\tconst q = query.trim().toLowerCase();\n\tif (!q) return 0;\n\treturn names.some((n) => n.replace(/(…|\\.\\.\\.)$/, '').trim().toLowerCase() === q) ? 1000 : 0;\n}\n\n/** Default number of recently run commands a palette remembers. */\nexport const DEFAULT_RECENT_LIMIT = 8;\n\n/** Moves `id` to the front of `list` (deduplicated, newest first, at most `cap`). Returns a new array. */\nexport function pushRecent(list: readonly string[], id: string, cap: number = DEFAULT_RECENT_LIMIT): string[] {\n\treturn [id, ...list.filter((x) => x !== id)].slice(0, Math.max(0, cap));\n}\n\nexport interface RankedCommand<T extends RankableCommand = RankableCommand> {\n\tentry: T;\n\tscore: number;\n\t/** Matched character indices in `entry.label` (empty when another field matched). */\n\tlabelIndices: number[];\n\t/** The entry was shown because it was run recently (empty query). */\n\trecent: boolean;\n}\n\nexport interface RankCommandsOptions {\n\t/** Recently run ids, newest first. Shown first for an empty query and boosted slightly otherwise. */\n\trecents?: readonly string[];\n\t/** Maximum number of recents shown for an empty query (default 8). */\n\trecentLimit?: number;\n\t/** Maximum number of results. */\n\tlimit?: number;\n\t/** Sort disabled commands after enabled ones (default `true`). */\n\tdisabledLast?: boolean;\n\t/** With an empty query: `all` (default) lists recents then every other command; `recents` lists only recents. */\n\temptyQuery?: 'all' | 'recents';\n}\n\n/**\n * Ranks commands for a palette query. Searches the label, `group label`, keywords and id;\n * an exact label or keyword match always wins. An empty query lists recent commands\n * first (deduplicated and capped), then the rest in their original order.\n */\nexport function rankCommands<T extends RankableCommand>(\n\tquery: string,\n\tentries: readonly T[],\n\toptions: RankCommandsOptions = {}\n): RankedCommand<T>[] {\n\tconst recents = options.recents ?? [];\n\tconst disabledLast = options.disabledLast ?? true;\n\tconst q = query.trim();\n\tlet ranked: Array<RankedCommand<T> & { order: number }>;\n\n\tif (!q) {\n\t\tconst byId = new Map(entries.map((e) => [e.id, e]));\n\t\tconst recentIds = [...new Set(recents)].filter((id) => byId.has(id)).slice(0, options.recentLimit ?? DEFAULT_RECENT_LIMIT);\n\t\tconst recentSet = new Set(recentIds);\n\t\tranked = recentIds.map((id, i) => ({ entry: byId.get(id)!, score: 1000 - i, labelIndices: [], recent: true, order: i }));\n\t\tif ((options.emptyQuery ?? 'all') === 'all') {\n\t\t\tentries.forEach((entry, i) => {\n\t\t\t\tif (!recentSet.has(entry.id)) ranked.push({ entry, score: 0, labelIndices: [], recent: false, order: recentIds.length + i });\n\t\t\t});\n\t\t}\n\t} else {\n\t\tranked = [];\n\t\tentries.forEach((entry, order) => {\n\t\t\tconst label = fuzzyMatch(q, entry.label);\n\t\t\tconst candidates: number[] = [];\n\t\t\tif (label) candidates.push(label.score);\n\t\t\tif (entry.group) {\n\t\t\t\tconst grouped = fuzzyScore(q, `${entry.group} ${entry.label}`);\n\t\t\t\tif (grouped !== null) candidates.push(grouped - 1);\n\t\t\t}\n\t\t\tfor (const keyword of entry.keywords ?? []) {\n\t\t\t\tconst s = fuzzyScore(q, keyword);\n\t\t\t\tif (s !== null) candidates.push(s - 2);\n\t\t\t}\n\t\t\tconst byId = fuzzyScore(q, entry.id);\n\t\t\tif (byId !== null) candidates.push(byId - 3);\n\t\t\tif (candidates.length === 0) return;\n\t\t\tconst recentIndex = recents.indexOf(entry.id);\n\t\t\tconst score =\n\t\t\t\tMath.max(...candidates) +\n\t\t\t\texactBonus(q, [entry.label, ...(entry.keywords ?? [])]) +\n\t\t\t\t(recentIndex >= 0 ? Math.max(1, 4 - recentIndex) : 0);\n\t\t\tranked.push({ entry, score, labelIndices: label?.indices ?? [], recent: false, order });\n\t\t});\n\t\tranked.sort((a, b) => b.score - a.score || a.entry.label.length - b.entry.label.length || a.order - b.order);\n\t}\n\n\tif (disabledLast) {\n\t\t// Stable partition: enabled first, keeping the ranking within each half.\n\t\tranked = [...ranked.filter((r) => r.entry.enabled !== false), ...ranked.filter((r) => r.entry.enabled === false)];\n\t}\n\tconst out = ranked.map(({ order: _order, ...rest }) => rest);\n\treturn options.limit !== undefined ? out.slice(0, options.limit) : out;\n}\n","import { formatShortcut, type KeyboardEventLike, type Platform } from './chords.js';\nimport { DEFAULT_RECENT_LIMIT, pushRecent, rankCommands, type RankedCommand } from './palette.js';\nimport type { CommandEntry, CommandRegistry, CommandResult } from './registry.js';\nimport { ShortcutMap } from './shortcuts.js';\n\n/** One palette row. */\nexport interface CommandPaletteItem extends RankedCommand<CommandEntry> {\n\tid: string;\n\tlabel: string;\n\tgroup?: string;\n\t/** Display-ready primary shortcut (`⇧⌘Z` / `Ctrl+Shift+Z`). */\n\tshortcut?: string;\n\tenabled: boolean;\n\tdisabledReason?: string;\n}\n\nexport interface CommandPaletteState {\n\topen: boolean;\n\tquery: string;\n\tactiveIndex: number;\n\titems: CommandPaletteItem[];\n\trecents: string[];\n\t/** Result of the last command the palette ran. */\n\tlastResult: CommandResult | null;\n}\n\nexport interface CommandPaletteOptions<TContext = any> {\n\t/** Context for enablement and runs (default: the registry's). */\n\tcontext?: TContext | (() => TContext);\n\t/** Only global commands plus these scopes. */\n\tscope?: string | readonly string[] | (() => string | readonly string[] | undefined);\n\t/** Initial recently run ids (newest first), e.g. restored from storage. */\n\trecents?: readonly string[];\n\t/** Called whenever the recents change, e.g. to persist them. */\n\tonRecentsChange?: (recents: string[]) => void;\n\trecentLimit?: number;\n\t/** Maximum rows (default 50). */\n\tlimit?: number;\n\t/** Platform for shortcut display (default: detected). */\n\tplatform?: Platform;\n\t/** Called after a command ran from the palette. */\n\tonRun?: (result: CommandResult) => void;\n}\n\n/**\n * Framework-agnostic command palette state (open, query, ranked rows, active row and\n * recents) over a `CommandRegistry`. The React hook and Svelte rune wrap it.\n */\nexport function createCommandPaletteController<TContext = any>(\n\tregistry: CommandRegistry<TContext>,\n\toptions: CommandPaletteOptions<TContext> = {}\n) {\n\tconst listeners = new Set<(state: CommandPaletteState) => void>();\n\tlet open = false;\n\tlet query = '';\n\tlet activeIndex = 0;\n\tlet recents = [...(options.recents ?? [])];\n\tlet lastResult: CommandResult | null = null;\n\tlet state: CommandPaletteState;\n\n\tconst context = (): TContext => {\n\t\tconst c = options.context;\n\t\tif (c === undefined) return registry.context;\n\t\treturn (typeof c === 'function' ? (c as () => TContext)() : c) as TContext;\n\t};\n\tconst scope = () => (typeof options.scope === 'function' ? options.scope() : options.scope);\n\n\tfunction computeItems(): CommandPaletteItem[] {\n\t\tif (!open) return [];\n\t\tconst entries = registry.list({ scope: scope(), context: context() });\n\t\tconst platform = options.platform ?? registry.shortcuts.platform;\n\t\treturn rankCommands(query, entries, {\n\t\t\trecents,\n\t\t\trecentLimit: options.recentLimit,\n\t\t\tlimit: options.limit ?? 50\n\t\t}).map((ranked) => ({\n\t\t\t...ranked,\n\t\t\tid: ranked.entry.id,\n\t\t\tlabel: ranked.entry.label,\n\t\t\t...(ranked.entry.group !== undefined ? { group: ranked.entry.group } : {}),\n\t\t\t...(ranked.entry.shortcuts[0] ? { shortcut: formatShortcut(ranked.entry.shortcuts[0], platform) } : {}),\n\t\t\tenabled: ranked.entry.enabled,\n\t\t\t...(ranked.entry.disabledReason ? { disabledReason: ranked.entry.disabledReason } : {})\n\t\t}));\n\t}\n\n\tfunction update() {\n\t\tconst items = computeItems();\n\t\tactiveIndex = items.length === 0 ? 0 : Math.min(Math.max(activeIndex, 0), items.length - 1);\n\t\tstate = { open, query, activeIndex, items, recents, lastResult };\n\t\tfor (const listener of Array.from(listeners)) listener(state);\n\t}\n\n\tstate = { open, query, activeIndex, items: [], recents, lastResult };\n\t// Follow registry changes only while someone listens (safe with React StrictMode remounts).\n\tlet unsubscribeRegistry: (() => void) | null = null;\n\tconst onRegistryChange = () => {\n\t\tif (open) update();\n\t};\n\n\tconst controller = {\n\t\tgetState: () => state,\n\t\tsubscribe(listener: (state: CommandPaletteState) => void): () => void {\n\t\t\tlisteners.add(listener);\n\t\t\tunsubscribeRegistry ??= registry.subscribe(onRegistryChange);\n\t\t\tif (open) update(); // catch up with changes made while nobody listened\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener);\n\t\t\t\tif (listeners.size === 0) {\n\t\t\t\t\tunsubscribeRegistry?.();\n\t\t\t\t\tunsubscribeRegistry = null;\n\t\t\t\t}\n\t\t\t};\n\t\t},\n\t\tsetOpen(next: boolean) {\n\t\t\tif (next === open) return;\n\t\t\topen = next;\n\t\t\tquery = '';\n\t\t\tactiveIndex = 0;\n\t\t\tupdate();\n\t\t},\n\t\ttoggle() {\n\t\t\tcontroller.setOpen(!open);\n\t\t},\n\t\tsetQuery(next: string) {\n\t\t\tif (next === query) return;\n\t\t\tquery = next;\n\t\t\tactiveIndex = 0;\n\t\t\tupdate();\n\t\t},\n\t\tsetActiveIndex(index: number) {\n\t\t\tactiveIndex = index;\n\t\t\tupdate();\n\t\t},\n\t\t/** Moves the active row by `delta`, wrapping around. */\n\t\tmove(delta: number) {\n\t\t\tconst n = state.items.length;\n\t\t\tif (n === 0) return;\n\t\t\tactiveIndex = (((activeIndex + delta) % n) + n) % n;\n\t\t\tupdate();\n\t\t},\n\t\t/** Runs a command by id, closes the palette and records it as recent. Disabled commands do nothing. */\n\t\trun(id: string): CommandResult | null {\n\t\t\tif (!registry.isEnabled(id, undefined, context()).enabled) return null;\n\t\t\topen = false;\n\t\t\tquery = '';\n\t\t\tactiveIndex = 0;\n\t\t\trecents = pushRecent(recents, id, options.recentLimit ?? DEFAULT_RECENT_LIMIT);\n\t\t\toptions.onRecentsChange?.(recents);\n\t\t\tconst result = registry.execute(id, undefined, context());\n\t\t\tlastResult = result;\n\t\t\tupdate();\n\t\t\toptions.onRun?.(result);\n\t\t\treturn result;\n\t\t},\n\t\trunActive(): CommandResult | null {\n\t\t\tconst item = state.items[state.activeIndex];\n\t\t\treturn item ? controller.run(item.id) : null;\n\t\t},\n\t\t/**\n\t\t * Keyboard handling for the palette input: ArrowUp/ArrowDown (wrap), Home/End,\n\t\t * Enter (run the active row) and Escape (close). Returns whether it handled the key.\n\t\t */\n\t\thandleKeyDown(event: KeyboardEventLike): boolean {\n\t\t\tif (!open) return false;\n\t\t\tswitch (event.key) {\n\t\t\t\tcase 'ArrowDown':\n\t\t\t\t\tcontroller.move(1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'ArrowUp':\n\t\t\t\t\tcontroller.move(-1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Home':\n\t\t\t\t\tcontroller.setActiveIndex(0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'End':\n\t\t\t\t\tcontroller.setActiveIndex(state.items.length - 1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Enter':\n\t\t\t\t\tcontroller.runActive();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Escape':\n\t\t\t\t\tcontroller.setOpen(false);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tevent.preventDefault?.();\n\t\t\treturn true;\n\t\t},\n\t\t/** Re-reads commands and enablement. */\n\t\trefresh() {\n\t\t\tupdate();\n\t\t},\n\t\tdestroy() {\n\t\t\tunsubscribeRegistry?.();\n\t\t\tunsubscribeRegistry = null;\n\t\t\tlisteners.clear();\n\t\t}\n\t};\n\treturn controller;\n}\n\nexport type CommandPaletteController = ReturnType<typeof createCommandPaletteController>;\n\n/**\n * Matches a global \"open palette\" hotkey (e.g. `Mod+K`), also while typing in inputs.\n * Returns `true` when `event` is the hotkey.\n */\nexport function matchPaletteHotkey(event: KeyboardEventLike, hotkey: string, platform?: Platform): boolean {\n\tconst map = new ShortcutMap([{ command: 'palette', chord: hotkey, allowInEditable: true }], platform ? { platform } : {});\n\treturn map.resolve(event) !== null;\n}\n","// Portions ported from filmcraft-main/crates/automation/src/server.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\nimport type { AgentTool, AgentToolProvider, McpToolResult } from '../agent/registry.js';\nimport { rankCommands } from './palette.js';\nimport type { CommandRegistry, CommandResult } from './registry.js';\n\nexport interface CommandToolProviderOptions<TContext = any> {\n\t/** Provider id (default `commands`). */\n\tid?: string;\n\t/** Always prefix the tool names with `<namespace>__`. */\n\tnamespace?: string;\n\t/** Context for enablement and runs (default: the registry's). */\n\tcontext?: TContext | (() => TContext);\n\t/** Only expose global commands plus these scopes. */\n\tscope?: string | readonly string[];\n\t/** Commands agents may not see or run (e.g. ones that open dialogs). */\n\texclude?: (id: string) => boolean;\n}\n\nconst toJson = (value: unknown): unknown => {\n\tif (value === undefined) return null;\n\ttry {\n\t\treturn JSON.parse(JSON.stringify(value));\n\t} catch {\n\t\treturn String(value);\n\t}\n};\n\nfunction errorResult(result: Extract<CommandResult, { ok: false }>): McpToolResult {\n\treturn {\n\t\tisError: true,\n\t\tcontent: [{ type: 'text', text: `${result.code}: ${result.message}` }],\n\t\tstructuredContent: {\n\t\t\terror: { code: result.code, message: result.message, command: result.id, ...(result.details ? { details: result.details } : {}) }\n\t\t}\n\t};\n}\n\n/**\n * Exposes a `CommandRegistry` to agents through a `ToolRegistry`:\n *\n * - `list_commands {query?, enabledOnly?}`: ids, labels, params schemas, shortcuts and\n * enablement (with the reason a command is disabled).\n * - `run_command {id, params?}`: runs one command; disabled commands, unknown params and\n * failures come back as `isError` results with a `{code, message}` error.\n * - `run_commands {steps: [{id, params?}], stopOnError?}`: runs steps **in order**, each as\n * its own command (and undo step). It is not atomic: steps that succeeded before a failure\n * stay applied. For all-or-nothing behaviour, register a command that runs the steps\n * inside `HistoryManager.batch` (or mark it `undoable` on a registry with `history`).\n *\n * The id enum in `run_command`'s schema follows the registered commands, so the\n * `ToolRegistry` announces `listChanged` when commands are added or removed.\n */\nexport function createCommandToolProvider<TContext = any>(\n\tregistry: CommandRegistry<TContext>,\n\toptions: CommandToolProviderOptions<TContext> = {}\n): AgentToolProvider {\n\tconst context = (): TContext => {\n\t\tconst c = options.context;\n\t\tif (c === undefined) return registry.context;\n\t\treturn (typeof c === 'function' ? (c as () => TContext)() : c) as TContext;\n\t};\n\tconst visible = () =>\n\t\tregistry.list({ scope: options.scope, context: context() }).filter((e) => !options.exclude?.(e.id));\n\tconst allowed = (id: string) => registry.has(id) && !options.exclude?.(id) && visible().some((e) => e.id === id);\n\n\tasync function runOne(id: string, params: unknown): Promise<CommandResult> {\n\t\tif (!allowed(id)) return { ok: false, id, code: 'unknown_command', message: `Unknown command \"${id}\".` };\n\t\treturn registry.executeAsync(id, params ?? {}, context());\n\t}\n\n\tconst listCommands: AgentTool = {\n\t\tname: 'list_commands',\n\t\ttitle: 'List commands',\n\t\tdescription:\n\t\t\t'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).',\n\t\tinputSchema: {\n\t\t\ttype: 'object',\n\t\t\tproperties: {\n\t\t\t\tquery: { type: 'string', description: 'Fuzzy filter on label, keywords, group and id.' },\n\t\t\t\tenabledOnly: { type: 'boolean', description: 'Only commands that can run now (default false).' }\n\t\t\t},\n\t\t\tadditionalProperties: false\n\t\t},\n\t\tannotations: { title: 'List commands', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },\n\t\thandler: ({ query = '', enabledOnly = false }) => {\n\t\t\tlet entries = visible();\n\t\t\tif (enabledOnly) entries = entries.filter((e) => e.enabled);\n\t\t\tif (String(query).trim()) entries = rankCommands(String(query), entries, { disabledLast: false }).map((r) => r.entry);\n\t\t\treturn {\n\t\t\t\tcommands: entries.map((e) => ({\n\t\t\t\t\tid: e.id,\n\t\t\t\t\tlabel: e.label,\n\t\t\t\t\t...(e.group ? { group: e.group } : {}),\n\t\t\t\t\t...(e.description ? { description: e.description } : {}),\n\t\t\t\t\t...(e.params ? { params: e.params } : {}),\n\t\t\t\t\t...(e.shortcuts.length ? { shortcuts: e.shortcuts } : {}),\n\t\t\t\t\tenabled: e.enabled,\n\t\t\t\t\t...(e.disabledReason ? { disabledReason: e.disabledReason } : {}),\n\t\t\t\t\treadOnly: e.readOnly\n\t\t\t\t}))\n\t\t\t};\n\t\t}\n\t};\n\n\tconst runCommandTool = (): AgentTool => {\n\t\tconst ids = visible().map((e) => e.id);\n\t\treturn {\n\t\t\tname: 'run_command',\n\t\t\ttitle: 'Run a command',\n\t\t\tdescription:\n\t\t\t\t'Runs one command by id with optional params (see list_commands for each command\\'s params schema). Unknown params are rejected.',\n\t\t\tinputSchema: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\tid: { type: 'string', description: 'Command id from list_commands.', ...(ids.length ? { enum: ids } : {}) },\n\t\t\t\t\tparams: { type: 'object', description: 'Command parameters.' }\n\t\t\t\t},\n\t\t\t\trequired: ['id'],\n\t\t\t\tadditionalProperties: false\n\t\t\t},\n\t\t\tannotations: { title: 'Run a command', readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },\n\t\t\thandler: async ({ id, params }) => {\n\t\t\t\tconst result = await runOne(String(id), params);\n\t\t\t\treturn result.ok ? { id: result.id, ok: true, result: toJson(result.result) } : errorResult(result);\n\t\t\t}\n\t\t};\n\t};\n\n\tconst runCommands: AgentTool = {\n\t\tname: 'run_commands',\n\t\ttitle: 'Run several commands',\n\t\tdescription:\n\t\t\t'Runs several commands in order: {steps: [{id, params?}], stopOnError?: true}. Each step is its own command and undo step; the batch is NOT atomic (steps before a failure stay applied). Returns {completed, failed, results: [{id, ok, result | code, message}]}.',\n\t\tinputSchema: {\n\t\t\ttype: 'object',\n\t\t\tproperties: {\n\t\t\t\tsteps: {\n\t\t\t\t\ttype: 'array',\n\t\t\t\t\tminItems: 1,\n\t\t\t\t\titems: {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\tid: { type: 'string', description: 'Command id.' },\n\t\t\t\t\t\t\tparams: { type: 'object', description: 'Command parameters.' }\n\t\t\t\t\t\t},\n\t\t\t\t\t\trequired: ['id'],\n\t\t\t\t\t\tadditionalProperties: false\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tstopOnError: { type: 'boolean', description: 'Stop at the first failing step (default true).' }\n\t\t\t},\n\t\t\trequired: ['steps'],\n\t\t\tadditionalProperties: false\n\t\t},\n\t\tannotations: {\n\t\t\ttitle: 'Run several commands',\n\t\t\treadOnlyHint: false,\n\t\t\tdestructiveHint: true,\n\t\t\tidempotentHint: false,\n\t\t\topenWorldHint: false\n\t\t},\n\t\thandler: async ({ steps, stopOnError = true }) => {\n\t\t\tlet completed = 0;\n\t\t\tlet failed = 0;\n\t\t\tconst results: Array<Record<string, unknown>> = [];\n\t\t\tfor (const step of steps as Array<{ id: string; params?: unknown }>) {\n\t\t\t\tconst result = await runOne(step.id, step.params);\n\t\t\t\tif (result.ok) {\n\t\t\t\t\tcompleted++;\n\t\t\t\t\tresults.push({ id: result.id, ok: true, result: toJson(result.result) });\n\t\t\t\t} else {\n\t\t\t\t\tfailed++;\n\t\t\t\t\tresults.push({ id: result.id, ok: false, code: result.code, message: result.message });\n\t\t\t\t\tif (stopOnError) break;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst summary = { completed, failed, skipped: steps.length - completed - failed, results };\n\t\t\treturn failed > 0\n\t\t\t\t? { isError: true, content: [{ type: 'text', text: JSON.stringify(summary) }], structuredContent: summary }\n\t\t\t\t: summary;\n\t\t}\n\t};\n\n\treturn {\n\t\tid: options.id ?? 'commands',\n\t\tnamespace: options.namespace,\n\t\ttools: () => [listCommands, runCommandTool(), runCommands],\n\t\tsubscribe: (notify) => registry.subscribe(notify)\n\t};\n}\n","import type { HistoryState } from '../history/types.js';\nimport type { CanvasArrangeAction } from '../canvas/arrangeShortcuts.js';\nimport type { AlignEdge, DistributeAxis, DistributeMode, ZOrderOperation } from '../canvas/arrange.js';\nimport { DEFAULT_ARRANGE_SHORTCUTS } from '../canvas/arrangeShortcuts.js';\nimport type { CommandParamsSchema, CommandSpec } from './registry.js';\nimport { ShortcutMap, type ShortcutBinding } from './shortcuts.js';\nimport type { KeyboardEventLike, Platform } from './chords.js';\n\n// ---------------------------------------------------------------------------\n// History\n// ---------------------------------------------------------------------------\n\n/** Minimal history surface (`HistoryManager` satisfies it). */\nexport interface HistoryCommandTarget {\n\tundo(): boolean | void;\n\tredo(): boolean | void;\n\tgetState(): Pick<HistoryState, 'canUndo' | 'canRedo'> & Partial<Pick<HistoryState, 'undoName' | 'redoName'>>;\n}\n\n/** Default history bindings: `Mod+Z` undo; `Mod+Shift+Z` redo, plus `Mod+Y` off macOS. */\nexport const DEFAULT_HISTORY_SHORTCUTS: readonly ShortcutBinding[] = [\n\t{ command: 'undo', chord: 'Mod+Z' },\n\t{ command: 'redo', chord: 'Mod+Shift+Z' },\n\t{ command: 'redo', chord: 'Mod+Y', platforms: ['windows', 'linux'] }\n];\n\nexport interface HistoryCommandOptions {\n\t/** Id prefix (default `history.`). */\n\tprefix?: string;\n\tgroup?: string;\n\tscope?: string;\n}\n\n/** `history.undo` / `history.redo` commands for a `HistoryManager` (disabled with a reason when empty). */\nexport function createHistoryCommands(history: HistoryCommandTarget, options: HistoryCommandOptions = {}): CommandSpec[] {\n\tconst prefix = options.prefix ?? 'history.';\n\tconst group = options.group ?? 'Edit';\n\tconst shortcutsOf = (command: 'undo' | 'redo') =>\n\t\tDEFAULT_HISTORY_SHORTCUTS.filter((b) => b.command === command).map(({ command: _c, ...rest }) => rest);\n\treturn [\n\t\t{\n\t\t\tid: `${prefix}undo`,\n\t\t\tlabel: 'Undo',\n\t\t\tgroup,\n\t\t\tkeywords: ['revert', 'back'],\n\t\t\tdescription: 'Reverts the last change.',\n\t\t\tshortcut: shortcutsOf('undo'),\n\t\t\t...(options.scope ? { scope: options.scope } : {}),\n\t\t\tenabled: () => (history.getState().canUndo ? true : 'Nothing to undo.'),\n\t\t\trun: () => {\n\t\t\t\thistory.undo();\n\t\t\t\treturn { undone: true, state: history.getState() };\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\tid: `${prefix}redo`,\n\t\t\tlabel: 'Redo',\n\t\t\tgroup,\n\t\t\tkeywords: ['repeat', 'forward'],\n\t\t\tdescription: 'Re-applies the last undone change.',\n\t\t\tshortcut: shortcutsOf('redo'),\n\t\t\t...(options.scope ? { scope: options.scope } : {}),\n\t\t\tenabled: () => (history.getState().canRedo ? true : 'Nothing to redo.'),\n\t\t\trun: () => {\n\t\t\t\thistory.redo();\n\t\t\t\treturn { redone: true, state: history.getState() };\n\t\t\t}\n\t\t}\n\t];\n}\n\nlet historyShortcutMap: ShortcutMap | null = null;\n\n/**\n * Resolves a keydown event to `undo` / `redo` with the default history bindings\n * (`Mod` is ⌘ on macOS and Ctrl elsewhere). Events from text inputs and\n * contenteditable elements are ignored unless `allowInEditable`.\n */\nexport function matchHistoryShortcut(\n\tevent: KeyboardEventLike,\n\toptions: { platform?: Platform; allowInEditable?: boolean } = {}\n): 'undo' | 'redo' | null {\n\thistoryShortcutMap ??= new ShortcutMap(DEFAULT_HISTORY_SHORTCUTS);\n\treturn (historyShortcutMap.resolve(event, options)?.command as 'undo' | 'redo' | undefined) ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Canvas arrange\n// ---------------------------------------------------------------------------\n\n/** Minimal arrange controller surface (`createCanvasArrangeController` satisfies it). */\nexport interface ArrangeCommandTarget {\n\talign(edge: AlignEdge, ids?: Iterable<string>): unknown;\n\tdistribute(axis: DistributeAxis, mode?: DistributeMode, ids?: Iterable<string>): unknown;\n\treorder(operation: ZOrderOperation, ids?: Iterable<string>): unknown;\n\tlock(ids?: Iterable<string>): unknown;\n\tunlock(ids?: Iterable<string>): unknown;\n}\n\nexport interface ArrangeCommandOptions {\n\t/** Id prefix (default `canvas.`). */\n\tprefix?: string;\n\tgroup?: string;\n\t/** Scope of the commands and their shortcuts (default `canvas`). Pass `null` for global. */\n\tscope?: string | null;\n\t/** Current selection, used for enablement (\"Select at least two nodes\"). */\n\tgetSelectedIds?: () => string[];\n\t/** Scene navigation (`nextScene` / `previousScene`); those commands are only added when given. */\n\tscenes?: { next(): unknown; previous(): unknown };\n\t/** Use these bindings instead of `DEFAULT_ARRANGE_SHORTCUTS`. */\n\tbindings?: readonly { action: CanvasArrangeAction; label: string }[];\n}\n\nconst ARRANGE_LABELS: Record<CanvasArrangeAction, string> = {\n\talignLeft: 'Align Left',\n\talignCenter: 'Align Horizontal Centers',\n\talignRight: 'Align Right',\n\talignTop: 'Align Top',\n\talignMiddle: 'Align Vertical Centers',\n\talignBottom: 'Align Bottom',\n\tdistributeHorizontal: 'Distribute Horizontally',\n\tdistributeVertical: 'Distribute Vertically',\n\tlock: 'Lock',\n\tunlock: 'Unlock',\n\tbringForward: 'Bring Forward',\n\tsendBackward: 'Send Backward',\n\tbringToFront: 'Bring to Front',\n\tsendToBack: 'Send to Back',\n\tnextScene: 'Next Scene',\n\tpreviousScene: 'Previous Scene'\n};\n\nconst IDS_PARAMS: CommandParamsSchema = {\n\ttype: 'object',\n\tproperties: {\n\t\tids: {\n\t\t\ttype: 'array',\n\t\t\titems: { type: 'string' },\n\t\t\tdescription: 'Node ids to act on (default: the selection).'\n\t\t}\n\t}\n};\n\n/**\n * Commands for the canvas arrange actions (`canvas.alignLeft`, `canvas.bringToFront`, …)\n * with the default arrange shortcuts. Each accepts `{ ids? }`; enablement checks the\n * named ids, or the selection when none are named.\n */\nexport function createArrangeCommands(controller: ArrangeCommandTarget, options: ArrangeCommandOptions = {}): CommandSpec[] {\n\tconst prefix = options.prefix ?? 'canvas.';\n\tconst group = options.group ?? 'Arrange';\n\tconst scope = options.scope === null ? undefined : options.scope ?? 'canvas';\n\tconst bindings = options.bindings ?? DEFAULT_ARRANGE_SHORTCUTS;\n\tconst count = (params?: { ids?: string[] }) => params?.ids?.length ?? options.getSelectedIds?.().length;\n\tconst needs = (min: number, what: string) => (_: unknown, params?: { ids?: string[] }) => {\n\t\tconst n = count(params);\n\t\tif (n === undefined || n >= min) return true;\n\t\treturn min === 1 ? `Select a ${what} first.` : `Select at least ${min} ${what}s.`;\n\t};\n\n\tconst run: Record<CanvasArrangeAction, (ids?: string[]) => unknown> = {\n\t\talignLeft: (ids) => controller.align('left', ids),\n\t\talignCenter: (ids) => controller.align('center', ids),\n\t\talignRight: (ids) => controller.align('right', ids),\n\t\talignTop: (ids) => controller.align('top', ids),\n\t\talignMiddle: (ids) => controller.align('middle', ids),\n\t\talignBottom: (ids) => controller.align('bottom', ids),\n\t\tdistributeHorizontal: (ids) => controller.distribute('horizontal', 'gaps', ids),\n\t\tdistributeVertical: (ids) => controller.distribute('vertical', 'gaps', ids),\n\t\tlock: (ids) => controller.lock(ids),\n\t\tunlock: (ids) => controller.unlock(ids),\n\t\tbringForward: (ids) => controller.reorder('bringForward', ids),\n\t\tsendBackward: (ids) => controller.reorder('sendBackward', ids),\n\t\tbringToFront: (ids) => controller.reorder('bringToFront', ids),\n\t\tsendToBack: (ids) => controller.reorder('sendToBack', ids),\n\t\tnextScene: () => options.scenes?.next(),\n\t\tpreviousScene: () => options.scenes?.previous()\n\t};\n\n\tconst actions = Object.keys(ARRANGE_LABELS) as CanvasArrangeAction[];\n\treturn actions\n\t\t.filter((action) => options.scenes || (action !== 'nextScene' && action !== 'previousScene'))\n\t\t.map((action): CommandSpec => {\n\t\t\tconst isScene = action === 'nextScene' || action === 'previousScene';\n\t\t\tconst enabled = isScene\n\t\t\t\t? undefined\n\t\t\t\t: action.startsWith('align')\n\t\t\t\t\t? needs(2, 'node')\n\t\t\t\t\t: action.startsWith('distribute')\n\t\t\t\t\t\t? needs(3, 'node')\n\t\t\t\t\t\t: needs(1, 'node');\n\t\t\treturn {\n\t\t\t\tid: `${prefix}${action}`,\n\t\t\t\tlabel: ARRANGE_LABELS[action],\n\t\t\t\tgroup: isScene ? 'Scenes' : group,\n\t\t\t\tkeywords: isScene ? ['scene', 'slide', 'page'] : action.startsWith('align') ? ['align'] : ['arrange', 'layer', 'order'],\n\t\t\t\t...(scope ? { scope } : {}),\n\t\t\t\tshortcut: bindings.filter((b) => b.action === action).map((b) => b.label),\n\t\t\t\t...(isScene ? {} : { params: IDS_PARAMS }),\n\t\t\t\t...(enabled ? { enabled } : {}),\n\t\t\t\trun: (_ctx: unknown, params: { ids?: string[] }) => run[action](params?.ids)\n\t\t\t};\n\t\t});\n}\n\n// ---------------------------------------------------------------------------\n// Spreadsheet table actions\n// ---------------------------------------------------------------------------\n\n/** Spreadsheet controller surface used by `createSpreadsheetCommands`. */\nexport interface SpreadsheetCommandTarget {\n\tselectedRange: unknown;\n\tgetFilterState(): { enabled: boolean; rules: readonly unknown[] };\n\ttoggleFilters(): void;\n\tclearFilters(): void;\n\tunhideAll(): void;\n\tmergeCells(): boolean;\n\tunmergeCells(): boolean;\n\ttransposeRange(): boolean;\n}\n\nexport interface SpreadsheetCommandOptions {\n\t/** Id prefix (default `spreadsheet.`). */\n\tprefix?: string;\n\t/** Scope (default `spreadsheet`). Pass `null` for global. */\n\tscope?: string | null;\n}\n\n/** Palette / agent commands for common spreadsheet table actions (no default shortcuts). */\nexport function createSpreadsheetCommands(\n\tcontroller: SpreadsheetCommandTarget,\n\toptions: SpreadsheetCommandOptions = {}\n): CommandSpec[] {\n\tconst prefix = options.prefix ?? 'spreadsheet.';\n\tconst scope = options.scope === null ? undefined : options.scope ?? 'spreadsheet';\n\tconst hasRange = () => (controller.selectedRange ? true : 'Select a range first.');\n\tconst base = { group: 'Table', ...(scope ? { scope } : {}) };\n\treturn [\n\t\t{ ...base, id: `${prefix}toggleFilters`, label: 'Toggle Filters', keywords: ['filter'], run: () => controller.toggleFilters() },\n\t\t{\n\t\t\t...base,\n\t\t\tid: `${prefix}clearFilters`,\n\t\t\tlabel: 'Clear Filters',\n\t\t\tkeywords: ['filter', 'reset'],\n\t\t\tenabled: () => (controller.getFilterState().rules.length > 0 ? true : 'No filters to clear.'),\n\t\t\trun: () => controller.clearFilters()\n\t\t},\n\t\t{ ...base, id: `${prefix}unhideAll`, label: 'Unhide All Rows and Columns', keywords: ['show', 'hidden'], run: () => controller.unhideAll() },\n\t\t{ ...base, id: `${prefix}mergeCells`, label: 'Merge Cells', keywords: ['combine'], enabled: hasRange, run: () => controller.mergeCells() },\n\t\t{ ...base, id: `${prefix}unmergeCells`, label: 'Unmerge Cells', keywords: ['split'], enabled: hasRange, run: () => controller.unmergeCells() },\n\t\t{ ...base, id: `${prefix}transposeRange`, label: 'Transpose Range', keywords: ['rotate', 'swap rows columns'], enabled: hasRange, run: () => controller.transposeRange() }\n\t];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -39,12 +39,44 @@ interface CellRange {
|
|
|
39
39
|
}
|
|
40
40
|
interface CellData {
|
|
41
41
|
raw: string;
|
|
42
|
+
/**
|
|
43
|
+
* Evaluated value. Typed (non-formula) input is parsed: `"120"` → 120,
|
|
44
|
+
* `"TRUE"` → true, `"3/4/2026"` → `"2026-03-04"` (dates are ISO text),
|
|
45
|
+
* `"10:30"` → 0.4375 (a time alone is a fraction of a day); `'120` forces
|
|
46
|
+
* the text `"120"`. Formulas store their result.
|
|
47
|
+
*/
|
|
42
48
|
value: any;
|
|
43
49
|
error?: string;
|
|
44
50
|
/** Why the formula failed, e.g. `Argument 2 of SUMIF must be a range.` Set alongside `error`. */
|
|
45
51
|
errorMessage?: string;
|
|
46
52
|
format?: CellFormat;
|
|
53
|
+
/**
|
|
54
|
+
* Number format code chosen automatically for typed input, e.g.
|
|
55
|
+
* `"$"#,##0.00` for `$1,200.50`, `0%` for `10%`, `#,##0` for `1,234`,
|
|
56
|
+
* `m/d/yyyy` for `3/4/2026`, `h:mm` for `10:30`. Used by
|
|
57
|
+
* `formatCellDisplay`; absent for formulas and General numbers.
|
|
58
|
+
*/
|
|
59
|
+
numberFormat?: string;
|
|
47
60
|
readOnly?: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Set (only) on cells showing a value spilled from a dynamic array: the
|
|
63
|
+
* anchor cell holding the formula, e.g. `A1`. Spilled cells keep an empty
|
|
64
|
+
* `raw` and are never stored in the document.
|
|
65
|
+
*/
|
|
66
|
+
spillAnchor?: string;
|
|
67
|
+
}
|
|
68
|
+
/** A dynamic array spilled from its anchor cell (the cell holding the formula). */
|
|
69
|
+
interface SpreadsheetSpill {
|
|
70
|
+
/** Anchor cell key, e.g. `A1`. */
|
|
71
|
+
key: string;
|
|
72
|
+
anchor: {
|
|
73
|
+
row: number;
|
|
74
|
+
col: number;
|
|
75
|
+
};
|
|
76
|
+
/** Every cell the array covers, anchor included. */
|
|
77
|
+
range: CellRange;
|
|
78
|
+
/** The anchor's formula. */
|
|
79
|
+
formula: string;
|
|
48
80
|
}
|
|
49
81
|
interface SpreadsheetDocument {
|
|
50
82
|
id: string;
|
|
@@ -115,7 +147,7 @@ interface SpreadsheetDataSource {
|
|
|
115
147
|
updateRecord(recordId: string, field: string, value: any): Promise<void> | void;
|
|
116
148
|
}
|
|
117
149
|
|
|
118
|
-
type FormulaTokenType = 'NUMBER' | 'STRING' | 'BOOLEAN' | 'ERROR' | 'CELL_REF' | 'RANGE' | 'PROPERTY_REF' | 'IDENTIFIER' | 'OPERATOR' | 'LPAREN' | 'RPAREN' | 'COMMA' | 'EOF';
|
|
150
|
+
type FormulaTokenType = 'NUMBER' | 'STRING' | 'BOOLEAN' | 'ERROR' | 'CELL_REF' | 'RANGE' | 'SPILL_REF' | 'PROPERTY_REF' | 'IDENTIFIER' | 'OPERATOR' | 'LPAREN' | 'RPAREN' | 'COMMA' | 'EOF';
|
|
119
151
|
interface FormulaToken {
|
|
120
152
|
type: FormulaTokenType;
|
|
121
153
|
value: string;
|
|
@@ -125,7 +157,7 @@ declare function tokenizeFormula(formula: string): FormulaToken[];
|
|
|
125
157
|
|
|
126
158
|
/** Row number used for the open end of whole-column ranges such as `A:A`. */
|
|
127
159
|
declare const WHOLE_COLUMN_END_ROW = 1048576;
|
|
128
|
-
type ASTNode = LiteralNode | CellRefNode | RangeNode | PropertyRefNode | BinaryOpNode | UnaryOpNode | FunctionCallNode;
|
|
160
|
+
type ASTNode = LiteralNode | CellRefNode | RangeNode | SpillRefNode | NameNode | PropertyRefNode | BinaryOpNode | UnaryOpNode | FunctionCallNode;
|
|
129
161
|
interface LiteralNode {
|
|
130
162
|
type: 'Literal';
|
|
131
163
|
value: number | string | boolean;
|
|
@@ -144,6 +176,19 @@ interface RangeNode {
|
|
|
144
176
|
endCol: string;
|
|
145
177
|
endRow: number;
|
|
146
178
|
}
|
|
179
|
+
/** `A1#`: the whole spill range of the dynamic array anchored at A1. */
|
|
180
|
+
interface SpillRefNode {
|
|
181
|
+
type: 'SpillRef';
|
|
182
|
+
/** Anchor cell, e.g. `A1`. */
|
|
183
|
+
ref: string;
|
|
184
|
+
col: string;
|
|
185
|
+
row: number;
|
|
186
|
+
}
|
|
187
|
+
/** A bare name: a LET variable, or `#NAME?` when nothing defines it. */
|
|
188
|
+
interface NameNode {
|
|
189
|
+
type: 'Name';
|
|
190
|
+
name: string;
|
|
191
|
+
}
|
|
147
192
|
interface PropertyRefNode {
|
|
148
193
|
type: 'PropertyRef';
|
|
149
194
|
property: string;
|
|
@@ -193,14 +238,34 @@ declare class FormulaParser {
|
|
|
193
238
|
}
|
|
194
239
|
declare function parseFormula(formula: string): ASTNode;
|
|
195
240
|
|
|
196
|
-
/**
|
|
197
|
-
* Value helpers shared by the formula evaluator and the built-in functions:
|
|
198
|
-
* error values, spreadsheet coercion rules, comparisons, ranges and dates.
|
|
199
|
-
*/
|
|
200
241
|
/** Spreadsheet error values. They propagate through operators and functions. */
|
|
201
242
|
declare const FORMULA_ERRORS: Set<string>;
|
|
202
|
-
type FormulaErrorCode = '#DIV/0!' | '#VALUE!' | '#REF!' | '#NAME?' | '#N/A' | '#NUM!' | '#CYCLE!' | '#ERROR!';
|
|
243
|
+
type FormulaErrorCode = '#DIV/0!' | '#VALUE!' | '#REF!' | '#NAME?' | '#N/A' | '#NUM!' | '#CYCLE!' | '#ERROR!' | '#SPILL!' | '#CALC!';
|
|
203
244
|
declare function isFormulaError(value: unknown): value is string;
|
|
245
|
+
/**
|
|
246
|
+
* Number to text as Excel converts it in `&` and General display: up to 15
|
|
247
|
+
* significant digits, scientific for very large or very small magnitudes.
|
|
248
|
+
*/
|
|
249
|
+
declare function numberToText(n: number): string;
|
|
250
|
+
/**
|
|
251
|
+
* Compares numbers the way Excel does: both are rounded to 15 significant
|
|
252
|
+
* digits first, so binary noise such as `0.1+0.2` versus `0.3` counts as equal.
|
|
253
|
+
*/
|
|
254
|
+
declare function compareNumbers(a: number, b: number): number;
|
|
255
|
+
/**
|
|
256
|
+
* Excel's comparison for the `=`, `<>`, `<`… operators: numbers < text <
|
|
257
|
+
* booleans < errors, numbers compared at 15 significant digits, text
|
|
258
|
+
* case-insensitively. A blank acts as 0, "" or FALSE depending on the other
|
|
259
|
+
* side. Dates are ISO text: two ISO dates compare chronologically
|
|
260
|
+
* ("2026-1-5" is before "2026-01-10"), and an ISO date against a number
|
|
261
|
+
* compares as its serial number.
|
|
262
|
+
*/
|
|
263
|
+
declare function compareValues(left: unknown, right: unknown): number;
|
|
264
|
+
/**
|
|
265
|
+
* Sort order (ascending): numbers, text, booleans, errors, then blanks last.
|
|
266
|
+
* Errors are equal to each other, so sorting keeps their order.
|
|
267
|
+
*/
|
|
268
|
+
declare function sortCompareValues(left: unknown, right: unknown): number;
|
|
204
269
|
declare function colNameToIndex(col: string): number;
|
|
205
270
|
declare function indexToColName(index: number): string;
|
|
206
271
|
/**
|
|
@@ -221,6 +286,20 @@ interface EvaluationContext {
|
|
|
221
286
|
*/
|
|
222
287
|
resolveRange?: (startCol: string, startRow: number, endCol: string, endRow: number) => any[];
|
|
223
288
|
resolveProperty?: (property: string) => any;
|
|
289
|
+
/**
|
|
290
|
+
* The spilled array anchored at a cell, for `A1#` references: its shape and
|
|
291
|
+
* values (column-major, like `resolveRange`), or an error code (e.g.
|
|
292
|
+
* `#REF!` when the cell holds no array).
|
|
293
|
+
*/
|
|
294
|
+
resolveSpill?: (col: string, row: number) => FormulaRange | string;
|
|
295
|
+
/**
|
|
296
|
+
* The cell holding the formula being evaluated, used by the implicit
|
|
297
|
+
* intersection operator (`=@A:A` reads the cell in the formula's row).
|
|
298
|
+
*/
|
|
299
|
+
getFormulaCell?: () => {
|
|
300
|
+
col: string;
|
|
301
|
+
row: number;
|
|
302
|
+
} | null;
|
|
224
303
|
}
|
|
225
304
|
/** A human-readable reason for an error value. */
|
|
226
305
|
interface FormulaDiagnostic {
|
|
@@ -234,12 +313,21 @@ interface FormulaEvaluationResult {
|
|
|
234
313
|
error?: FormulaErrorCode;
|
|
235
314
|
/** Why the formula failed, e.g. `Argument 2 of SUMIF must be a range.` */
|
|
236
315
|
message?: string;
|
|
316
|
+
/**
|
|
317
|
+
* Set when the formula returned an array of more than one value (a
|
|
318
|
+
* dynamic array). `value` is then its top-left value; a spreadsheet spills
|
|
319
|
+
* the whole array into the cells below and to the right.
|
|
320
|
+
*/
|
|
321
|
+
array?: FormulaRange;
|
|
237
322
|
}
|
|
238
323
|
/** Generic explanation of an error code, used when no specific reason was recorded. */
|
|
239
324
|
declare function describeFormulaError(code: string): string;
|
|
325
|
+
/** Largest array a formula may build (SEQUENCE, RANDARRAY, broadcasting). */
|
|
326
|
+
declare const MAX_FORMULA_ARRAY_SIZE = 1000000;
|
|
240
327
|
declare class FormulaEvaluator {
|
|
241
328
|
private context;
|
|
242
329
|
private diagnostics;
|
|
330
|
+
private scopes;
|
|
243
331
|
constructor(context?: EvaluationContext);
|
|
244
332
|
/**
|
|
245
333
|
* Evaluates a formula. Errors in the formula are returned as error values
|
|
@@ -248,15 +336,42 @@ declare class FormulaEvaluator {
|
|
|
248
336
|
evaluate(astOrFormula: ASTNode | string): any;
|
|
249
337
|
/**
|
|
250
338
|
* Evaluates a formula and explains errors. Never throws: malformed formulas
|
|
251
|
-
* return `#ERROR!` with the parser's message. A result
|
|
252
|
-
* (
|
|
339
|
+
* return `#ERROR!` with the parser's message. A result with several values
|
|
340
|
+
* (a range or a dynamic array) is returned in `array`, with its top-left
|
|
341
|
+
* value as `value`; a one-value array is just that value.
|
|
253
342
|
*/
|
|
254
343
|
evaluateWithDiagnostics(astOrFormula: ASTNode | string): FormulaEvaluationResult;
|
|
255
344
|
/** Records why an error happened and returns the error code. */
|
|
256
345
|
private fail;
|
|
257
346
|
private evaluateNode;
|
|
347
|
+
private unary;
|
|
348
|
+
/** A binary operator on two single values. */
|
|
349
|
+
private binary;
|
|
350
|
+
/**
|
|
351
|
+
* Dates are ISO text: date +/- days is a date, date - date is a number of
|
|
352
|
+
* days (fractional when times are involved).
|
|
353
|
+
*/
|
|
354
|
+
private dateArithmetic;
|
|
355
|
+
/**
|
|
356
|
+
* `@` (implicit intersection): a range reference reads the cell in the
|
|
357
|
+
* formula's row (one column) or column (one row); arrays give their
|
|
358
|
+
* top-left value.
|
|
359
|
+
*/
|
|
360
|
+
private implicitIntersection;
|
|
361
|
+
private evaluateSpillRef;
|
|
258
362
|
private evaluateRange;
|
|
259
363
|
private callFunction;
|
|
364
|
+
private finishCall;
|
|
365
|
+
private lazyArguments;
|
|
366
|
+
/**
|
|
367
|
+
* Applies a scalar function element by element when it receives arrays
|
|
368
|
+
* (`=LEN(A1:A3)`, `=IF(A1:A3>1, "y", "n")`). Arguments typed `range` are
|
|
369
|
+
* passed whole. Returns undefined when no trigger argument is a
|
|
370
|
+
* multi-value array.
|
|
371
|
+
*/
|
|
372
|
+
private liftOverArrays;
|
|
373
|
+
/** LET(name1, value1, [name2, value2, ...], calculation). */
|
|
374
|
+
private evaluateLet;
|
|
260
375
|
private createContext;
|
|
261
376
|
}
|
|
262
377
|
|
|
@@ -273,10 +388,25 @@ declare function extractCellDependencies(node: ASTNode): CellDep[];
|
|
|
273
388
|
declare class DependencyGraph {
|
|
274
389
|
private dependencies;
|
|
275
390
|
private dependents;
|
|
391
|
+
private spillDependencies;
|
|
392
|
+
private spillDependents;
|
|
393
|
+
private spillEdges;
|
|
276
394
|
setCellFormula(cellKey: string, formulaStr: string | null): void;
|
|
277
395
|
/** Removes every registered formula and dependency. */
|
|
278
396
|
clear(): void;
|
|
397
|
+
/**
|
|
398
|
+
* Records the dynamic-array edges of the anchor `anchorKey`, replacing its
|
|
399
|
+
* previous ones: every key in `spilledKeys` (cells holding its spilled
|
|
400
|
+
* values) depends on the anchor, and the anchor depends on every key in
|
|
401
|
+
* `blockingKeys` (cells that stop it spilling). Pass empty lists to remove
|
|
402
|
+
* the anchor's edges.
|
|
403
|
+
*/
|
|
404
|
+
setSpillEdges(anchorKey: string, spilledKeys: Iterable<string>, blockingKeys?: Iterable<string>): void;
|
|
405
|
+
/** The spilled cells registered for `anchorKey` by `setSpillEdges`. */
|
|
406
|
+
getSpilledKeys(anchorKey: string): string[];
|
|
407
|
+
/** Formula dependencies plus dynamic-array (spill) dependencies of a cell. */
|
|
279
408
|
getDependencies(cellKey: string): string[];
|
|
409
|
+
/** Cells depending on `cellKey`, through formulas or spills. */
|
|
280
410
|
getDependents(cellKey: string): string[];
|
|
281
411
|
/**
|
|
282
412
|
* Detects if there is a cycle containing cellKey.
|
|
@@ -324,7 +454,8 @@ declare function shiftFormulaReferences(formula: string, change: StructuralChang
|
|
|
324
454
|
/**
|
|
325
455
|
* Calls `rewrite` with the source text of every cell or range reference in
|
|
326
456
|
* `formula` (e.g. `"$A1"`, `"B2:C10"`, `"A:A"`) and splices in its result.
|
|
327
|
-
*
|
|
457
|
+
* For a spill reference (`A1#`) it receives the anchor (`"A1"`) and the `#`
|
|
458
|
+
* is kept, unless the rewrite returns `#REF!`. String literals, property references and function names (e.g. `LOG10(`)
|
|
328
459
|
* are skipped. Formulas that fail to tokenize are returned unchanged.
|
|
329
460
|
*/
|
|
330
461
|
declare function mapFormulaReferences(formula: string, rewrite: (reference: string) => string): string;
|
|
@@ -385,6 +516,8 @@ declare const SPREADSHEET_CLIPBOARD_MIME = "application/x.pixerate.spreadsheet+j
|
|
|
385
516
|
interface SpreadsheetClipboardCell {
|
|
386
517
|
raw: string;
|
|
387
518
|
value: unknown;
|
|
519
|
+
/** Display text for `text/plain` and `text/html` (e.g. `10%` for 0.1); defaults to the value as text. Not stored in the JSON payload. */
|
|
520
|
+
text?: string;
|
|
388
521
|
}
|
|
389
522
|
interface SpreadsheetClipboardPayload {
|
|
390
523
|
type: 'pixerate-spreadsheet';
|
|
@@ -524,6 +657,12 @@ interface SpreadsheetControllerOptions {
|
|
|
524
657
|
onDocumentChange?: (doc: SpreadsheetDocument) => void;
|
|
525
658
|
onSelectionChange?: (activeCell: CellCoordinate | null, range: CellRange | null) => void;
|
|
526
659
|
onCellCommit?: (rowId: string, colId: string, raw: string, value: any) => void;
|
|
660
|
+
/**
|
|
661
|
+
* Approximate memory budget for undo/redo snapshots, in bytes (UTF-16 size of
|
|
662
|
+
* the serialized documents). The oldest undo steps beyond it are dropped, but
|
|
663
|
+
* the most recent one is always kept. Defaults to 64 MiB; 0 = unlimited.
|
|
664
|
+
*/
|
|
665
|
+
maxHistoryBytes?: number;
|
|
527
666
|
}
|
|
528
667
|
declare class SpreadsheetController {
|
|
529
668
|
document: SpreadsheetDocument;
|
|
@@ -541,11 +680,39 @@ declare class SpreadsheetController {
|
|
|
541
680
|
private undoStack;
|
|
542
681
|
private redoStack;
|
|
543
682
|
private isApplyingHistory;
|
|
683
|
+
private readonly maxHistoryBytes;
|
|
544
684
|
private batching;
|
|
545
685
|
private pendingCommits;
|
|
546
686
|
private evaluatingRowIndex;
|
|
687
|
+
private evaluatingCell;
|
|
688
|
+
private spills;
|
|
689
|
+
private spilledBy;
|
|
690
|
+
private spillCells;
|
|
691
|
+
private spillChanges;
|
|
547
692
|
constructor(options?: SpreadsheetControllerOptions);
|
|
548
693
|
loadDocument(document: SpreadsheetDocument): void;
|
|
694
|
+
/**
|
|
695
|
+
* Re-parses the value of every stored typed (non-formula) cell from its
|
|
696
|
+
* `raw` input, so documents saved before typed input was parsed (whose
|
|
697
|
+
* values are text such as `"120"`) compare and sort as numbers. Cells of
|
|
698
|
+
* bound columns in record rows keep their value: it belongs to the data
|
|
699
|
+
* source.
|
|
700
|
+
*/
|
|
701
|
+
private rederiveTypedValues;
|
|
702
|
+
/**
|
|
703
|
+
* Value of typed (non-formula) input: a number, boolean, ISO date, error
|
|
704
|
+
* or text (see `parseCellInput`), its automatic number format, and the
|
|
705
|
+
* `CellFormat` to use: the automatic one (currency, percentage, date,
|
|
706
|
+
* number) when `format` is unset or `text` (the default of new columns).
|
|
707
|
+
*/
|
|
708
|
+
private typedCell;
|
|
709
|
+
/**
|
|
710
|
+
* Typed input for a bound field, coerced by the field's declared type:
|
|
711
|
+
* number, boolean and date fields get a number, boolean or ISO date when
|
|
712
|
+
* the input parses as one; string and enum fields (and unknown fields)
|
|
713
|
+
* keep the text exactly as typed.
|
|
714
|
+
*/
|
|
715
|
+
private boundInputValue;
|
|
549
716
|
registerDataSource(ds: SpreadsheetDataSource): void;
|
|
550
717
|
setPrimaryDataSource(dataSourceId: string | undefined): void;
|
|
551
718
|
syncWithDataSource(): void;
|
|
@@ -562,6 +729,14 @@ declare class SpreadsheetController {
|
|
|
562
729
|
* order. Every cell in a reference cycle is marked `#CYCLE!`.
|
|
563
730
|
*/
|
|
564
731
|
recalculateCell(rowId: string, colId: string): void;
|
|
732
|
+
/**
|
|
733
|
+
* Recalculates `keys` (and, with `includeDependents`, their dependents) in
|
|
734
|
+
* dependency order. Spill ranges are only known after evaluating their
|
|
735
|
+
* anchors, so when a pass changes which cells hold spilled values (and so
|
|
736
|
+
* the dependency graph), the dependents of those cells are recalculated in
|
|
737
|
+
* another pass, until nothing changes.
|
|
738
|
+
*/
|
|
739
|
+
private recalculateKeys;
|
|
565
740
|
/**
|
|
566
741
|
* Rebuilds the dependency graph from scratch and recalculates every formula
|
|
567
742
|
* in dependency order.
|
|
@@ -571,6 +746,26 @@ declare class SpreadsheetController {
|
|
|
571
746
|
private locateCellKey;
|
|
572
747
|
private markCycle;
|
|
573
748
|
private evalSingleCellByKey;
|
|
749
|
+
/**
|
|
750
|
+
* Spills `array` from the anchor at (row, col) into the cells below and to
|
|
751
|
+
* the right. Returns why it can't (the anchor then shows `#SPILL!`), or
|
|
752
|
+
* null once placed. The grid never grows to fit an array, as in Excel.
|
|
753
|
+
*/
|
|
754
|
+
private placeSpill;
|
|
755
|
+
/** Removes the array spilled from `anchor`. With `keepEdges`, its dependency edges stay. */
|
|
756
|
+
private clearSpill;
|
|
757
|
+
private forgetSpilledCell;
|
|
758
|
+
private resolveSpillByCoord;
|
|
759
|
+
private toSpill;
|
|
760
|
+
/**
|
|
761
|
+
* The dynamic array covering (row, col), whether it is the anchor (the cell
|
|
762
|
+
* holding the formula) or a spilled cell; null when there is none.
|
|
763
|
+
*/
|
|
764
|
+
getSpillAt(row: number, col: number): SpreadsheetSpill | null;
|
|
765
|
+
/** Every dynamic array currently spilled. */
|
|
766
|
+
getSpills(): SpreadsheetSpill[];
|
|
767
|
+
/** Whether `range` overlaps a spilled array (its anchor or spilled cells). */
|
|
768
|
+
private intersectsSpill;
|
|
574
769
|
private resolveCellByCoord;
|
|
575
770
|
private resolveRangeByCoords;
|
|
576
771
|
private resolveCurrentRowProperty;
|
|
@@ -643,6 +838,7 @@ declare class SpreadsheetController {
|
|
|
643
838
|
* HTML table, then TSV. Returns false when there was nothing to paste.
|
|
644
839
|
*/
|
|
645
840
|
pasteClipboardData(source: SpreadsheetClipboardSource, target?: CellPosition): boolean;
|
|
841
|
+
private spillAnchorInRange;
|
|
646
842
|
private getSelectionTopLeft;
|
|
647
843
|
/** The table settings object, created on first use. */
|
|
648
844
|
private get table();
|
|
@@ -746,9 +942,18 @@ declare class SpreadsheetController {
|
|
|
746
942
|
*/
|
|
747
943
|
getViewModel(): SpreadsheetViewModel;
|
|
748
944
|
private recordSnapshot;
|
|
945
|
+
/** Drops the oldest snapshots beyond `maxHistoryBytes`, always keeping the newest. */
|
|
946
|
+
private trimHistory;
|
|
947
|
+
/** Approximate bytes held by the undo/redo snapshots (UTF-16 size). */
|
|
948
|
+
getHistoryByteSize(): number;
|
|
949
|
+
/** Number of undo / redo snapshots currently held. */
|
|
950
|
+
getHistoryDepth(): {
|
|
951
|
+
undo: number;
|
|
952
|
+
redo: number;
|
|
953
|
+
};
|
|
749
954
|
undo(): void;
|
|
750
955
|
redo(): void;
|
|
751
956
|
private notifyChange;
|
|
752
957
|
}
|
|
753
958
|
|
|
754
|
-
export { type
|
|
959
|
+
export { type SpreadsheetDataSource as $, type ASTNode as A, type BinaryOpNode as B, type CellCoordinate as C, DEFAULT_COLUMN_WIDTH as D, type EvaluationContext as E, FORMULA_ERRORS as F, type GroupAggregate as G, type NewFilterRule as H, type PropertyRefNode as I, type RowType as J, SPREADSHEET_CLIPBOARD_MIME as K, type LiteralNode as L, MAX_FORMULA_ARRAY_SIZE as M, type NameNode as N, type SortDirection as O, type ParsedSpreadsheetClipboard as P, type SortKey as Q, type RangeNode as R, SpreadsheetController as S, type SpillRefNode as T, type SpreadsheetCellSpan as U, type SpreadsheetClipboardCell as V, type SpreadsheetClipboardData as W, type SpreadsheetClipboardPayload as X, type SpreadsheetClipboardSource as Y, type SpreadsheetColumn as Z, type SpreadsheetControllerOptions as _, type CellData as a, type SpreadsheetDataSourceField as a0, type SpreadsheetDocument as a1, type SpreadsheetFilterState as a2, type SpreadsheetGrouping as a3, type SpreadsheetRow as a4, type SpreadsheetRowGroup as a5, type SpreadsheetRowSection as a6, type SpreadsheetSpill as a7, type SpreadsheetTableSettings as a8, type SpreadsheetViewColumn as a9, rebaseClipboardRows as aA, remapFormulaReferences as aB, rowPassesFilters as aC, serializeHtmlTable as aD, shiftFormulaReferences as aE, sortCompareValues as aF, tokenizeFormula as aG, type SpreadsheetViewModel as aa, type SpreadsheetViewRow as ab, type StructuralChange as ac, type UnaryOpNode as ad, WHOLE_COLUMN_END_ROW as ae, buildSpreadsheetView as af, colNameToIndex as ag, columnDependencyKey as ah, compareNumbers as ai, compareValues as aj, computeRowGroups as ak, createSpreadsheetClipboardData as al, describeFormulaError as am, extractCellDependencies as an, getRowSection as ao, getTableSections as ap, indexToColName as aq, isFormulaError as ar, mapFormulaReferences as as, numberToText as at, offsetFormulaReferences as au, parseCellReference as av, parseFormula as aw, parseHtmlTable as ax, parseRange as ay, readSpreadsheetClipboard as az, type CellDep as b, type CellFormat as c, type CellPosition as d, type CellRange as e, type CellRefNode as f, type CellValueReader as g, type ColumnBinding as h, type ColumnType as i, type CsvExportOptions as j, type CsvImportOptions as k, DEFAULT_ROW_HEIGHT as l, DataSourceBinder as m, DependencyGraph as n, type FilterOperator as o, type FilterRule as p, type FormulaDiagnostic as q, type FormulaErrorCode as r, type FormulaEvaluationResult as s, FormulaEvaluator as t, FormulaParser as u, type FormulaRange as v, type FormulaToken as w, type FormulaTokenType as x, type FunctionCallNode as y, type GroupSummary as z };
|