@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.
Files changed (236) hide show
  1. package/dist/animations/glyph-cycle.d.cts +1 -1
  2. package/dist/animations/glyph-cycle.d.ts +1 -1
  3. package/dist/animations/{types-Db61aI9J.d.cts → types-BwKTZhg9.d.cts} +14 -0
  4. package/dist/animations/{types-Db61aI9J.d.ts → types-BwKTZhg9.d.ts} +14 -0
  5. package/dist/animations/wipe.d.cts +1 -1
  6. package/dist/animations/wipe.d.ts +1 -1
  7. package/dist/animations-extra.d.cts +14 -0
  8. package/dist/animations-extra.d.ts +14 -0
  9. package/dist/approval-ui-QAKWNFNM.js +1 -0
  10. package/dist/approval-ui.cjs +2 -2
  11. package/dist/approval-ui.d.cts +186 -8
  12. package/dist/approval-ui.d.ts +186 -8
  13. package/dist/approval-ui.js +2 -2
  14. package/dist/{artifacts-ui-IGB5YKLO.js → artifacts-ui-NJGMM27I.js} +1 -1
  15. package/dist/artifacts-ui.cjs +4 -4
  16. package/dist/artifacts-ui.d.cts +186 -8
  17. package/dist/artifacts-ui.d.ts +186 -8
  18. package/dist/artifacts-ui.js +5 -5
  19. package/dist/chunk-2ANTRKTV.js +1 -0
  20. package/dist/chunk-4HPTPUC6.js +1 -0
  21. package/dist/chunk-6V3MNEKB.js +1 -0
  22. package/dist/chunk-GKPCIQPB.js +1 -0
  23. package/dist/chunk-HGUCGM3K.js +9 -0
  24. package/dist/chunk-IO5VVUKP.js +3 -0
  25. package/dist/chunk-J4J3Y2P2.js +1 -0
  26. package/dist/chunk-K6HKIP5K.js +1 -0
  27. package/dist/chunk-K7NA7G7J.js +1 -0
  28. package/dist/chunk-MXUTS3LB.js +1 -0
  29. package/dist/chunk-PDPVORUF.js +1 -0
  30. package/dist/chunk-QRKGQPU7.js +1 -0
  31. package/dist/chunk-S6PBWE75.js +1 -0
  32. package/dist/chunk-T7QM7YMF.js +1 -0
  33. package/dist/chunk-TR2H475E.js +1 -0
  34. package/dist/chunk-UPO4GUFC.js +1 -0
  35. package/dist/chunk-ZC66NAIR.js +1 -0
  36. package/dist/client-history-GOZWBDA5.js +1 -0
  37. package/dist/client-history.js +1 -0
  38. package/dist/client-stream-42FOI3EC.js +4 -0
  39. package/dist/client-stream.js +5 -0
  40. package/dist/codegen.cjs +1 -1
  41. package/dist/codegen.js +1 -1
  42. package/dist/context-mentions-E7HJYWO6.js +161 -0
  43. package/dist/{context-mentions-inline-I2RDEBAK.js → context-mentions-inline-QVESLW55.js} +1 -1
  44. package/dist/context-mentions.cjs +7 -7
  45. package/dist/context-mentions.d.cts +186 -8
  46. package/dist/context-mentions.d.ts +186 -8
  47. package/dist/context-mentions.js +8 -8
  48. package/dist/event-stream-view-FOIJHFQO.js +1 -0
  49. package/dist/event-stream-view.cjs +1 -1
  50. package/dist/event-stream-view.d.cts +189 -31
  51. package/dist/event-stream-view.d.ts +189 -31
  52. package/dist/event-stream-view.js +1 -1
  53. package/dist/forms-ui.d.cts +227 -667
  54. package/dist/forms-ui.d.ts +227 -667
  55. package/dist/history-shell-QDQ44PSE.js +3 -0
  56. package/dist/history-shell.js +3 -0
  57. package/dist/{history-view-BD6OXLNA.js → history-view-NCFBI5GR.js} +2 -2
  58. package/dist/history-view.cjs +2 -2
  59. package/dist/history-view.d.cts +35 -1
  60. package/dist/history-view.d.ts +35 -1
  61. package/dist/history-view.js +2 -2
  62. package/dist/index.cjs +80 -74
  63. package/dist/index.cjs.map +1 -1
  64. package/dist/index.d.cts +233 -738
  65. package/dist/index.d.ts +233 -738
  66. package/dist/index.global.js +3 -215
  67. package/dist/index.global.js.map +1 -1
  68. package/dist/index.js +81 -75
  69. package/dist/index.js.map +1 -1
  70. package/dist/install.global.js +1 -1
  71. package/dist/install.global.js.map +1 -1
  72. package/dist/launcher.global.js +3 -67
  73. package/dist/launcher.global.js.map +1 -1
  74. package/dist/markdown-parsers.js +22 -22
  75. package/dist/runtype-tts-entry-NFBVWR7N.js +1 -0
  76. package/dist/runtype-tts.js +1 -1
  77. package/dist/session-actions-ISSKSI66.js +1 -0
  78. package/dist/session-actions.js +1 -0
  79. package/dist/session-reconnect.d.cts +186 -8
  80. package/dist/session-reconnect.d.ts +186 -8
  81. package/dist/smart-dom-reader.cjs +13 -13
  82. package/dist/smart-dom-reader.d.cts +186 -8
  83. package/dist/smart-dom-reader.d.ts +186 -8
  84. package/dist/smart-dom-reader.js +11 -11
  85. package/dist/theme-editor-preview.cjs +116 -98
  86. package/dist/theme-editor-preview.d.cts +188 -8
  87. package/dist/theme-editor-preview.d.ts +188 -8
  88. package/dist/theme-editor-preview.js +49 -54
  89. package/dist/theme-editor.cjs +2 -2
  90. package/dist/theme-editor.d.cts +187 -23
  91. package/dist/theme-editor.d.ts +187 -23
  92. package/dist/theme-editor.js +2 -2
  93. package/dist/theme-reference.d.cts +14 -0
  94. package/dist/theme-reference.d.ts +14 -0
  95. package/dist/ui-extras-entry-WAYFKVNW.js +3 -0
  96. package/dist/ui-extras.js +72 -0
  97. package/dist/voice-runtime-XLU6YK2N.js +17 -0
  98. package/dist/voice-runtime.cjs +17 -1
  99. package/dist/voice-runtime.d.cts +11656 -232
  100. package/dist/voice-runtime.d.ts +11656 -232
  101. package/dist/voice-runtime.js +17 -1
  102. package/dist/voice-worklet-player.cjs +19 -4
  103. package/dist/voice-worklet-player.d.cts +9 -10
  104. package/dist/voice-worklet-player.d.ts +9 -10
  105. package/dist/voice-worklet-player.js +19 -4
  106. package/dist/webmcp-polyfill.js +1 -1
  107. package/dist/webmcp-runtime-V6ZWW3PI.js +6 -0
  108. package/dist/webmcp-runtime.cjs +2 -2
  109. package/dist/webmcp-runtime.d.cts +1 -33
  110. package/dist/webmcp-runtime.d.ts +1 -33
  111. package/dist/webmcp-runtime.js +2 -2
  112. package/dist/widget.css +1 -1
  113. package/package.json +11 -5
  114. package/src/approval-paused-tool-settle.test.ts +325 -0
  115. package/src/client-approve.test.ts +311 -0
  116. package/src/client-history-eager.ts +9 -0
  117. package/src/client-history-loader.ts +23 -0
  118. package/src/client-history.ts +579 -0
  119. package/src/client-resume.ts +177 -0
  120. package/src/client-stream-eager.ts +12 -0
  121. package/src/client-stream-loader.ts +25 -0
  122. package/src/client-stream.ts +1880 -0
  123. package/src/client.test.ts +31 -1
  124. package/src/client.ts +293 -2607
  125. package/src/components/approval-actions.test.ts +27 -0
  126. package/src/components/approval-actions.ts +27 -3
  127. package/src/components/message-bubble.test.ts +19 -0
  128. package/src/components/message-bubble.ts +2 -0
  129. package/src/components/registry.ts +6 -6
  130. package/src/components/tool-bubble.test.ts +9 -0
  131. package/src/components/tool-bubble.ts +1 -0
  132. package/src/history-shell-bundle.test.ts +54 -0
  133. package/src/history-shell-eager.ts +12 -0
  134. package/src/history-shell-loader.ts +27 -0
  135. package/src/history-shell.ts +2362 -0
  136. package/src/history-view-loader.ts +2 -0
  137. package/src/history-view.ts +3 -0
  138. package/src/index-core.ts +6 -0
  139. package/src/index-global.ts +90 -248
  140. package/src/index.ts +13 -0
  141. package/src/install.ts +6 -4
  142. package/src/internal/runtype-history-provider.test.ts +1 -0
  143. package/src/internal/runtype-history-provider.ts +28 -13
  144. package/src/plugins/registry.ts +8 -8
  145. package/src/session-actions-chunk.test.ts +55 -0
  146. package/src/session-actions-eager.ts +11 -0
  147. package/src/session-actions-loader.ts +37 -0
  148. package/src/session-actions.ts +909 -0
  149. package/src/session-history.test.ts +3 -1
  150. package/src/session.ts +895 -1538
  151. package/src/session.voice.test.ts +1171 -5
  152. package/src/styles/widget.css +58 -0
  153. package/src/theme-editor/state.ts +91 -91
  154. package/src/types.ts +204 -5
  155. package/src/ui-ask-user-sheet.ts +382 -0
  156. package/src/ui-extras-eager.ts +10 -0
  157. package/src/ui-extras-entry.ts +9 -0
  158. package/src/ui-extras-loader.ts +26 -0
  159. package/src/ui.artifact-rail-resize.test.ts +2 -1
  160. package/src/ui.ask-user-chunk.test.ts +93 -0
  161. package/src/ui.history-chunk.test.ts +2 -1
  162. package/src/ui.history-config-provider.test.ts +2 -1
  163. package/src/ui.history-confirm-fallback.test.ts +142 -0
  164. package/src/ui.history-controller.test.ts +2 -1
  165. package/src/ui.history-lifecycle.test.ts +2 -1
  166. package/src/ui.history-render-hooks.test.ts +2 -1
  167. package/src/ui.history-shell.test.ts +2 -1
  168. package/src/ui.rail-overlay.test.ts +2 -1
  169. package/src/ui.rail-resize.test.ts +2 -1
  170. package/src/ui.rail-trigger-pending.test.ts +2 -1
  171. package/src/ui.ts +340 -2770
  172. package/src/utils/attachment-manager.ts +67 -67
  173. package/src/utils/constants.ts +3 -0
  174. package/src/utils/context-mention-controller.ts +323 -323
  175. package/src/utils/context-mention-manager.ts +40 -40
  176. package/src/utils/context-mention-orchestrator.ts +28 -0
  177. package/src/utils/event-stream-buffer.ts +50 -50
  178. package/src/utils/event-stream-store.ts +43 -43
  179. package/src/utils/throughput-tracker.ts +34 -34
  180. package/src/utils/virtual-scroller.ts +67 -67
  181. package/src/utils/visitor-store.test.ts +50 -0
  182. package/src/utils/visitor-store.ts +23 -5
  183. package/src/voice/__fixtures__/voice-wire/README.md +1 -0
  184. package/src/voice/__fixtures__/voice-wire/client/cancel.json +3 -0
  185. package/src/voice/__fixtures__/voice-wire/client/context.json +4 -0
  186. package/src/voice/__fixtures__/voice-wire/client/delegation_result.json +6 -0
  187. package/src/voice/__fixtures__/voice-wire/client/delegation_update.json +6 -0
  188. package/src/voice/__fixtures__/voice-wire/client/ping.json +3 -0
  189. package/src/voice/__fixtures__/voice-wire/client/playback_progress.json +5 -0
  190. package/src/voice/__fixtures__/voice-wire/client/start.json +3 -0
  191. package/src/voice/__fixtures__/voice-wire/server/artifact.json +11 -0
  192. package/src/voice/__fixtures__/voice-wire/server/attached.json +4 -0
  193. package/src/voice/__fixtures__/voice-wire/server/audio_clear.json +4 -0
  194. package/src/voice/__fixtures__/voice-wire/server/audio_end.json +3 -0
  195. package/src/voice/__fixtures__/voice-wire/server/delegation_cancelled.json +5 -0
  196. package/src/voice/__fixtures__/voice-wire/server/delegation_completed.json +8 -0
  197. package/src/voice/__fixtures__/voice-wire/server/delegation_started.json +15 -0
  198. package/src/voice/__fixtures__/voice-wire/server/error.json +6 -0
  199. package/src/voice/__fixtures__/voice-wire/server/metrics.json +10 -0
  200. package/src/voice/__fixtures__/voice-wire/server/pong.json +3 -0
  201. package/src/voice/__fixtures__/voice-wire/server/session_config.json +16 -0
  202. package/src/voice/__fixtures__/voice-wire/server/transcript_final.json +7 -0
  203. package/src/voice/__fixtures__/voice-wire/server/transcript_interim.json +4 -0
  204. package/src/voice/__fixtures__/voice-wire/server/transcript_partial.json +6 -0
  205. package/src/voice/__fixtures__/voice-wire/server/transcript_update.json +10 -0
  206. package/src/voice/__fixtures__/voice-wire/server/warning.json +5 -0
  207. package/src/voice/audio-playback-manager.test.ts +57 -0
  208. package/src/voice/audio-playback-manager.ts +120 -98
  209. package/src/voice/browser-voice-provider.ts +37 -37
  210. package/src/voice/fallback-speech-engine.ts +22 -16
  211. package/src/voice/keyed-voice-transcript.ts +314 -0
  212. package/src/voice/mic-state-styles.ts +182 -0
  213. package/src/voice/read-aloud-controller.ts +46 -44
  214. package/src/voice/runtype-speech-engine.ts +35 -33
  215. package/src/voice/runtype-voice-provider.ts +680 -189
  216. package/src/voice/session-voice-wiring.ts +266 -0
  217. package/src/voice/voice-delegation.test.ts +71 -0
  218. package/src/voice/voice-delegation.ts +364 -0
  219. package/src/voice/voice-turn-tracker.ts +6 -6
  220. package/src/voice/voice.test.ts +1060 -8
  221. package/src/voice/worklet-playback-engine.test.ts +81 -0
  222. package/src/voice/worklet-playback-engine.ts +21 -3
  223. package/src/voice-runtime-loader.ts +4 -1
  224. package/src/voice-runtime.ts +7 -0
  225. package/src/webmcp-runtime-entry.ts +41 -39
  226. package/dist/approval-ui-3NMYNXBD.js +0 -1
  227. package/dist/chunk-5EIIHQLQ.js +0 -1
  228. package/dist/chunk-7CO4T5KB.js +0 -1
  229. package/dist/chunk-EFJBUH5F.js +0 -1
  230. package/dist/chunk-R2TMIMDI.js +0 -3
  231. package/dist/chunk-UTVLOTWB.js +0 -9
  232. package/dist/context-mentions-45MODWOY.js +0 -161
  233. package/dist/event-stream-view-GL3ADRY2.js +0 -1
  234. package/dist/runtype-tts-entry-UJAEF7NZ.js +0 -1
  235. package/dist/voice-runtime-7DA7MJH4.js +0 -1
  236. package/dist/webmcp-runtime-JI7T4QYF.js +0 -6
