@runtypelabs/persona 4.25.0 → 4.26.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/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-Db61aI9J.d.cts → types-BwKTZhg9.d.cts} +14 -0
- package/dist/animations/{types-Db61aI9J.d.ts → types-BwKTZhg9.d.ts} +14 -0
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/animations-extra.d.cts +14 -0
- package/dist/animations-extra.d.ts +14 -0
- package/dist/approval-ui-QAKWNFNM.js +1 -0
- package/dist/approval-ui.cjs +2 -2
- package/dist/approval-ui.d.cts +186 -8
- package/dist/approval-ui.d.ts +186 -8
- package/dist/approval-ui.js +2 -2
- package/dist/{artifacts-ui-IGB5YKLO.js → artifacts-ui-NJGMM27I.js} +1 -1
- package/dist/artifacts-ui.cjs +4 -4
- package/dist/artifacts-ui.d.cts +186 -8
- package/dist/artifacts-ui.d.ts +186 -8
- package/dist/artifacts-ui.js +5 -5
- package/dist/chunk-2ANTRKTV.js +1 -0
- package/dist/chunk-4HPTPUC6.js +1 -0
- package/dist/chunk-6V3MNEKB.js +1 -0
- package/dist/chunk-GKPCIQPB.js +1 -0
- package/dist/chunk-HGUCGM3K.js +9 -0
- package/dist/chunk-IO5VVUKP.js +3 -0
- package/dist/chunk-J4J3Y2P2.js +1 -0
- package/dist/chunk-K6HKIP5K.js +1 -0
- package/dist/chunk-K7NA7G7J.js +1 -0
- package/dist/chunk-MXUTS3LB.js +1 -0
- package/dist/chunk-PDPVORUF.js +1 -0
- package/dist/chunk-QRKGQPU7.js +1 -0
- package/dist/chunk-S6PBWE75.js +1 -0
- package/dist/chunk-T7QM7YMF.js +1 -0
- package/dist/chunk-TR2H475E.js +1 -0
- package/dist/chunk-UPO4GUFC.js +1 -0
- package/dist/chunk-ZC66NAIR.js +1 -0
- package/dist/client-history-GOZWBDA5.js +1 -0
- package/dist/client-history.js +1 -0
- package/dist/client-stream-42FOI3EC.js +4 -0
- package/dist/client-stream.js +5 -0
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions-E7HJYWO6.js +161 -0
- package/dist/{context-mentions-inline-I2RDEBAK.js → context-mentions-inline-QVESLW55.js} +1 -1
- package/dist/context-mentions.cjs +7 -7
- package/dist/context-mentions.d.cts +186 -8
- package/dist/context-mentions.d.ts +186 -8
- package/dist/context-mentions.js +8 -8
- package/dist/event-stream-view-FOIJHFQO.js +1 -0
- package/dist/event-stream-view.cjs +1 -1
- package/dist/event-stream-view.d.cts +189 -31
- package/dist/event-stream-view.d.ts +189 -31
- package/dist/event-stream-view.js +1 -1
- package/dist/forms-ui.d.cts +227 -667
- package/dist/forms-ui.d.ts +227 -667
- package/dist/history-shell-QDQ44PSE.js +3 -0
- package/dist/history-shell.js +3 -0
- package/dist/{history-view-BD6OXLNA.js → history-view-NCFBI5GR.js} +2 -2
- package/dist/history-view.cjs +2 -2
- package/dist/history-view.d.cts +35 -1
- package/dist/history-view.d.ts +35 -1
- package/dist/history-view.js +2 -2
- package/dist/index.cjs +80 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +233 -738
- package/dist/index.d.ts +233 -738
- package/dist/index.global.js +3 -215
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +81 -75
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/launcher.global.js +3 -67
- package/dist/launcher.global.js.map +1 -1
- package/dist/markdown-parsers.js +22 -22
- package/dist/runtype-tts-entry-NFBVWR7N.js +1 -0
- package/dist/runtype-tts.js +1 -1
- package/dist/session-actions-ISSKSI66.js +1 -0
- package/dist/session-actions.js +1 -0
- package/dist/session-reconnect.d.cts +186 -8
- package/dist/session-reconnect.d.ts +186 -8
- package/dist/smart-dom-reader.cjs +13 -13
- package/dist/smart-dom-reader.d.cts +186 -8
- package/dist/smart-dom-reader.d.ts +186 -8
- package/dist/smart-dom-reader.js +11 -11
- package/dist/theme-editor-preview.cjs +116 -98
- package/dist/theme-editor-preview.d.cts +188 -8
- package/dist/theme-editor-preview.d.ts +188 -8
- package/dist/theme-editor-preview.js +49 -54
- package/dist/theme-editor.cjs +2 -2
- package/dist/theme-editor.d.cts +187 -23
- package/dist/theme-editor.d.ts +187 -23
- package/dist/theme-editor.js +2 -2
- package/dist/theme-reference.d.cts +14 -0
- package/dist/theme-reference.d.ts +14 -0
- package/dist/ui-extras-entry-WAYFKVNW.js +3 -0
- package/dist/ui-extras.js +72 -0
- package/dist/voice-runtime-XLU6YK2N.js +17 -0
- package/dist/voice-runtime.cjs +17 -1
- package/dist/voice-runtime.d.cts +11656 -232
- package/dist/voice-runtime.d.ts +11656 -232
- package/dist/voice-runtime.js +17 -1
- package/dist/voice-worklet-player.cjs +19 -4
- package/dist/voice-worklet-player.d.cts +9 -10
- package/dist/voice-worklet-player.d.ts +9 -10
- package/dist/voice-worklet-player.js +19 -4
- package/dist/webmcp-polyfill.js +1 -1
- package/dist/webmcp-runtime-V6ZWW3PI.js +6 -0
- package/dist/webmcp-runtime.cjs +2 -2
- package/dist/webmcp-runtime.d.cts +1 -33
- package/dist/webmcp-runtime.d.ts +1 -33
- package/dist/webmcp-runtime.js +2 -2
- package/dist/widget.css +1 -1
- package/package.json +11 -5
- package/src/approval-paused-tool-settle.test.ts +325 -0
- package/src/client-approve.test.ts +311 -0
- package/src/client-history-eager.ts +9 -0
- package/src/client-history-loader.ts +23 -0
- package/src/client-history.ts +579 -0
- package/src/client-resume.ts +177 -0
- package/src/client-stream-eager.ts +12 -0
- package/src/client-stream-loader.ts +25 -0
- package/src/client-stream.ts +1880 -0
- package/src/client.test.ts +31 -1
- package/src/client.ts +293 -2607
- package/src/components/approval-actions.test.ts +27 -0
- package/src/components/approval-actions.ts +27 -3
- package/src/components/message-bubble.test.ts +19 -0
- package/src/components/message-bubble.ts +2 -0
- package/src/components/registry.ts +6 -6
- package/src/components/tool-bubble.test.ts +9 -0
- package/src/components/tool-bubble.ts +1 -0
- package/src/history-shell-bundle.test.ts +54 -0
- package/src/history-shell-eager.ts +12 -0
- package/src/history-shell-loader.ts +27 -0
- package/src/history-shell.ts +2362 -0
- package/src/history-view-loader.ts +2 -0
- package/src/history-view.ts +3 -0
- package/src/index-core.ts +6 -0
- package/src/index-global.ts +90 -248
- package/src/index.ts +13 -0
- package/src/install.ts +6 -4
- package/src/internal/runtype-history-provider.test.ts +1 -0
- package/src/internal/runtype-history-provider.ts +28 -13
- package/src/plugins/registry.ts +8 -8
- package/src/session-actions-chunk.test.ts +55 -0
- package/src/session-actions-eager.ts +11 -0
- package/src/session-actions-loader.ts +37 -0
- package/src/session-actions.ts +909 -0
- package/src/session-history.test.ts +3 -1
- package/src/session.ts +895 -1538
- package/src/session.voice.test.ts +1171 -5
- package/src/styles/widget.css +58 -0
- package/src/theme-editor/state.ts +91 -91
- package/src/types.ts +204 -5
- package/src/ui-ask-user-sheet.ts +382 -0
- package/src/ui-extras-eager.ts +10 -0
- package/src/ui-extras-entry.ts +9 -0
- package/src/ui-extras-loader.ts +26 -0
- package/src/ui.artifact-rail-resize.test.ts +2 -1
- package/src/ui.ask-user-chunk.test.ts +93 -0
- package/src/ui.history-chunk.test.ts +2 -1
- package/src/ui.history-config-provider.test.ts +2 -1
- package/src/ui.history-confirm-fallback.test.ts +142 -0
- package/src/ui.history-controller.test.ts +2 -1
- package/src/ui.history-lifecycle.test.ts +2 -1
- package/src/ui.history-render-hooks.test.ts +2 -1
- package/src/ui.history-shell.test.ts +2 -1
- package/src/ui.rail-overlay.test.ts +2 -1
- package/src/ui.rail-resize.test.ts +2 -1
- package/src/ui.rail-trigger-pending.test.ts +2 -1
- package/src/ui.ts +340 -2770
- package/src/utils/attachment-manager.ts +67 -67
- package/src/utils/constants.ts +3 -0
- package/src/utils/context-mention-controller.ts +323 -323
- package/src/utils/context-mention-manager.ts +40 -40
- package/src/utils/context-mention-orchestrator.ts +28 -0
- package/src/utils/event-stream-buffer.ts +50 -50
- package/src/utils/event-stream-store.ts +43 -43
- package/src/utils/throughput-tracker.ts +34 -34
- package/src/utils/virtual-scroller.ts +67 -67
- package/src/utils/visitor-store.test.ts +50 -0
- package/src/utils/visitor-store.ts +23 -5
- package/src/voice/__fixtures__/voice-wire/README.md +1 -0
- package/src/voice/__fixtures__/voice-wire/client/cancel.json +3 -0
- package/src/voice/__fixtures__/voice-wire/client/context.json +4 -0
- package/src/voice/__fixtures__/voice-wire/client/delegation_result.json +6 -0
- package/src/voice/__fixtures__/voice-wire/client/delegation_update.json +6 -0
- package/src/voice/__fixtures__/voice-wire/client/ping.json +3 -0
- package/src/voice/__fixtures__/voice-wire/client/playback_progress.json +5 -0
- package/src/voice/__fixtures__/voice-wire/client/start.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/artifact.json +11 -0
- package/src/voice/__fixtures__/voice-wire/server/attached.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/audio_clear.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/audio_end.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_cancelled.json +5 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_completed.json +8 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_started.json +15 -0
- package/src/voice/__fixtures__/voice-wire/server/error.json +6 -0
- package/src/voice/__fixtures__/voice-wire/server/metrics.json +10 -0
- package/src/voice/__fixtures__/voice-wire/server/pong.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/session_config.json +16 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_final.json +7 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_interim.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_partial.json +6 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_update.json +10 -0
- package/src/voice/__fixtures__/voice-wire/server/warning.json +5 -0
- package/src/voice/audio-playback-manager.test.ts +57 -0
- package/src/voice/audio-playback-manager.ts +120 -98
- package/src/voice/browser-voice-provider.ts +37 -37
- package/src/voice/fallback-speech-engine.ts +22 -16
- package/src/voice/keyed-voice-transcript.ts +314 -0
- package/src/voice/mic-state-styles.ts +182 -0
- package/src/voice/read-aloud-controller.ts +46 -44
- package/src/voice/runtype-speech-engine.ts +35 -33
- package/src/voice/runtype-voice-provider.ts +680 -189
- package/src/voice/session-voice-wiring.ts +266 -0
- package/src/voice/voice-delegation.test.ts +71 -0
- package/src/voice/voice-delegation.ts +364 -0
- package/src/voice/voice-turn-tracker.ts +6 -6
- package/src/voice/voice.test.ts +1060 -8
- package/src/voice/worklet-playback-engine.test.ts +81 -0
- package/src/voice/worklet-playback-engine.ts +21 -3
- package/src/voice-runtime-loader.ts +4 -1
- package/src/voice-runtime.ts +7 -0
- package/src/webmcp-runtime-entry.ts +41 -39
- package/dist/approval-ui-3NMYNXBD.js +0 -1
- package/dist/chunk-5EIIHQLQ.js +0 -1
- package/dist/chunk-7CO4T5KB.js +0 -1
- package/dist/chunk-EFJBUH5F.js +0 -1
- package/dist/chunk-R2TMIMDI.js +0 -3
- package/dist/chunk-UTVLOTWB.js +0 -9
- package/dist/context-mentions-45MODWOY.js +0 -161
- package/dist/event-stream-view-GL3ADRY2.js +0 -1
- package/dist/runtype-tts-entry-UJAEF7NZ.js +0 -1
- package/dist/voice-runtime-7DA7MJH4.js +0 -1
- package/dist/webmcp-runtime-JI7T4QYF.js +0 -6
package/src/styles/widget.css
CHANGED
|
@@ -4072,6 +4072,50 @@
|
|
|
4072
4072
|
opacity: 1;
|
|
4073
4073
|
pointer-events: auto;
|
|
4074
4074
|
}
|
|
4075
|
+
|
|
4076
|
+
/* Room for the hover pill so it never covers text. Right-aligned: an inline
|
|
4077
|
+
spacer as wide as its buttons ends the last line (it wraps to a line of its
|
|
4078
|
+
own when the last line is full). Left/center, or six or more buttons: a
|
|
4079
|
+
line below the text. */
|
|
4080
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill.persona-message-actions-right)
|
|
4081
|
+
.persona-message-content
|
|
4082
|
+
> :last-child::after,
|
|
4083
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill.persona-message-actions-right)
|
|
4084
|
+
.persona-message-content:not(:has(*))::after {
|
|
4085
|
+
content: "";
|
|
4086
|
+
display: inline-block;
|
|
4087
|
+
width: calc(var(--persona-message-actions-count, 1) * 32px - 4px);
|
|
4088
|
+
}
|
|
4089
|
+
|
|
4090
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill button:nth-child(2)) {
|
|
4091
|
+
--persona-message-actions-count: 2;
|
|
4092
|
+
}
|
|
4093
|
+
|
|
4094
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill button:nth-child(3)) {
|
|
4095
|
+
--persona-message-actions-count: 3;
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill button:nth-child(4)) {
|
|
4099
|
+
--persona-message-actions-count: 4;
|
|
4100
|
+
}
|
|
4101
|
+
|
|
4102
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill button:nth-child(5)) {
|
|
4103
|
+
--persona-message-actions-count: 5;
|
|
4104
|
+
}
|
|
4105
|
+
|
|
4106
|
+
/* Six or more buttons: no inline spacer, a line below the text instead. */
|
|
4107
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill button:nth-child(6)) {
|
|
4108
|
+
--persona-message-actions-count: 0;
|
|
4109
|
+
}
|
|
4110
|
+
|
|
4111
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill:not(.persona-message-actions-right))
|
|
4112
|
+
.persona-message-content::after,
|
|
4113
|
+
.persona-message-bubble:has(> .persona-message-actions-hover.persona-message-actions-pill button:nth-child(6))
|
|
4114
|
+
.persona-message-content::after {
|
|
4115
|
+
content: "";
|
|
4116
|
+
display: block;
|
|
4117
|
+
height: 28px;
|
|
4118
|
+
}
|
|
4075
4119
|
}
|
|
4076
4120
|
|
|
4077
4121
|
/* On touch devices (no hover support), show inline and always visible */
|
|
@@ -4682,6 +4726,20 @@
|
|
|
4682
4726
|
max-height: 9rem;
|
|
4683
4727
|
}
|
|
4684
4728
|
|
|
4729
|
+
.persona-approval-call {
|
|
4730
|
+
margin: 0 0 0.6rem;
|
|
4731
|
+
}
|
|
4732
|
+
.persona-approval-tool-name {
|
|
4733
|
+
display: inline-block;
|
|
4734
|
+
max-width: 100%;
|
|
4735
|
+
overflow-wrap: anywhere;
|
|
4736
|
+
margin: 0 0 0.35rem;
|
|
4737
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
4738
|
+
font-size: 0.75rem;
|
|
4739
|
+
font-weight: 600;
|
|
4740
|
+
color: var(--persona-text, #1f2937);
|
|
4741
|
+
}
|
|
4742
|
+
|
|
4685
4743
|
.persona-approval-reason {
|
|
4686
4744
|
margin: 0 0 0.6rem;
|
|
4687
4745
|
font-size: 0.8125rem;
|
|
@@ -62,14 +62,14 @@ function unsetByPath(obj: unknown, path: string): unknown {
|
|
|
62
62
|
export class ThemeEditorState {
|
|
63
63
|
private config: AgentWidgetConfig;
|
|
64
64
|
private theme: PersonaTheme;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
#listeners: ConfigChangeListener[] = [];
|
|
66
|
+
#history: ConfiguratorSnapshot[] = [];
|
|
67
|
+
#historyIndex = -1;
|
|
68
|
+
#suppressHistory = false;
|
|
69
|
+
#authoredConfig: Partial<AgentWidgetConfig> = {};
|
|
70
|
+
#authoredTheme: DeepPartial<PersonaTheme> = {};
|
|
71
|
+
#mergeDefaults = true;
|
|
72
|
+
#snapshotIntent = new WeakMap<ConfiguratorSnapshot, { config: Partial<AgentWidgetConfig>; theme: DeepPartial<PersonaTheme> }>();
|
|
73
73
|
|
|
74
74
|
constructor(
|
|
75
75
|
initialTheme?: DeepPartial<PersonaTheme>,
|
|
@@ -77,9 +77,9 @@ export class ThemeEditorState {
|
|
|
77
77
|
options?: { mergeDefaults?: boolean }
|
|
78
78
|
) {
|
|
79
79
|
const mergeDefaults = options?.mergeDefaults ?? true;
|
|
80
|
-
this
|
|
81
|
-
this
|
|
82
|
-
this
|
|
80
|
+
this.#mergeDefaults = mergeDefaults;
|
|
81
|
+
this.#authoredConfig = { ...initialConfig };
|
|
82
|
+
this.#authoredTheme = initialTheme ?? {};
|
|
83
83
|
const defaults = resolveDefaults(initialConfig);
|
|
84
84
|
this.config = (mergeDefaults
|
|
85
85
|
? { ...defaults, ...initialConfig }
|
|
@@ -89,8 +89,8 @@ export class ThemeEditorState {
|
|
|
89
89
|
validate: false,
|
|
90
90
|
future: this.config.future,
|
|
91
91
|
});
|
|
92
|
-
this
|
|
93
|
-
this
|
|
92
|
+
this.#syncThemeIntoConfig();
|
|
93
|
+
this.#pushHistorySnapshot(this.exportSnapshot(), true);
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// ─── Read ───────────────────────────────────────────────────
|
|
@@ -129,11 +129,11 @@ export class ThemeEditorState {
|
|
|
129
129
|
*/
|
|
130
130
|
set(path: string, value: unknown): void {
|
|
131
131
|
const previousVersion = resolveDefaultsVersion(this.config);
|
|
132
|
-
this
|
|
132
|
+
this.#recordIntent(path, value);
|
|
133
133
|
if (path.startsWith('theme.')) {
|
|
134
134
|
const themePath = path.replace('theme.', '');
|
|
135
135
|
this.theme = setByPath(this.theme, themePath, value) as PersonaTheme;
|
|
136
|
-
this
|
|
136
|
+
this.#syncThemeIntoConfig();
|
|
137
137
|
} else if (path.startsWith('darkTheme.')) {
|
|
138
138
|
const themePath = path.replace('darkTheme.', '');
|
|
139
139
|
const dark = this.config.darkTheme ?? createTheme(undefined, { future: this.config.future });
|
|
@@ -145,19 +145,19 @@ export class ThemeEditorState {
|
|
|
145
145
|
this.config = setByPath(this.config, path, value) as AgentWidgetConfig;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
this
|
|
149
|
-
this
|
|
150
|
-
this
|
|
148
|
+
this.#rebaseDefaults(previousVersion);
|
|
149
|
+
this.#recordHistory();
|
|
150
|
+
this.#notifyListeners();
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/** Delete a dot-path and prune empty parents so sparse preferences inherit. */
|
|
154
154
|
unset(path: string): void {
|
|
155
155
|
const previousVersion = resolveDefaultsVersion(this.config);
|
|
156
|
-
this
|
|
156
|
+
this.#recordIntent(path, undefined, true);
|
|
157
157
|
if (path.startsWith('theme.')) {
|
|
158
158
|
const themePath = path.replace('theme.', '');
|
|
159
159
|
this.theme = unsetByPath(this.theme, themePath) as PersonaTheme;
|
|
160
|
-
this
|
|
160
|
+
this.#syncThemeIntoConfig();
|
|
161
161
|
} else if (path.startsWith('darkTheme.')) {
|
|
162
162
|
const themePath = path.replace('darkTheme.', '');
|
|
163
163
|
this.config = {
|
|
@@ -170,9 +170,9 @@ export class ThemeEditorState {
|
|
|
170
170
|
} else {
|
|
171
171
|
this.config = unsetByPath(this.config, path) as AgentWidgetConfig;
|
|
172
172
|
}
|
|
173
|
-
this
|
|
174
|
-
this
|
|
175
|
-
this
|
|
173
|
+
this.#rebaseDefaults(previousVersion);
|
|
174
|
+
this.#recordHistory();
|
|
175
|
+
this.#notifyListeners();
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/** Batch-set multiple paths at once */
|
|
@@ -183,7 +183,7 @@ export class ThemeEditorState {
|
|
|
183
183
|
let configChanged = false;
|
|
184
184
|
|
|
185
185
|
for (const [path, value] of Object.entries(updates)) {
|
|
186
|
-
this
|
|
186
|
+
this.#recordIntent(path, value);
|
|
187
187
|
if (path.startsWith('theme.')) {
|
|
188
188
|
const themePath = path.replace('theme.', '');
|
|
189
189
|
this.theme = setByPath(this.theme, themePath, value) as PersonaTheme;
|
|
@@ -203,35 +203,35 @@ export class ThemeEditorState {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
if (themeChanged) {
|
|
206
|
-
this
|
|
206
|
+
this.#syncThemeIntoConfig();
|
|
207
207
|
}
|
|
208
|
-
this
|
|
208
|
+
this.#rebaseDefaults(previousVersion);
|
|
209
209
|
if (themeChanged || darkThemeChanged || configChanged) {
|
|
210
|
-
this
|
|
211
|
-
this
|
|
210
|
+
this.#recordHistory();
|
|
211
|
+
this.#notifyListeners();
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
/** Replace the entire theme */
|
|
216
216
|
setTheme(theme: PersonaTheme): void {
|
|
217
|
-
this
|
|
217
|
+
this.#authoredTheme = theme;
|
|
218
218
|
this.theme = theme;
|
|
219
|
-
this
|
|
220
|
-
this
|
|
221
|
-
this
|
|
219
|
+
this.#syncThemeIntoConfig();
|
|
220
|
+
this.#recordHistory();
|
|
221
|
+
this.#notifyListeners();
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
/** Replace the entire config (for preset loading) */
|
|
225
225
|
setFullConfig(config: AgentWidgetConfig, theme?: PersonaTheme): void {
|
|
226
|
-
this
|
|
227
|
-
if (theme) this
|
|
226
|
+
this.#authoredConfig = { ...config };
|
|
227
|
+
if (theme) this.#authoredTheme = theme;
|
|
228
228
|
this.config = { ...config };
|
|
229
229
|
if (theme) {
|
|
230
230
|
this.theme = theme;
|
|
231
231
|
}
|
|
232
|
-
this
|
|
233
|
-
this
|
|
234
|
-
this
|
|
232
|
+
this.#syncThemeIntoConfig();
|
|
233
|
+
this.#recordHistory();
|
|
234
|
+
this.#notifyListeners();
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
/** Import a snapshot (v2 or raw theme) */
|
|
@@ -259,48 +259,48 @@ export class ThemeEditorState {
|
|
|
259
259
|
/** Reset to defaults */
|
|
260
260
|
resetToDefaults(): void {
|
|
261
261
|
const future = this.config.future;
|
|
262
|
-
this
|
|
263
|
-
this
|
|
262
|
+
this.#authoredConfig = future ? { future } : {};
|
|
263
|
+
this.#authoredTheme = {};
|
|
264
264
|
this.config = {
|
|
265
265
|
...resolveDefaults({ future }),
|
|
266
266
|
...(future ? { future } : {}),
|
|
267
267
|
} as AgentWidgetConfig;
|
|
268
268
|
this.theme = createTheme(undefined, { future: this.config.future });
|
|
269
|
-
this
|
|
270
|
-
this
|
|
271
|
-
this
|
|
272
|
-
this
|
|
273
|
-
this
|
|
269
|
+
this.#syncThemeIntoConfig();
|
|
270
|
+
this.#history = [];
|
|
271
|
+
this.#historyIndex = -1;
|
|
272
|
+
this.#pushHistorySnapshot(this.exportSnapshot());
|
|
273
|
+
this.#notifyListeners();
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
// ─── History ────────────────────────────────────────────────
|
|
277
277
|
|
|
278
278
|
canUndo(): boolean {
|
|
279
|
-
return this
|
|
279
|
+
return this.#historyIndex > 0;
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
canRedo(): boolean {
|
|
283
|
-
return this
|
|
283
|
+
return this.#historyIndex >= 0 && this.#historyIndex < this.#history.length - 1;
|
|
284
284
|
}
|
|
285
285
|
|
|
286
286
|
getHistoryLength(): number {
|
|
287
|
-
return this
|
|
287
|
+
return this.#history.length;
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
getHistoryIndex(): number {
|
|
291
|
-
return this
|
|
291
|
+
return this.#historyIndex;
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
undo(): void {
|
|
295
295
|
if (!this.canUndo()) return;
|
|
296
|
-
this
|
|
297
|
-
this
|
|
296
|
+
this.#historyIndex -= 1;
|
|
297
|
+
this.#restoreSnapshot(this.#history[this.#historyIndex]);
|
|
298
298
|
}
|
|
299
299
|
|
|
300
300
|
redo(): void {
|
|
301
301
|
if (!this.canRedo()) return;
|
|
302
|
-
this
|
|
303
|
-
this
|
|
302
|
+
this.#historyIndex += 1;
|
|
303
|
+
this.#restoreSnapshot(this.#history[this.#historyIndex]);
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
// ─── Snapshots ──────────────────────────────────────────────
|
|
@@ -316,87 +316,87 @@ export class ThemeEditorState {
|
|
|
316
316
|
// ─── Listeners ──────────────────────────────────────────────
|
|
317
317
|
|
|
318
318
|
onChange(listener: ConfigChangeListener): () => void {
|
|
319
|
-
this
|
|
319
|
+
this.#listeners.push(listener);
|
|
320
320
|
return () => {
|
|
321
|
-
const idx = this
|
|
322
|
-
if (idx >= 0) this
|
|
321
|
+
const idx = this.#listeners.indexOf(listener);
|
|
322
|
+
if (idx >= 0) this.#listeners.splice(idx, 1);
|
|
323
323
|
};
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
// ─── Private ────────────────────────────────────────────────
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
#recordIntent(path: string, value: unknown, remove = false): void {
|
|
329
329
|
const write = (target: object, key: string) => remove || value === undefined
|
|
330
330
|
? unsetByPath(target, key) : setByPath(target, key, value);
|
|
331
331
|
if (path.startsWith('theme.')) {
|
|
332
|
-
this
|
|
332
|
+
this.#authoredTheme = write(this.#authoredTheme, path.slice(6)) as DeepPartial<PersonaTheme>;
|
|
333
333
|
} else if (path === 'theme') {
|
|
334
|
-
this
|
|
334
|
+
this.#authoredTheme = (value ?? {}) as DeepPartial<PersonaTheme>;
|
|
335
335
|
} else {
|
|
336
|
-
this
|
|
336
|
+
this.#authoredConfig = write(this.#authoredConfig, path) as Partial<AgentWidgetConfig>;
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
#rebaseDefaults(previousVersion: string): void {
|
|
341
341
|
if (previousVersion === resolveDefaultsVersion(this.config)) return;
|
|
342
|
-
this.config = (this
|
|
343
|
-
? deepMerge(resolveDefaults(this
|
|
344
|
-
: { ...this
|
|
345
|
-
this.theme = createTheme(this
|
|
346
|
-
this
|
|
342
|
+
this.config = (this.#mergeDefaults
|
|
343
|
+
? deepMerge(resolveDefaults(this.#authoredConfig), this.#authoredConfig)
|
|
344
|
+
: { ...this.#authoredConfig }) as AgentWidgetConfig;
|
|
345
|
+
this.theme = createTheme(this.#authoredTheme, { validate: false, future: this.config.future });
|
|
346
|
+
this.#syncThemeIntoConfig();
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
-
|
|
349
|
+
#syncThemeIntoConfig(): void {
|
|
350
350
|
this.config = {
|
|
351
351
|
...this.config,
|
|
352
352
|
theme: this.theme,
|
|
353
353
|
};
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
-
|
|
357
|
-
for (const listener of this
|
|
356
|
+
#notifyListeners(): void {
|
|
357
|
+
for (const listener of this.#listeners) {
|
|
358
358
|
listener(this.config, this.theme);
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
|
|
363
|
-
this
|
|
362
|
+
#recordHistory(): void {
|
|
363
|
+
this.#pushHistorySnapshot(this.exportSnapshot());
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
|
|
367
|
-
if (this
|
|
368
|
-
this
|
|
366
|
+
#pushHistorySnapshot(snapshot: ConfiguratorSnapshot, replaceCurrent = false): void {
|
|
367
|
+
if (this.#suppressHistory) return;
|
|
368
|
+
this.#snapshotIntent.set(snapshot, { config: this.#authoredConfig, theme: this.#authoredTheme });
|
|
369
369
|
|
|
370
370
|
const serialized = JSON.stringify(snapshot);
|
|
371
371
|
const currentSerialized =
|
|
372
|
-
this
|
|
373
|
-
? JSON.stringify(this
|
|
372
|
+
this.#historyIndex >= 0 && this.#history[this.#historyIndex]
|
|
373
|
+
? JSON.stringify(this.#history[this.#historyIndex])
|
|
374
374
|
: null;
|
|
375
375
|
|
|
376
|
-
if (replaceCurrent && this
|
|
377
|
-
this
|
|
376
|
+
if (replaceCurrent && this.#historyIndex >= 0) {
|
|
377
|
+
this.#history[this.#historyIndex] = snapshot;
|
|
378
378
|
return;
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
-
const currentIntent = this
|
|
382
|
-
? this
|
|
381
|
+
const currentIntent = this.#historyIndex >= 0
|
|
382
|
+
? this.#snapshotIntent.get(this.#history[this.#historyIndex]) : undefined;
|
|
383
383
|
if (serialized === currentSerialized &&
|
|
384
|
-
JSON.stringify(this
|
|
384
|
+
JSON.stringify(this.#snapshotIntent.get(snapshot)) === JSON.stringify(currentIntent)) return;
|
|
385
385
|
|
|
386
|
-
this
|
|
387
|
-
this
|
|
388
|
-
this
|
|
386
|
+
this.#history = this.#history.slice(0, this.#historyIndex + 1);
|
|
387
|
+
this.#history.push(snapshot);
|
|
388
|
+
this.#historyIndex = this.#history.length - 1;
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
|
|
392
|
-
this
|
|
393
|
-
const intent = this
|
|
394
|
-
this
|
|
395
|
-
this
|
|
391
|
+
#restoreSnapshot(snapshot: ConfiguratorSnapshot): void {
|
|
392
|
+
this.#suppressHistory = true;
|
|
393
|
+
const intent = this.#snapshotIntent.get(snapshot);
|
|
394
|
+
this.#authoredConfig = intent?.config ?? snapshot.config as Partial<AgentWidgetConfig>;
|
|
395
|
+
this.#authoredTheme = intent?.theme ?? snapshot.theme;
|
|
396
396
|
this.config = snapshot.config as unknown as AgentWidgetConfig;
|
|
397
397
|
this.theme = createTheme(snapshot.theme, { validate: false, future: this.config.future });
|
|
398
|
-
this
|
|
399
|
-
this
|
|
400
|
-
this
|
|
398
|
+
this.#syncThemeIntoConfig();
|
|
399
|
+
this.#suppressHistory = false;
|
|
400
|
+
this.#notifyListeners();
|
|
401
401
|
}
|
|
402
402
|
}
|