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.
- package/lib/acp-host.js +23 -11
- package/lib/ayu.js +22 -0
- package/lib/boot.js +26 -4
- package/lib/catppuccin.js +23 -0
- package/lib/client-run.js +11 -2
- package/lib/cordis-protocol.js +4 -0
- package/lib/creator-overlay.js +3 -3
- package/lib/everforest.js +21 -0
- package/lib/iceberg.js +21 -0
- package/lib/index.js +10 -2
- package/lib/inspect.js +139 -7
- package/lib/kanagawa.js +22 -0
- package/lib/mux.js +2 -0
- package/lib/palettes/ayu.json +44 -0
- package/lib/palettes/catppuccin.json +44 -0
- package/lib/palettes/everforest.json +44 -0
- package/lib/palettes/iceberg.json +44 -0
- package/lib/palettes/kanagawa.json +44 -0
- package/lib/palettes/solarized.json +44 -0
- package/lib/runner.js +2 -2
- package/lib/solarized.js +21 -0
- package/lib/tui-client-plugin-registry.js +3 -3
- package/lib/tui-local-plugins.js +2 -1
- package/lib/tui-plugin-store.js +4 -3
- package/lib/tui-presets.js +129 -13
- package/lib/tui-theme.js +17 -3
- package/package.json +4 -3
- package/skills/tui-plugin-development/SKILL.md +11 -8
- package/vendor/darwin-arm64/dsh-tui +0 -0
- package/vendor/darwin-x64/dsh-tui +0 -0
- package/vendor/linux-arm64/dsh-tui +0 -0
- package/vendor/linux-x64/dsh-tui +0 -0
- package/vendor/win32-x64/dsh-tui.exe +0 -0
|
@@ -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
|
package/lib/solarized.js
ADDED
|
@@ -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
|
|
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)
|
package/lib/tui-local-plugins.js
CHANGED
|
@@ -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
|
|
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,
|
package/lib/tui-plugin-store.js
CHANGED
|
@@ -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
|
|
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
|
|
57
|
+
kind,
|
|
57
58
|
name,
|
|
58
59
|
purpose,
|
|
59
60
|
source: { pluginId, packageId },
|
package/lib/tui-presets.js
CHANGED
|
@@ -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
|
|
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: '
|
|
128
|
-
options:
|
|
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 (
|
|
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 =
|
|
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
|
|
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
|
|
308
|
+
title: 'UI Plugin',
|
|
198
309
|
value: active(),
|
|
199
|
-
options:
|
|
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
|
-
|
|
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
|
-
|
|
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 = {
|
|
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, {
|
|
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
|
-
|
|
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
|
}
|