@@ -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
- private listeners: ConfigChangeListener[] = [];
66
- private history: ConfiguratorSnapshot[] = [];
67
- private historyIndex = -1;
68
- private suppressHistory = false;
69
- private authoredConfig: Partial<AgentWidgetConfig> = {};
70
- private authoredTheme: DeepPartial<PersonaTheme> = {};
71
- private mergeDefaults = true;
72
- private snapshotIntent = new WeakMap<ConfiguratorSnapshot, { config: Partial<AgentWidgetConfig>; theme: DeepPartial<PersonaTheme> }>();
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.mergeDefaults = mergeDefaults;
81
- this.authoredConfig = { ...initialConfig };
82
- this.authoredTheme = initialTheme ?? {};
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.syncThemeIntoConfig();
93
- this.pushHistorySnapshot(this.exportSnapshot(), true);
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.recordIntent(path, value);
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.syncThemeIntoConfig();
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.rebaseDefaults(previousVersion);
149
- this.recordHistory();
150
- this.notifyListeners();
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.recordIntent(path, undefined, true);
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.syncThemeIntoConfig();
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.rebaseDefaults(previousVersion);
174
- this.recordHistory();
175
- this.notifyListeners();
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.recordIntent(path, value);
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.syncThemeIntoConfig();
206
+ this.#syncThemeIntoConfig();
207
207
  }
