martty 0.2.17 → 0.2.18

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.
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": "catppuccin",
3
+ "label": "Catppuccin",
4
+ "dark": {
5
+ "bg": "#1e1e2e",
6
+ "surface": "#1e1e2e",
7
+ "panel": "#45475a",
8
+ "fg": "#cdd6f4",
9
+ "fg_secondary": "#585b70",
10
+ "fg_tertiary": "#585b70",
11
+ "caption": "#585b70",
12
+ "brand": "#89b4fa",
13
+ "brand_soft": "#f5c2e7",
14
+ "bubble_bg": "#353748",
15
+ "bubble_fg": "#cdd6f4",
16
+ "border": "#585b70",
17
+ "code_bg": "#1e1e2e",
18
+ "ok": "#a6e3a1",
19
+ "warn": "#f9e2af",
20
+ "err": "#f38ba8",
21
+ "hint": "#94e2d5",
22
+ "chip_bg": "#45475a"
23
+ },
24
+ "light": {
25
+ "bg": "#eff1f5",
26
+ "surface": "#eff1f5",
27
+ "panel": "#bcc0cc",
28
+ "fg": "#4c4f69",
29
+ "fg_secondary": "#6c6f85",
30
+ "fg_tertiary": "#6c6f85",
31
+ "caption": "#6c6f85",
32
+ "brand": "#1e66f5",
33
+ "brand_soft": "#ea76cb",
34
+ "bubble_bg": "#d8dae1",
35
+ "bubble_fg": "#4c4f69",
36
+ "border": "#6c6f85",
37
+ "code_bg": "#eff1f5",
38
+ "ok": "#40a02b",
39
+ "warn": "#df8e1d",
40
+ "err": "#d20f39",
41
+ "hint": "#179299",
42
+ "chip_bg": "#bcc0cc"
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": "everforest",
3
+ "label": "Everforest",
4
+ "dark": {
5
+ "bg": "#2d353b",
6
+ "surface": "#2d353b",
7
+ "panel": "#343f44",
8
+ "fg": "#d3c6aa",
9
+ "fg_secondary": "#859289",
10
+ "fg_tertiary": "#859289",
11
+ "caption": "#859289",
12
+ "brand": "#7fbbb3",
13
+ "brand_soft": "#d699b6",
14
+ "bubble_bg": "#414b51",
15
+ "bubble_fg": "#d3c6aa",
16
+ "border": "#859289",
17
+ "code_bg": "#2d353b",
18
+ "ok": "#a7c080",
19
+ "warn": "#dbbc7f",
20
+ "err": "#e67e80",
21
+ "hint": "#83c092",
22
+ "chip_bg": "#343f44"
23
+ },
24
+ "light": {
25
+ "bg": "#fdf6e3",
26
+ "surface": "#fdf6e3",
27
+ "panel": "#f4f0d9",
28
+ "fg": "#5c6a72",
29
+ "fg_secondary": "#939f91",
30
+ "fg_tertiary": "#939f91",
31
+ "caption": "#939f91",
32
+ "brand": "#3a94c5",
33
+ "brand_soft": "#df69ba",
34
+ "bubble_bg": "#efe9d5",
35
+ "bubble_fg": "#5c6a72",
36
+ "border": "#939f91",
37
+ "code_bg": "#fdf6e3",
38
+ "ok": "#8da101",
39
+ "warn": "#dfa000",
40
+ "err": "#f85552",
41
+ "hint": "#35a77c",
42
+ "chip_bg": "#f4f0d9"
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": "iceberg",
3
+ "label": "Iceberg",
4
+ "dark": {
5
+ "bg": "#161821",
6
+ "surface": "#161821",
7
+ "panel": "#1e2132",
8
+ "fg": "#c6c8d1",
9
+ "fg_secondary": "#6b7089",
10
+ "fg_tertiary": "#6b7089",
11
+ "caption": "#6b7089",
12
+ "brand": "#84a0c6",
13
+ "brand_soft": "#a093c7",
14
+ "bubble_bg": "#272c42",
15
+ "bubble_fg": "#c6c8d1",
16
+ "border": "#6b7089",
17
+ "code_bg": "#161821",
18
+ "ok": "#b4be82",
19
+ "warn": "#e2a478",
20
+ "err": "#e27878",
21
+ "hint": "#89b8c2",
22
+ "chip_bg": "#1e2132"
23
+ },
24
+ "light": {
25
+ "bg": "#e8e9ec",
26
+ "surface": "#e8e9ec",
27
+ "panel": "#dcdfe7",
28
+ "fg": "#33374c",
29
+ "fg_secondary": "#8389a3",
30
+ "fg_tertiary": "#8389a3",
31
+ "caption": "#8389a3",
32
+ "brand": "#2d539e",
33
+ "brand_soft": "#7759b4",
34
+ "bubble_bg": "#cacdd7",
35
+ "bubble_fg": "#33374c",
36
+ "border": "#8389a3",
37
+ "code_bg": "#e8e9ec",
38
+ "ok": "#668e3d",
39
+ "warn": "#c57339",
40
+ "err": "#cc517a",
41
+ "hint": "#3f83a6",
42
+ "chip_bg": "#dcdfe7"
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": "kanagawa",
3
+ "label": "Kanagawa",
4
+ "dark": {
5
+ "bg": "#1f1f28",
6
+ "surface": "#1f1f28",
7
+ "panel": "#16161d",
8
+ "fg": "#dcd7ba",
9
+ "fg_secondary": "#727169",
10
+ "fg_tertiary": "#727169",
11
+ "caption": "#727169",
12
+ "brand": "#7e9cd8",
13
+ "brand_soft": "#957fb8",
14
+ "bubble_bg": "#2d4f67",
15
+ "bubble_fg": "#c8c093",
16
+ "border": "#727169",
17
+ "code_bg": "#1f1f28",
18
+ "ok": "#76946a",
19
+ "warn": "#c0a36e",
20
+ "err": "#c34043",
21
+ "hint": "#6a9589",
22
+ "chip_bg": "#16161d"
23
+ },
24
+ "light": {
25
+ "bg": "#f2ecbc",
26
+ "surface": "#f2ecbc",
27
+ "panel": "#c9cbd1",
28
+ "fg": "#545464",
29
+ "fg_secondary": "#8a8980",
30
+ "fg_tertiary": "#8a8980",
31
+ "caption": "#8a8980",
32
+ "brand": "#4d699b",
33
+ "brand_soft": "#b35b79",
34
+ "bubble_bg": "#c9cbd1",
35
+ "bubble_fg": "#43436c",
36
+ "border": "#8a8980",
37
+ "code_bg": "#f2ecbc",
38
+ "ok": "#6f894e",
39
+ "warn": "#77713f",
40
+ "err": "#c84053",
41
+ "hint": "#597b75",
42
+ "chip_bg": "#c9cbd1"
43
+ }
44
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": "solarized",
3
+ "label": "Solarized",
4
+ "dark": {
5
+ "bg": "#002b36",
6
+ "surface": "#002b36",
7
+ "panel": "#073642",
8
+ "fg": "#839496",
9
+ "fg_secondary": "#586e75",
10
+ "fg_tertiary": "#586e75",
11
+ "caption": "#586e75",
12
+ "brand": "#268bd2",
13
+ "brand_soft": "#d33682",
14
+ "bubble_bg": "#073642",
15
+ "bubble_fg": "#93a1a1",
16
+ "border": "#586e75",
17
+ "code_bg": "#002b36",
18
+ "ok": "#859900",
19
+ "warn": "#b58900",
20
+ "err": "#dc322f",
21
+ "hint": "#2aa198",
22
+ "chip_bg": "#073642"
23
+ },
24
+ "light": {
25
+ "bg": "#fdf6e3",
26
+ "surface": "#fdf6e3",
27
+ "panel": "#eee8d5",
28
+ "fg": "#657b83",
29
+ "fg_secondary": "#586e75",
30
+ "fg_tertiary": "#586e75",
31
+ "caption": "#586e75",
32
+ "brand": "#268bd2",
33
+ "brand_soft": "#d33682",
34
+ "bubble_bg": "#eee8d5",
35
+ "bubble_fg": "#586e75",
36
+ "border": "#586e75",
37
+ "code_bg": "#fdf6e3",
38
+ "ok": "#859900",
39
+ "warn": "#b58900",
40
+ "err": "#dc322f",
41
+ "hint": "#2aa198",
42
+ "chip_bg": "#eee8d5"
43
+ }
44
+ }
package/lib/runner.js CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { spawn } from 'node:child_process'
11
11
  import { createRequire } from 'node:module'
12
- import { fileURLToPath } from 'node:url'
12
+ import { fileURLToPath, pathToFileURL } from 'node:url'
13
13
 
14
14
  export const name = 'dsh-tui-runner'
15
15
  export const inject = ['loader', 'acpServer', 'cmdlineArgs', 'appExit', 'tuiClientPlugins']
@@ -20,7 +20,7 @@ const requireFromTui = createRequire(import.meta.url)
20
20
  function ownAcpBridge() {
21
21
  const specifier = '@openma/deepseek-harness-acp/bridge'
22
22
  try {
23
- return requireFromTui.resolve(specifier)
23
+ return pathToFileURL(requireFromTui.resolve(specifier)).href
24
24
  } catch {
25
25
  // A source-linked package may rely on the active profile's installation.
26
26
  return specifier
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Gallery palette pack `solarized`. Registers complete dark/light token maps:
3
+ * dark from Solarized Dark, light from Solarized Light (terminalcolors.com/themes/solarized). Does not activate:
4
+ * `/theme` covers it. `inject = ['tuiTheme']`: sibling profile row, not
5
+ * `ctx.plugin` inside the runner.
6
+ */
7
+
8
+ import { readFileSync } from 'node:fs'
9
+
10
+ const solarizedPalette = JSON.parse(
11
+ readFileSync(new URL('./palettes/solarized.json', import.meta.url), 'utf8'),
12
+ )
13
+
14
+ export const name = 'tui-theme-solarized'
15
+ export const inject = ['tuiTheme']
16
+
17
+ export function apply(ctx) {
18
+ ctx.effect(() => ctx.tuiTheme.register(solarizedPalette, { activate: false }))
19
+ }
20
+
21
+ export { solarizedPalette }
@@ -8,7 +8,7 @@ export const name = 'tui-client-plugin-registry'
8
8
  export const inject = []
9
9
 
10
10
  const ID = /^[a-z0-9][a-z0-9-]*$/
11
- const KINDS = new Set(['theme', 'ui-preset'])
11
+ const KINDS = new Set(['theme', 'ui', 'ui-preset'])
12
12
 
13
13
  function normalizeEntry(value) {
14
14
  if (typeof value !== 'string' || value.length === 0) {
@@ -41,14 +41,14 @@ class TuiClientPluginsService extends Service {
41
41
  throw new Error('tuiClientPlugins.register: id must be a lowercase package identifier')
42
42
  }
43
43
  if (!KINDS.has(options.kind)) {
44
- throw new Error('tuiClientPlugins.register: kind must be "theme" or "ui-preset"')
44
+ throw new Error('tuiClientPlugins.register: kind must be "theme" or "ui"')
45
45
  }
46
46
  if (this.entries.has(options.id)) {
47
47
  throw new Error(`tuiClientPlugins.register: id ${JSON.stringify(options.id)} is already registered`)
48
48
  }
49
49
  const entry = {
50
50
  id: options.id,
51
- kind: options.kind,
51
+ kind: options.kind === 'ui-preset' ? 'ui' : options.kind,
52
52
  entry: normalizeEntry(options.entry),
53
53
  }
54
54
  this.entries.set(entry.id, entry)
@@ -9,7 +9,7 @@ const PACKAGE_PREFIX = 'tui-package:'
9
9
  * @param {object} ctx
10
10
  * @param {{
11
11
  * store: object,
12
- * packages?: Array<{ id: string, kind: 'theme' | 'ui-preset', entry: string }>,
12
+ * packages?: Array<{ id: string, kind: 'theme' | 'ui', entry: string }>,
13
13
  * tuiTheme?: object,
14
14
  * tuiPresets?: object,
15
15
  * tuiSlots?: object,
@@ -34,6 +34,7 @@ export function installTuiLocalPlugins(ctx, options) {
34
34
 
35
35
  const env = (pluginId) => ({
36
36
  pluginId,
37
+ pluginSource: 'static',
37
38
  tuiTheme: options.tuiTheme,
38
39
  tuiPresets: options.tuiPresets,
39
40
  tuiSlots: options.tuiSlots,
@@ -14,7 +14,7 @@ import { homedir } from 'node:os'
14
14
  import path from 'node:path'
15
15
 
16
16
  const ARTIFACT_ID = /^[a-z0-9][a-z0-9-]*$/
17
- const KINDS = new Set(['theme', 'ui-preset'])
17
+ const KINDS = new Set(['theme', 'ui', 'ui-preset'])
18
18
  const MANIFEST = 'plugin.json'
19
19
 
20
20
  function artifactId(value) {
@@ -38,7 +38,8 @@ function validateManifest(value, expectedId) {
38
38
  if (value.schemaVersion !== 0) throw new Error('schemaVersion must be 0')
39
39
  const id = artifactId(value.id)
40
40
  if (id !== expectedId) throw new Error(`manifest id must match directory ${JSON.stringify(expectedId)}`)
41
- if (!KINDS.has(value.kind)) throw new Error('kind must be "theme" or "ui-preset"')
41
+ if (!KINDS.has(value.kind)) throw new Error('kind must be "theme" or "ui"')
42
+ const kind = value.kind === 'ui-preset' ? 'ui' : value.kind
42
43
  const name = nonEmpty(value.name, 'name')
43
44
  const purpose = nonEmpty(value.purpose, 'purpose')
44
45
  if (value.source === null || typeof value.source !== 'object' || Array.isArray(value.source)) {
@@ -53,7 +54,7 @@ function validateManifest(value, expectedId) {
53
54
  return {
54
55
  schemaVersion: 0,
55
56
  id,
56
- kind: value.kind,
57
+ kind,
57
58
  name,
58
59
  purpose,
59
60
  source: { pluginId, packageId },
@@ -3,6 +3,7 @@
3
3
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
4
4
  import path from 'node:path'
5
5
  import { Service } from '@deepseek-ai/cordis'
6
+ import { CORDIS_METHODS } from './cordis-protocol.js'
6
7
 
7
8
  export const name = 'tui-presets'
8
9
  export const inject = ['tuiCommands', 'tuiOverlay']
@@ -19,6 +20,10 @@ class TuiPresetsService extends Service {
19
20
  return this.core.register(options, mount)
20
21
  }
21
22
 
23
+ registerOwned(owner, options, mount, registerOptions) {
24
+ return this.core.registerOwned(owner, options, mount, registerOptions)
25
+ }
26
+
22
27
  activate(id) {
23
28
  return this.core.activate(id)
24
29
  }
@@ -27,6 +32,26 @@ class TuiPresetsService extends Service {
27
32
  return this.core.list()
28
33
  }
29
34
 
35
+ catalog() {
36
+ return this.core.catalog()
37
+ }
38
+
39
+ owner(id) {
40
+ return this.core.owner(id)
41
+ }
42
+
43
+ isLoaded(id) {
44
+ return this.core.isLoaded(id)
45
+ }
46
+
47
+ bindLifecycle(fn) {
48
+ return this.core.bindLifecycle(fn)
49
+ }
50
+
51
+ bindNotify(fn) {
52
+ return this.core.bindNotify(fn)
53
+ }
54
+
30
55
  active() {
31
56
  return this.core.active()
32
57
  }
@@ -67,6 +92,26 @@ export function installTuiPresets(ctx, options = {}) {
67
92
  let releaseActive
68
93
  let presetSelector
69
94
  let disposed = false
95
+ let lifecycle
96
+ let send = typeof options.notify === 'function' ? options.notify : undefined
97
+ const queue = []
98
+
99
+ function emit(params) {
100
+ if (send !== undefined) send(CORDIS_METHODS.uiUpdate, params)
101
+ else queue.push(params)
102
+ }
103
+
104
+ function publish() {
105
+ emit({ protocol: 0, plugins: catalog() })
106
+ }
107
+
108
+ function bindNotify(fn) {
109
+ if (typeof fn !== 'function') throw new Error('tuiPresets.bindNotify needs a function')
110
+ send = fn
111
+ const pending = queue.splice(0, queue.length)
112
+ for (const params of pending) send(CORDIS_METHODS.uiUpdate, params)
113
+ publish()
114
+ }
70
115
 
71
116
  function mount(entry) {
72
117
  const mounted = entry.mount()
@@ -109,31 +154,45 @@ export function installTuiPresets(ctx, options = {}) {
109
154
  if (entry === undefined) {
110
155
  throw new Error(`tuiPresets.activate: preset "${id}" is not registered`)
111
156
  }
157
+ if (!entry.loaded) {
158
+ throw new Error(`tuiPresets.activate: UI Plugin for "${id}" is not loaded`)
159
+ }
112
160
  switchTo(entry)
113
161
  if (persist) {
114
162
  preferredId = id
115
163
  writePreferred(settingsPath, id)
116
164
  }
165
+ publish()
117
166
  }
118
167
 
119
168
  function fallback() {
120
- const next = entries.get(preferredId) ?? entries.get('default') ?? entries.values().next().value
169
+ const preferred = entries.get(preferredId)
170
+ const stock = entries.get('default')
171
+ const next = (preferred?.loaded === true ? preferred : undefined)
172
+ ?? (stock?.loaded === true ? stock : undefined)
173
+ ?? [...entries.values()].find((entry) => entry.loaded)
121
174
  if (next !== undefined) switchTo(next)
122
175
  }
123
176
 
124
177
  function refreshCommandInput() {
125
178
  stopCommand?.update?.({
126
179
  input: {
127
- hint: 'preset',
128
- options: list().map((entry) => ({
180
+ hint: 'plugin',
181
+ options: catalog().map((entry) => ({
129
182
  value: entry.id,
130
183
  label: entry.label,
184
+ description: `${entry.source} · ${entry.status}`,
131
185
  })),
132
186
  },
133
187
  })
188
+ publish()
134
189
  }
135
190
 
136
191
  function register(options, mountPreset) {
192
+ return registerOwned(undefined, options, mountPreset, { source: 'static' })
193
+ }
194
+
195
+ function registerOwned(owner, options, mountPreset, registerOptions = {}) {
137
196
  if (disposed) throw new Error('tuiPresets: registry is disposed')
138
197
  if (options === null || typeof options !== 'object' || Array.isArray(options)) {
139
198
  throw new Error('tuiPresets.register: options must be an object')
@@ -151,10 +210,23 @@ export function installTuiPresets(ctx, options = {}) {
151
210
  if (typeof mountPreset !== 'function') {
152
211
  throw new Error('tuiPresets.register: mount must be a function')
153
212
  }
154
- if (entries.has(options.id)) {
213
+ if (owner !== undefined && (typeof owner !== 'string' || owner.length === 0)) {
214
+ throw new Error('tuiPresets.registerOwned: owner must be a non-empty string')
215
+ }
216
+ const source = owner === undefined ? 'static' : registerOptions.source ?? 'dynamic'
217
+ if (source !== 'static' && source !== 'dynamic') {
218
+ throw new Error('tuiPresets.register: source must be static or dynamic')
219
+ }
220
+ const retained = entries.get(options.id)
221
+ const resumesOwner = owner !== undefined
222
+ && retained?.owner === owner
223
+ && retained.loaded === false
224
+ if (retained !== undefined && !resumesOwner) {
155
225
  throw new Error(`tuiPresets.register: preset "${options.id}" is already registered`)
156
226
  }
157
- const entry = { id: options.id, label: options.label, mount: mountPreset }
227
+ const entry = resumesOwner
228
+ ? Object.assign(retained, { label: options.label, mount: mountPreset, source, loaded: true })
229
+ : { id: options.id, label: options.label, mount: mountPreset, owner, source, loaded: true }
158
230
  entries.set(entry.id, entry)
159
231
  refreshCommandInput()
160
232
  if (activeEntry === undefined || entry.id === preferredId) fallback()
@@ -170,7 +242,8 @@ export function installTuiPresets(ctx, options = {}) {
170
242
  activeEntry = undefined
171
243
  releaseActive = undefined
172
244
  }
173
- entries.delete(entry.id)
245
+ if (entry.owner === undefined) entries.delete(entry.id)
246
+ else entry.loaded = false
174
247
  refreshCommandInput()
175
248
  if (wasActive) fallback()
176
249
  }
@@ -180,30 +253,69 @@ export function installTuiPresets(ctx, options = {}) {
180
253
  return [...entries.values()].map(({ id, label }) => ({ id, label }))
181
254
  }
182
255
 
256
+ function catalog() {
257
+ return [...entries.values()].map((entry) => ({
258
+ id: entry.id,
259
+ label: entry.label,
260
+ source: entry.source,
261
+ status: activeEntry === entry ? 'active' : entry.loaded
262
+ ? (entry.source === 'dynamic' ? 'running' : 'ready')
263
+ : 'stopped',
264
+ ...(entry.owner === undefined ? {} : { owner: { pluginId: entry.owner } }),
265
+ }))
266
+ }
267
+
268
+ function owner(id) {
269
+ return entries.get(id)?.owner
270
+ }
271
+
272
+ function isLoaded(id) {
273
+ return entries.get(id)?.loaded === true
274
+ }
275
+
276
+ function bindLifecycle(fn) {
277
+ if (typeof fn !== 'function') throw new Error('tuiPresets.bindLifecycle needs a function')
278
+ lifecycle = fn
279
+ return () => {
280
+ if (lifecycle === fn) lifecycle = undefined
281
+ }
282
+ }
283
+
284
+ async function requestActivate(id) {
285
+ const entry = entries.get(id)
286
+ if (entry === undefined) throw new Error(`tuiPresets.activate: preset "${id}" is not registered`)
287
+ if (entry.loaded) return activate(id)
288
+ if (lifecycle === undefined || entry.owner === undefined) {
289
+ throw new Error(`tuiPresets.activate: UI Plugin for "${id}" is not loaded`)
290
+ }
291
+ await lifecycle(id, entry.owner)
292
+ if (entries.get(id)?.loaded === true && active() !== id) activate(id)
293
+ }
294
+
183
295
  function active() {
184
296
  return activeEntry?.id
185
297
  }
186
298
 
187
299
  const stopCommand = ctx.tuiCommands.register({
188
300
  name: 'ui',
189
- description: 'Switch UI preset',
301
+ description: 'Switch UI Plugin',
190
302
  }, async (args = '') => {
191
303
  const id = args.trim().toLowerCase()
192
304
  if (id.length === 0) {
193
- const choices = list()
194
305
  presetSelector?.close()
195
306
  presetSelector = ctx.tuiOverlay.openSelect({
196
307
  id: 'ui-preset',
197
- title: 'UI preset',
308
+ title: 'UI Plugin',
198
309
  value: active(),
199
- options: choices.map((entry) => ({
310
+ options: catalog().map((entry) => ({
200
311
  value: entry.id,
201
312
  label: entry.label,
313
+ description: `${entry.source} · ${entry.status}`,
202
314
  })),
203
315
  }, {
204
316
  onSubmit(value) {
205
317
  presetSelector = undefined
206
- activate(value)
318
+ return requestActivate(value)
207
319
  },
208
320
  onCancel() {
209
321
  presetSelector = undefined
@@ -211,7 +323,7 @@ export function installTuiPresets(ctx, options = {}) {
211
323
  })
212
324
  return
213
325
  }
214
- activate(id)
326
+ await requestActivate(id)
215
327
  })
216
328
  refreshCommandInput()
217
329
 
@@ -225,9 +337,13 @@ export function installTuiPresets(ctx, options = {}) {
225
337
  activeEntry = undefined
226
338
  releaseActive = undefined
227
339
  entries.clear()
340
+ lifecycle = undefined
228
341
  }
229
342
 
230
- const core = { register, activate, list, active, dispose }
343
+ const core = {
344
+ register, registerOwned, activate, list, catalog, owner, isLoaded, bindLifecycle, bindNotify,
345
+ active, dispose,
346
+ }
231
347
  const service = typeof ctx.provide === 'function'
232
348
  ? new TuiPresetsService(ctx, core)
233
349
  : core
package/lib/tui-theme.js CHANGED
@@ -242,7 +242,7 @@ export function installTuiTheme(ctx, options = {}) {
242
242
  let activationRevision = 0
243
243
 
244
244
  const builtin = validatePalette(defaultPalette)
245
- palettes.set(builtin.id, { palette: builtin, owner: undefined, loaded: true })
245
+ palettes.set(builtin.id, { palette: builtin, owner: undefined, loaded: true, source: 'static' })
246
246
 
247
247
  function emit(method, params) {
248
248
  if (typeof send === 'function') {
@@ -279,7 +279,14 @@ export function installTuiTheme(ctx, options = {}) {
279
279
  activeId = id
280
280
  activationRevision += 1
281
281
  if (notifyPainter) {
282
- emit(CORDIS_METHODS.themeUpdate, { protocol: PROTOCOL, palette, activate: true })
282
+ emit(CORDIS_METHODS.themeUpdate, {
283
+ protocol: PROTOCOL,
284
+ palette,
285
+ activate: true,
286
+ loaded: entry.loaded,
287
+ source: entry.source,
288
+ ...(entry.owner === undefined ? {} : { owner: { pluginId: entry.owner } }),
289
+ })
283
290
  }
284
291
  if (previousId !== id) {
285
292
  for (const listener of [...listeners]) {
@@ -336,13 +343,18 @@ export function installTuiTheme(ctx, options = {}) {
336
343
  const setup = () => {
337
344
  const previousId = cover ? activeId : undefined
338
345
  let leaseRevision
339
- entry = { palette: validated, owner, loaded: true }
346
+ const source = owner === undefined ? 'static' : registerOptions.source ?? 'dynamic'
347
+ if (source !== 'static' && source !== 'dynamic') {
348
+ throw new Error('tuiTheme.register: source must be static or dynamic')
349
+ }
350
+ entry = { palette: validated, owner, loaded: true, source }
340
351
  palettes.set(validated.id, entry)
341
352
  emit(CORDIS_METHODS.themeUpdate, {
342
353
  protocol: PROTOCOL,
343
354
  palette: validated,
344
355
  activate: false,
345
356
  loaded: true,
357
+ source,
346
358
  ...(owner === undefined ? {} : { owner: { pluginId: owner } }),
347
359
  })
348
360
  if (cover) {
@@ -372,6 +384,7 @@ export function installTuiTheme(ctx, options = {}) {
372
384
  palette: validated,
373
385
  activate: false,
374
386
  loaded: false,
387
+ source: entry.source,
375
388
  owner: { pluginId: owner },
376
389
  })
377
390
  }
@@ -400,6 +413,7 @@ export function installTuiTheme(ctx, options = {}) {
400
413
  palette: next,
401
414
  activate: false,
402
415
  loaded: true,
416
+ source: entry.source,
403
417
  ...(owner === undefined ? {} : { owner: { pluginId: owner } }),
404
418
  })
405
419
  }