@mirrowel/opencode-openshare 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +181 -2
- package/ci/README.md +56 -0
- package/ci/openshare.config.json +10 -0
- package/ci/openshare.js +2270 -0
- package/dist/commands.d.ts +7 -0
- package/dist/commands.js +440 -0
- package/dist/config.d.ts +138 -0
- package/dist/config.js +524 -0
- package/dist/core.d.ts +117 -0
- package/dist/core.js +1944 -0
- package/dist/dialogs.d.ts +94 -0
- package/dist/dialogs.js +725 -0
- package/dist/server.d.ts +64 -0
- package/dist/server.js +30 -0
- package/dist/settings.d.ts +24 -0
- package/dist/settings.js +1226 -0
- package/dist/share-flow.d.ts +287 -0
- package/dist/share-flow.js +516 -0
- package/dist/sidebar.d.ts +19 -0
- package/dist/sidebar.js +144 -0
- package/dist/tui-host.d.ts +158 -0
- package/dist/tui-host.js +6 -0
- package/dist/tui.d.ts +17 -0
- package/dist/tui.js +4719 -0
- package/dist/ui-prefs.d.ts +16 -0
- package/dist/ui-prefs.js +27 -0
- package/dist/v2-server.d.ts +81 -0
- package/dist/v2-server.js +402 -0
- package/dist/v2-tui.d.ts +24 -0
- package/dist/v2-tui.js +313 -0
- package/dist/v2-types.d.ts +134 -0
- package/dist/v2-types.js +8 -0
- package/openshare.config.json +16 -0
- package/package.json +98 -4
- package/src/banner.txt +25 -0
- package/src/commands.ts +452 -0
- package/src/config.ts +524 -0
- package/src/core.ts +1997 -0
- package/src/dialogs.tsx +971 -0
- package/src/server.ts +47 -0
- package/src/settings.ts +1239 -0
- package/src/share-flow.ts +551 -0
- package/src/sidebar.tsx +187 -0
- package/src/tui-host.ts +134 -0
- package/src/tui.tsx +318 -0
- package/src/ui-prefs.ts +36 -0
- package/src/v2-server.ts +438 -0
- package/src/v2-tui.ts +315 -0
- package/src/v2-types.ts +102 -0
- package/tsconfig.json +18 -0
package/src/v2-tui.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode v2 TUI plugin implementation: builds a ShareHostApi adapter
|
|
3
|
+
* over the v2 TUI plugin context so the unchanged share flows and settings
|
|
4
|
+
* dialog run on both hosts, and registers the same commands (one reactive
|
|
5
|
+
* keymap layer).
|
|
6
|
+
*
|
|
7
|
+
* Dialog bridging (family pattern): the v1 api exposes dialog components
|
|
8
|
+
* that RETURN JSX rendered inside an enclosing `dialog.replace(render)`
|
|
9
|
+
* entry; the v2 api only offers promise-based dialogs that open their own
|
|
10
|
+
* host entry. The bridge reconciles the two — `replace()` invokes the
|
|
11
|
+
* render thunk synchronously; if it returned nothing (a DialogX bridge
|
|
12
|
+
* already opened the host's own dialog), the caller's onClose is parked
|
|
13
|
+
* and invoked when that nested dialog is dismissed without a result.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createSignal } from "solid-js"
|
|
17
|
+
import { registerCommands } from "./commands.js"
|
|
18
|
+
import type { ClientApi } from "./core.js"
|
|
19
|
+
import type { ShareDialogSelectOption, ShareHostApi, ShareHostKeymapLayer } from "./tui-host.js"
|
|
20
|
+
import type { V2KeymapCommand, V2KeymapLayer, V2TuiContext, V2TuiSetup } from "./v2-types.js"
|
|
21
|
+
|
|
22
|
+
function pickThemeToken(source: unknown, ...path: Array<string | number>): unknown {
|
|
23
|
+
let current: unknown = source
|
|
24
|
+
for (const key of path) {
|
|
25
|
+
if (!current || typeof current !== "object") return undefined
|
|
26
|
+
current = (current as Record<string, unknown>)[key]
|
|
27
|
+
}
|
|
28
|
+
return current
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function buildV2Theme(context: V2TuiContext) {
|
|
32
|
+
// Read theme/mode live inside the getter so mid-session theme switches
|
|
33
|
+
// reach the flows.
|
|
34
|
+
return {
|
|
35
|
+
get current() {
|
|
36
|
+
const theme = context.theme
|
|
37
|
+
const dark = context.themeMode === "dark"
|
|
38
|
+
const text = pickThemeToken(theme, "text", "default")
|
|
39
|
+
return {
|
|
40
|
+
text,
|
|
41
|
+
textMuted: pickThemeToken(theme, "text", "subdued") ?? text,
|
|
42
|
+
background: pickThemeToken(theme, "background", "default"),
|
|
43
|
+
backgroundPanel: pickThemeToken(theme, "background", "surface", "offset") ?? pickThemeToken(theme, "background", "default"),
|
|
44
|
+
primary: pickThemeToken(theme, "text", "action", "primary", "selected") ?? text,
|
|
45
|
+
secondary: pickThemeToken(theme, "hue", dark ? "interactive" : "neutral", dark ? 300 : 700) ?? text,
|
|
46
|
+
accent: pickThemeToken(theme, "hue", "accent", dark ? 200 : 800) ?? text,
|
|
47
|
+
success: pickThemeToken(theme, "text", "feedback", "success", "default") ?? text,
|
|
48
|
+
warning: pickThemeToken(theme, "text", "feedback", "warning", "default") ?? text,
|
|
49
|
+
error: pickThemeToken(theme, "text", "feedback", "error", "default") ?? text,
|
|
50
|
+
info: pickThemeToken(theme, "text", "feedback", "info", "default") ?? text,
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function convertKeymapLayer(layer: ShareHostKeymapLayer): V2KeymapLayer {
|
|
57
|
+
const bindingsByName = new Map<string, string[]>()
|
|
58
|
+
for (const binding of layer.bindings ?? []) {
|
|
59
|
+
if (!binding?.cmd) continue
|
|
60
|
+
const keys = bindingsByName.get(binding.cmd) ?? []
|
|
61
|
+
keys.push(binding.key)
|
|
62
|
+
bindingsByName.set(binding.cmd, keys)
|
|
63
|
+
}
|
|
64
|
+
const commands: V2KeymapCommand[] = (layer.commands ?? []).map((command) => ({
|
|
65
|
+
id: command.name,
|
|
66
|
+
title: command.title ?? command.name,
|
|
67
|
+
description: command.desc,
|
|
68
|
+
group: command.group ?? command.category,
|
|
69
|
+
palette: true as const,
|
|
70
|
+
...(command.slashName ? { slash: { name: command.slashName, ...(command.slashAliases?.length ? { aliases: command.slashAliases } : {}) } } : {}),
|
|
71
|
+
...(command.suggested !== undefined ? { suggested: command.suggested } : {}),
|
|
72
|
+
...(command.enabled !== undefined ? { enabled: command.enabled } : {}),
|
|
73
|
+
...(bindingsByName.get(command.name)?.length ? { bind: bindingsByName.get(command.name)!.join(",") } : {}),
|
|
74
|
+
run: (_input?: string, event?: { preventDefault?: () => void; stopPropagation?: () => void }) =>
|
|
75
|
+
command.run({
|
|
76
|
+
event: event
|
|
77
|
+
? {
|
|
78
|
+
preventDefault: () => event.preventDefault?.(),
|
|
79
|
+
stopPropagation: () => event.stopPropagation?.(),
|
|
80
|
+
}
|
|
81
|
+
: undefined,
|
|
82
|
+
}),
|
|
83
|
+
}))
|
|
84
|
+
return { mode: layer.mode ?? "global", priority: layer.priority, commands }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Builds the v1-shaped ShareHostApi facade over a v2 TUI plugin context. */
|
|
88
|
+
export function buildV2HostApi(context: V2TuiContext): ShareHostApi {
|
|
89
|
+
const disposeFns: Array<() => void> = []
|
|
90
|
+
|
|
91
|
+
// --- kv: synchronous read-your-writes mirror over the persistent store ---
|
|
92
|
+
const [kvStore, kvMutate] = context.storage.store("kv", { initial: {} as Record<string, unknown> })
|
|
93
|
+
const kvMirror: Record<string, unknown> = {}
|
|
94
|
+
for (const [key, value] of Object.entries(kvStore as Record<string, unknown>)) kvMirror[key] = value
|
|
95
|
+
const kv = {
|
|
96
|
+
get<Value = unknown>(key: string, fallback?: Value): Value {
|
|
97
|
+
const value = key in kvMirror ? kvMirror[key] : (kvStore as Record<string, unknown>)[key]
|
|
98
|
+
return (value === undefined ? fallback : value) as Value
|
|
99
|
+
},
|
|
100
|
+
set(key: string, value: unknown) {
|
|
101
|
+
kvMirror[key] = value
|
|
102
|
+
void kvMutate((draft) => {
|
|
103
|
+
draft[key] = value
|
|
104
|
+
}).catch(() => undefined)
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// --- dialog bridging (see module doc comment) ---
|
|
109
|
+
const dialog = context.ui.dialog
|
|
110
|
+
let nestedOnClose: (() => void) | undefined
|
|
111
|
+
const settleNested = (dismissed: boolean) => {
|
|
112
|
+
const onClose = nestedOnClose
|
|
113
|
+
nestedOnClose = undefined
|
|
114
|
+
if (dismissed) onClose?.()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
hostVersion: 2,
|
|
119
|
+
app: { version: context.app?.version },
|
|
120
|
+
client: context.client as unknown as ClientApi,
|
|
121
|
+
kv,
|
|
122
|
+
lifecycle: {
|
|
123
|
+
onDispose(fn: () => void) {
|
|
124
|
+
disposeFns.push(fn)
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
theme: buildV2Theme(context),
|
|
128
|
+
ui: {
|
|
129
|
+
toast: (input) => {
|
|
130
|
+
try {
|
|
131
|
+
context.ui.toast.show({ title: input.title, message: input.message, variant: input.variant, duration: input.duration })
|
|
132
|
+
} catch {
|
|
133
|
+
/* toasts must never crash the flows */
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
dialog: {
|
|
137
|
+
replace(renderer: unknown, onClose?: () => void) {
|
|
138
|
+
nestedOnClose = undefined
|
|
139
|
+
let content: unknown
|
|
140
|
+
try {
|
|
141
|
+
content = typeof renderer === "function" ? (renderer as () => unknown)() : renderer
|
|
142
|
+
} catch {
|
|
143
|
+
content = undefined
|
|
144
|
+
}
|
|
145
|
+
if (content === undefined || content === null) {
|
|
146
|
+
nestedOnClose = onClose
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
dialog.show(() => content, onClose)
|
|
150
|
+
},
|
|
151
|
+
clear() {
|
|
152
|
+
nestedOnClose = undefined
|
|
153
|
+
dialog.clear()
|
|
154
|
+
},
|
|
155
|
+
setSize(size: string) {
|
|
156
|
+
try {
|
|
157
|
+
dialog.set({ size })
|
|
158
|
+
} catch {
|
|
159
|
+
/* size hints are best-effort */
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
// Promise menus (v2 host dialogs are host-native and fully keyed).
|
|
164
|
+
async showMenu<Value>(props: { title: string; options: ShareDialogSelectOption<Value>[]; current?: Value; hint?: string }): Promise<Value | undefined> {
|
|
165
|
+
const value = await dialog.select({
|
|
166
|
+
title: props.title,
|
|
167
|
+
placeholder: props.hint,
|
|
168
|
+
current: props.current,
|
|
169
|
+
options: props.options.map((option) => ({
|
|
170
|
+
title: option.title,
|
|
171
|
+
value: option.value,
|
|
172
|
+
description: option.description,
|
|
173
|
+
category: option.category,
|
|
174
|
+
disabled: option.disabled,
|
|
175
|
+
})),
|
|
176
|
+
})
|
|
177
|
+
return value as Value | undefined
|
|
178
|
+
},
|
|
179
|
+
async showConfirm(props: { title: string; message: string; confirmLabel?: string }) {
|
|
180
|
+
return (await dialog.confirm({ title: props.title, message: props.message, label: { confirm: props.confirmLabel } })) === true
|
|
181
|
+
},
|
|
182
|
+
async showAlert(props: { title: string; message: string }) {
|
|
183
|
+
await dialog.alert({ title: props.title, message: props.message })
|
|
184
|
+
},
|
|
185
|
+
async showPrompt(props: { title: string; placeholder?: string; value?: string }) {
|
|
186
|
+
return await dialog.prompt({ title: props.title, placeholder: props.placeholder, value: props.value })
|
|
187
|
+
},
|
|
188
|
+
DialogSelect(props) {
|
|
189
|
+
void dialog
|
|
190
|
+
.select({
|
|
191
|
+
title: props.title,
|
|
192
|
+
placeholder: props.placeholder,
|
|
193
|
+
current: props.current,
|
|
194
|
+
options: props.options.map((option) => ({
|
|
195
|
+
title: option.title,
|
|
196
|
+
value: option.value,
|
|
197
|
+
description: option.description,
|
|
198
|
+
category: option.category,
|
|
199
|
+
disabled: option.disabled,
|
|
200
|
+
})),
|
|
201
|
+
})
|
|
202
|
+
.then((value) => {
|
|
203
|
+
if (value === undefined) {
|
|
204
|
+
settleNested(true)
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
settleNested(false)
|
|
208
|
+
const option = props.options.find((item) => item.value === value)
|
|
209
|
+
if (option) props.onSelect(option)
|
|
210
|
+
})
|
|
211
|
+
.catch(() => settleNested(true))
|
|
212
|
+
},
|
|
213
|
+
DialogPrompt(props) {
|
|
214
|
+
void dialog
|
|
215
|
+
.prompt({ title: props.title, placeholder: props.placeholder, value: props.value })
|
|
216
|
+
.then((value) => {
|
|
217
|
+
settleNested(value === undefined)
|
|
218
|
+
if (value === undefined) props.onCancel?.()
|
|
219
|
+
else props.onConfirm(value)
|
|
220
|
+
})
|
|
221
|
+
.catch(() => {
|
|
222
|
+
settleNested(true)
|
|
223
|
+
props.onCancel?.()
|
|
224
|
+
})
|
|
225
|
+
},
|
|
226
|
+
DialogConfirm(props) {
|
|
227
|
+
void dialog
|
|
228
|
+
.confirm({ title: props.title, message: props.message, label: { confirm: props.confirmLabel } })
|
|
229
|
+
.then((result) => {
|
|
230
|
+
settleNested(result !== true)
|
|
231
|
+
if (result === true) props.onConfirm()
|
|
232
|
+
else props.onCancel?.()
|
|
233
|
+
})
|
|
234
|
+
.catch(() => {
|
|
235
|
+
settleNested(true)
|
|
236
|
+
props.onCancel?.()
|
|
237
|
+
})
|
|
238
|
+
},
|
|
239
|
+
DialogAlert(props) {
|
|
240
|
+
void dialog
|
|
241
|
+
.alert({ title: props.title, message: props.message })
|
|
242
|
+
.then(() => {
|
|
243
|
+
settleNested(false)
|
|
244
|
+
props.onConfirm?.()
|
|
245
|
+
})
|
|
246
|
+
.catch(() => {
|
|
247
|
+
settleNested(true)
|
|
248
|
+
props.onConfirm?.()
|
|
249
|
+
})
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
keymap: {
|
|
253
|
+
registerLayer(layer: ShareHostKeymapLayer) {
|
|
254
|
+
// v2 layers are reactive: the input function re-evaluates when the
|
|
255
|
+
// signal flips, so "unregistering" disables the layer.
|
|
256
|
+
const [active, setActive] = createSignal(true)
|
|
257
|
+
try {
|
|
258
|
+
context.keymap.layer(() =>
|
|
259
|
+
active()
|
|
260
|
+
? convertKeymapLayer(layer)
|
|
261
|
+
: { mode: "global", enabled: false, commands: [], bindings: [] },
|
|
262
|
+
)
|
|
263
|
+
} catch {
|
|
264
|
+
return () => undefined
|
|
265
|
+
}
|
|
266
|
+
return () => {
|
|
267
|
+
setActive(false)
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
sessionInfo: () => undefined,
|
|
272
|
+
currentSessionID: undefined,
|
|
273
|
+
clipboard: {
|
|
274
|
+
// same belt-and-braces as the v1 facade: navigator may resolve as a
|
|
275
|
+
// silent no-op in the TUI runtime; OSC52 is the reliable path
|
|
276
|
+
async write(text) {
|
|
277
|
+
let ok = false
|
|
278
|
+
try {
|
|
279
|
+
const clip = (navigator as unknown as { clipboard?: { writeText?: (t: string) => Promise<void> } }).clipboard
|
|
280
|
+
if (typeof clip?.writeText === "function") {
|
|
281
|
+
await clip.writeText(text).then(
|
|
282
|
+
() => {
|
|
283
|
+
ok = true
|
|
284
|
+
},
|
|
285
|
+
() => {},
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
} catch {}
|
|
289
|
+
try {
|
|
290
|
+
process.stdout.write(`\x1b]52;c;${Buffer.from(text, "utf8").toString("base64")}\x07`)
|
|
291
|
+
ok = true
|
|
292
|
+
} catch {}
|
|
293
|
+
return ok
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* v2 TUI plugin setup: registers the share commands (one reactive keymap
|
|
301
|
+
* layer). Session-context wiring (currentSessionID) finalizes in phase 4
|
|
302
|
+
* once the beta's session/route surface is verified.
|
|
303
|
+
*/
|
|
304
|
+
export function createV2TuiSetup(): V2TuiSetup {
|
|
305
|
+
return async (context: V2TuiContext) => {
|
|
306
|
+
const host = buildV2HostApi(context)
|
|
307
|
+
const sessionID = () => host.currentSessionID?.() ?? undefined
|
|
308
|
+
const unregister = registerCommands(host, sessionID)
|
|
309
|
+
return () => {
|
|
310
|
+
try {
|
|
311
|
+
unregister()
|
|
312
|
+
} catch {}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
package/src/v2-types.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal structural types for the OpenCode v2 TUI plugin context subset
|
|
3
|
+
* used by this plugin. Hand-written on purpose (same policy as the server
|
|
4
|
+
* side and the family plugins): the v2 SDK is still beta and a v2 plugin
|
|
5
|
+
* module must not import the plugin SDK at runtime anyway. Keep in sync
|
|
6
|
+
* with the beta repo (packages/plugin/src/tui) when the API settles.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type V2TuiKeyEvent = {
|
|
10
|
+
preventDefault?(): void
|
|
11
|
+
stopPropagation?(): void
|
|
12
|
+
[key: string]: unknown
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type V2KeymapCommand = {
|
|
16
|
+
id?: string
|
|
17
|
+
title?: string
|
|
18
|
+
description?: string
|
|
19
|
+
group?: string
|
|
20
|
+
enabled?: boolean | (() => boolean)
|
|
21
|
+
bind?: false | string
|
|
22
|
+
palette?: true
|
|
23
|
+
slash?: { name: string; aliases?: string[]; arguments?: true }
|
|
24
|
+
suggested?: boolean | (() => boolean)
|
|
25
|
+
run: (input?: string, event?: V2TuiKeyEvent) => void | false | Promise<void>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export type V2KeymapLayer = {
|
|
29
|
+
mode?: string
|
|
30
|
+
enabled?: boolean | (() => boolean)
|
|
31
|
+
priority?: number
|
|
32
|
+
commands?: readonly V2KeymapCommand[]
|
|
33
|
+
bindings?: readonly string[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type V2DialogSelectOption<Value> = {
|
|
37
|
+
title: string
|
|
38
|
+
value: Value
|
|
39
|
+
description?: string
|
|
40
|
+
category?: string
|
|
41
|
+
disabled?: boolean
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type V2LocationRef = { directory: string; workspaceID?: string }
|
|
45
|
+
|
|
46
|
+
export type V2TuiContext = {
|
|
47
|
+
options: Readonly<Record<string, unknown>>
|
|
48
|
+
location?: unknown
|
|
49
|
+
app: { version?: string; channel?: string }
|
|
50
|
+
renderer: { root?: unknown }
|
|
51
|
+
client: any
|
|
52
|
+
keymap: {
|
|
53
|
+
layer(input: () => V2KeymapLayer): void
|
|
54
|
+
mode: { current(): string; push(mode: string): () => void }
|
|
55
|
+
}
|
|
56
|
+
storage: {
|
|
57
|
+
store<Value extends object>(
|
|
58
|
+
key: string,
|
|
59
|
+
options: { initial: Value },
|
|
60
|
+
): readonly [Value, (mutation: (draft: Value) => void) => Promise<void>]
|
|
61
|
+
}
|
|
62
|
+
theme: V2ResolvedTheme
|
|
63
|
+
themeMode: "dark" | "light"
|
|
64
|
+
ui: {
|
|
65
|
+
dialog: {
|
|
66
|
+
show(render: () => unknown, onClose?: () => void): void
|
|
67
|
+
set(options: { size?: string; centered?: boolean }): void
|
|
68
|
+
clear(): void
|
|
69
|
+
alert(options: { title: string; message: string }): Promise<void>
|
|
70
|
+
confirm(options: {
|
|
71
|
+
title: string
|
|
72
|
+
message: string
|
|
73
|
+
label?: { confirm?: string; cancel?: string }
|
|
74
|
+
}): Promise<boolean | undefined>
|
|
75
|
+
prompt(options: { title: string; description?: string; placeholder?: string; value?: string }): Promise<string | undefined>
|
|
76
|
+
select<Value>(options: {
|
|
77
|
+
title: string
|
|
78
|
+
placeholder?: string
|
|
79
|
+
current?: Value
|
|
80
|
+
options: readonly V2DialogSelectOption<Value>[]
|
|
81
|
+
}): Promise<Value | undefined>
|
|
82
|
+
}
|
|
83
|
+
toast: { show(options: { title?: string; message: string; variant?: string; duration?: number }): void }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export type V2ResolvedTheme = {
|
|
88
|
+
text: {
|
|
89
|
+
default: unknown
|
|
90
|
+
subdued: unknown
|
|
91
|
+
feedback: Record<string, { default: unknown }>
|
|
92
|
+
action: Record<string, Record<string, unknown>>
|
|
93
|
+
}
|
|
94
|
+
background: {
|
|
95
|
+
default: unknown
|
|
96
|
+
surface: { offset: unknown; overlay: unknown }
|
|
97
|
+
}
|
|
98
|
+
hue: Record<string, Record<string | number, unknown>>
|
|
99
|
+
categorical?: ReadonlyArray<unknown>
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export type V2TuiSetup = (context: V2TuiContext) => Promise<(() => void) | void> | (() => void) | void
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2023",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2023", "DOM"],
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUncheckedIndexedAccess": false,
|
|
10
|
+
"noEmitOnError": true,
|
|
11
|
+
"declaration": true,
|
|
12
|
+
"jsx": "react-jsx",
|
|
13
|
+
"jsxImportSource": "@opentui/solid",
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src"]
|
|
18
|
+
}
|