208
- this.rebaseDefaults(previousVersion);
208
+ this.#rebaseDefaults(previousVersion);
209
209
  if (themeChanged || darkThemeChanged || configChanged) {
210
- this.recordHistory();
211
- this.notifyListeners();
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.authoredTheme = theme;
217
+ this.#authoredTheme = theme;
218
218
  this.theme = theme;
219
- this.syncThemeIntoConfig();
220
- this.recordHistory();
221
- this.notifyListeners();
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.authoredConfig = { ...config };
227
- if (theme) this.authoredTheme = theme;
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.syncThemeIntoConfig();
233
- this.recordHistory();
234
- this.notifyListeners();
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.authoredConfig = future ? { future } : {};
263
- this.authoredTheme = {};
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.syncThemeIntoConfig();
270
- this.history = [];
271
- this.historyIndex = -1;
272
- this.pushHistorySnapshot(this.exportSnapshot());
273
- this.notifyListeners();
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.historyIndex > 0;
279
+ return this.#historyIndex > 0;
280
280
  }
281
281
 
282
282
  canRedo(): boolean {
283
- return this.historyIndex >= 0 && this.historyIndex < this.history.length - 1;
283
+ return this.#historyIndex >= 0 && this.#historyIndex < this.#history.length - 1;
284
284
  }
285
285
 
286
286
  getHistoryLength(): number {
287
- return this.history.length;
287
+ return this.#history.length;
288
288
  }
289
289
 
290
290
  getHistoryIndex(): number {
291
- return this.historyIndex;
291
+ return this.#historyIndex;
292
292
  }
293
293
 
294
294
  undo(): void {
295
295
  if (!this.canUndo()) return;
296
- this.historyIndex -= 1;
297
- this.restoreSnapshot(this.history[this.historyIndex]);
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.historyIndex += 1;
303
- this.restoreSnapshot(this.history[this.historyIndex]);
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.listeners.push(listener);
319
+ this.#listeners.push(listener);
320
320
  return () => {
321
- const idx = this.listeners.indexOf(listener);
322
- if (idx >= 0) this.listeners.splice(idx, 1);
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
- private recordIntent(path: string, value: unknown, remove = false): void {
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.authoredTheme = write(this.authoredTheme, path.slice(6)) as DeepPartial<PersonaTheme>;
332
+ this.#authoredTheme = write(this.#authoredTheme, path.slice(6)) as DeepPartial<PersonaTheme>;
333
333
  } else if (path === 'theme') {
334
- this.authoredTheme = (value ?? {}) as DeepPartial<PersonaTheme>;
334
+ this.#authoredTheme = (value ?? {}) as DeepPartial<PersonaTheme>;
335
335
  } else {
336
- this.authoredConfig = write(this.authoredConfig, path) as Partial<AgentWidgetConfig>;
336
+ this.#authoredConfig = write(this.#authoredConfig, path) as Partial<AgentWidgetConfig>;
337
337
  }
338
338
  }
339
339
 
340
- private rebaseDefaults(previousVersion: string): void {
340
+ #rebaseDefaults(previousVersion: string): void {
341
341
  if (previousVersion === resolveDefaultsVersion(this.config)) return;
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();
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
- private syncThemeIntoConfig(): void {
349
+ #syncThemeIntoConfig(): void {
350
350
  this.config = {
351
351
  ...this.config,
352
352
  theme: this.theme,
353
353
  };
354
354
  }
355
355
 
356
- private notifyListeners(): void {
357
- for (const listener of this.listeners) {
356
+ #notifyListeners(): void {
357
+ for (const listener of this.#listeners) {
358
358
  listener(this.config, this.theme);
359
359
  }
360
360
  }
361
361
 
362
- private recordHistory(): void {
363
- this.pushHistorySnapshot(this.exportSnapshot());
362
+ #recordHistory(): void {
363
+ this.#pushHistorySnapshot(this.exportSnapshot());
364
364
  }
365
365
 
366
- private pushHistorySnapshot(snapshot: ConfiguratorSnapshot, replaceCurrent = false): void {
367
- if (this.suppressHistory) return;
368
- this.snapshotIntent.set(snapshot, { config: this.authoredConfig, theme: this.authoredTheme });
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.historyIndex >= 0 && this.history[this.historyIndex]
373
- ? JSON.stringify(this.history[this.historyIndex])
372
+ this.#historyIndex >= 0 && this.#history[this.#historyIndex]
373
+ ? JSON.stringify(this.#history[this.#historyIndex])
374
374
  : null;
375
375
 
376
- if (replaceCurrent && this.historyIndex >= 0) {
377
- this.history[this.historyIndex] = snapshot;
376
+ if (replaceCurrent && this.#historyIndex >= 0) {
377
+ this.#history[this.#historyIndex] = snapshot;
378
378
  return;
379
379
  }
380
380
 
381
- const currentIntent = this.historyIndex >= 0
382
- ? this.snapshotIntent.get(this.history[this.historyIndex]) : undefined;
381
+ const currentIntent = this.#historyIndex >= 0
382
+ ? this.#snapshotIntent.get(this.#history[this.#historyIndex]) : undefined;
383
383
  if (serialized === currentSerialized &&
384
- JSON.stringify(this.snapshotIntent.get(snapshot)) === JSON.stringify(currentIntent)) return;
384
+ JSON.stringify(this.#snapshotIntent.get(snapshot)) === JSON.stringify(currentIntent)) return;
385
385
 
386
- this.history = this.history.slice(0, this.historyIndex + 1);
387
- this.history.push(snapshot);
388
- this.historyIndex = this.history.length - 1;
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
- private 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;
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.syncThemeIntoConfig();
399
- this.suppressHistory = false;
400
- this.notifyListeners();
398
+ this.#syncThemeIntoConfig();
399
+ this.#suppressHistory = false;
400
+ this.#notifyListeners();
401
401
  }
402
402
  }