@saeeol/plugin 7.3.3 → 7.3.5

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/src/tui.ts ADDED
@@ -0,0 +1,501 @@
1
+ import type {
2
+ AgentPart,
3
+ SaeeolClient,
4
+ Event,
5
+ FilePart,
6
+ LspStatus,
7
+ McpStatus,
8
+ Todo,
9
+ Message,
10
+ Part,
11
+ Provider,
12
+ PermissionRequest,
13
+ QuestionRequest,
14
+ SessionStatus,
15
+ TextPart,
16
+ Config as SdkConfig,
17
+ } from "@saeeol/sdk/v2"
18
+ import type { CliRenderer, ParsedKey, RGBA, SlotMode } from "@opentui/core"
19
+ import type { JSX, SolidPlugin } from "@opentui/solid"
20
+ import type { Config as PluginConfig, PluginOptions } from "./index.js"
21
+
22
+ export type { CliRenderer, SlotMode } from "@opentui/core"
23
+
24
+ export type TuiRouteCurrent =
25
+ | {
26
+ name: "home"
27
+ }
28
+ | {
29
+ name: "session"
30
+ params: {
31
+ sessionID: string
32
+ prompt?: unknown
33
+ }
34
+ }
35
+ | {
36
+ name: string
37
+ params?: Record<string, unknown>
38
+ }
39
+
40
+ export type TuiRouteDefinition = {
41
+ name: string
42
+ render: (input: { params?: Record<string, unknown> }) => JSX.Element
43
+ }
44
+
45
+ export type TuiCommand = {
46
+ title: string
47
+ value: string
48
+ description?: string
49
+ category?: string
50
+ keybind?: string
51
+ suggested?: boolean
52
+ hidden?: boolean
53
+ enabled?: boolean
54
+ slash?: {
55
+ name: string
56
+ aliases?: string[]
57
+ }
58
+ onSelect?: () => void
59
+ }
60
+
61
+ export type TuiKeybind = {
62
+ name: string
63
+ ctrl: boolean
64
+ meta: boolean
65
+ shift: boolean
66
+ super?: boolean
67
+ leader: boolean
68
+ }
69
+
70
+ export type TuiKeybindMap = Record<string, string>
71
+
72
+ export type TuiKeybindSet = {
73
+ readonly all: TuiKeybindMap
74
+ get: (name: string) => string
75
+ match: (name: string, evt: ParsedKey) => boolean
76
+ print: (name: string) => string
77
+ }
78
+
79
+ export type TuiDialogProps = {
80
+ size?: "medium" | "large" | "xlarge"
81
+ onClose: () => void
82
+ children?: JSX.Element
83
+ }
84
+
85
+ export type TuiDialogStack = {
86
+ replace: (render: () => JSX.Element, onClose?: () => void) => void
87
+ clear: () => void
88
+ setSize: (size: "medium" | "large" | "xlarge") => void
89
+ readonly size: "medium" | "large" | "xlarge"
90
+ readonly depth: number
91
+ readonly open: boolean
92
+ }
93
+
94
+ export type TuiDialogAlertProps = {
95
+ title: string
96
+ message: string
97
+ onConfirm?: () => void
98
+ }
99
+
100
+ export type TuiDialogConfirmProps = {
101
+ title: string
102
+ message: string
103
+ onConfirm?: () => void
104
+ onCancel?: () => void
105
+ }
106
+
107
+ export type TuiDialogPromptProps = {
108
+ title: string
109
+ description?: () => JSX.Element
110
+ placeholder?: string
111
+ value?: string
112
+ busy?: boolean
113
+ busyText?: string
114
+ onConfirm?: (value: string) => void
115
+ onCancel?: () => void
116
+ }
117
+
118
+ export type TuiDialogSelectOption<Value = unknown> = {
119
+ title: string
120
+ value: Value
121
+ description?: string
122
+ footer?: JSX.Element | string
123
+ category?: string
124
+ disabled?: boolean
125
+ onSelect?: () => void
126
+ }
127
+
128
+ export type TuiDialogSelectProps<Value = unknown> = {
129
+ title: string
130
+ placeholder?: string
131
+ options: TuiDialogSelectOption<Value>[]
132
+ flat?: boolean
133
+ onMove?: (option: TuiDialogSelectOption<Value>) => void
134
+ onFilter?: (query: string) => void
135
+ onSelect?: (option: TuiDialogSelectOption<Value>) => void
136
+ skipFilter?: boolean
137
+ current?: Value
138
+ }
139
+
140
+ export type TuiPromptInfo = {
141
+ input: string
142
+ mode?: "normal" | "shell"
143
+ parts: (
144
+ | Omit<FilePart, "id" | "messageID" | "sessionID">
145
+ | Omit<AgentPart, "id" | "messageID" | "sessionID">
146
+ | (Omit<TextPart, "id" | "messageID" | "sessionID"> & {
147
+ source?: {
148
+ text: {
149
+ start: number
150
+ end: number
151
+ value: string
152
+ }
153
+ }
154
+ })
155
+ )[]
156
+ }
157
+
158
+ export type TuiPromptRef = {
159
+ focused: boolean
160
+ current: TuiPromptInfo
161
+ set(prompt: TuiPromptInfo): void
162
+ reset(): void
163
+ blur(): void
164
+ focus(): void
165
+ submit(): void
166
+ }
167
+
168
+ export type TuiPromptProps = {
169
+ sessionID?: string
170
+ workspaceID?: string
171
+ visible?: boolean
172
+ disabled?: boolean
173
+ onSubmit?: () => void
174
+ ref?: (ref: TuiPromptRef | undefined) => void
175
+ hint?: JSX.Element
176
+ right?: JSX.Element
177
+ showPlaceholder?: boolean
178
+ placeholders?: {
179
+ normal?: string[]
180
+ shell?: string[]
181
+ }
182
+ }
183
+
184
+ export type TuiToast = {
185
+ variant?: "info" | "success" | "warning" | "error"
186
+ title?: string
187
+ message: string
188
+ duration?: number
189
+ }
190
+
191
+ export type TuiThemeCurrent = {
192
+ readonly primary: RGBA
193
+ readonly secondary: RGBA
194
+ readonly accent: RGBA
195
+ readonly error: RGBA
196
+ readonly warning: RGBA
197
+ readonly success: RGBA
198
+ readonly info: RGBA
199
+ readonly text: RGBA
200
+ readonly textMuted: RGBA
201
+ readonly selectedListItemText: RGBA
202
+ readonly background: RGBA
203
+ readonly backgroundPanel: RGBA
204
+ readonly backgroundElement: RGBA
205
+ readonly backgroundMenu: RGBA
206
+ readonly border: RGBA
207
+ readonly borderActive: RGBA
208
+ readonly borderSubtle: RGBA
209
+ readonly diffAdded: RGBA
210
+ readonly diffRemoved: RGBA
211
+ readonly diffContext: RGBA
212
+ readonly diffHunkHeader: RGBA
213
+ readonly diffHighlightAdded: RGBA
214
+ readonly diffHighlightRemoved: RGBA
215
+ readonly diffAddedBg: RGBA
216
+ readonly diffRemovedBg: RGBA
217
+ readonly diffContextBg: RGBA
218
+ readonly diffLineNumber: RGBA
219
+ readonly diffAddedLineNumberBg: RGBA
220
+ readonly diffRemovedLineNumberBg: RGBA
221
+ readonly markdownText: RGBA
222
+ readonly markdownHeading: RGBA
223
+ readonly markdownLink: RGBA
224
+ readonly markdownLinkText: RGBA
225
+ readonly markdownCode: RGBA
226
+ readonly markdownBlockQuote: RGBA
227
+ readonly markdownEmph: RGBA
228
+ readonly markdownStrong: RGBA
229
+ readonly markdownHorizontalRule: RGBA
230
+ readonly markdownListItem: RGBA
231
+ readonly markdownListEnumeration: RGBA
232
+ readonly markdownImage: RGBA
233
+ readonly markdownImageText: RGBA
234
+ readonly markdownCodeBlock: RGBA
235
+ readonly syntaxComment: RGBA
236
+ readonly syntaxKeyword: RGBA
237
+ readonly syntaxFunction: RGBA
238
+ readonly syntaxVariable: RGBA
239
+ readonly syntaxString: RGBA
240
+ readonly syntaxNumber: RGBA
241
+ readonly syntaxType: RGBA
242
+ readonly syntaxOperator: RGBA
243
+ readonly syntaxPunctuation: RGBA
244
+ readonly thinkingOpacity: number
245
+ }
246
+
247
+ export type TuiTheme = {
248
+ readonly current: TuiThemeCurrent
249
+ readonly selected: string
250
+ has: (name: string) => boolean
251
+ set: (name: string) => boolean
252
+ install: (jsonPath: string) => Promise<void>
253
+ mode: () => "dark" | "light"
254
+ readonly ready: boolean
255
+ }
256
+
257
+ export type TuiKV = {
258
+ get: <Value = unknown>(key: string, fallback?: Value) => Value
259
+ set: (key: string, value: unknown) => void
260
+ readonly ready: boolean
261
+ }
262
+
263
+ export type TuiState = {
264
+ readonly ready: boolean
265
+ readonly config: SdkConfig
266
+ readonly provider: ReadonlyArray<Provider>
267
+ readonly path: {
268
+ state: string
269
+ config: string
270
+ worktree: string
271
+ directory: string
272
+ }
273
+ readonly vcs: { branch?: string } | undefined
274
+ session: {
275
+ count: () => number
276
+ diff: (sessionID: string) => ReadonlyArray<TuiSidebarFileItem>
277
+ todo: (sessionID: string) => ReadonlyArray<TuiSidebarTodoItem>
278
+ messages: (sessionID: string) => ReadonlyArray<Message>
279
+ status: (sessionID: string) => SessionStatus | undefined
280
+ permission: (sessionID: string) => ReadonlyArray<PermissionRequest>
281
+ question: (sessionID: string) => ReadonlyArray<QuestionRequest>
282
+ }
283
+ part: (messageID: string) => ReadonlyArray<Part>
284
+ lsp: () => ReadonlyArray<TuiSidebarLspItem>
285
+ mcp: () => ReadonlyArray<TuiSidebarMcpItem>
286
+ }
287
+
288
+ type TuiConfigView = Pick<PluginConfig, "$schema" | "theme" | "keybinds" | "plugin"> &
289
+ NonNullable<PluginConfig["tui"]> & {
290
+ plugin_enabled?: Record<string, boolean>
291
+ }
292
+
293
+ export type TuiApp = {
294
+ readonly version: string
295
+ }
296
+
297
+ type Frozen<Value> = Value extends (...args: never[]) => unknown
298
+ ? Value
299
+ : Value extends ReadonlyArray<infer Item>
300
+ ? ReadonlyArray<Frozen<Item>>
301
+ : Value extends object
302
+ ? { readonly [Key in keyof Value]: Frozen<Value[Key]> }
303
+ : Value
304
+
305
+ export type TuiSidebarMcpItem = {
306
+ name: string
307
+ status: McpStatus["status"]
308
+ error?: string
309
+ }
310
+
311
+ export type TuiSidebarLspItem = Pick<LspStatus, "id" | "root" | "status">
312
+
313
+ export type TuiSidebarTodoItem = Pick<Todo, "content" | "status">
314
+
315
+ export type TuiSidebarFileItem = {
316
+ file: string
317
+ additions: number
318
+ deletions: number
319
+ }
320
+
321
+ export type TuiHostSlotMap = {
322
+ app: {}
323
+ home_logo: {}
324
+ home_prompt: {
325
+ workspace_id?: string
326
+ ref?: (ref: TuiPromptRef | undefined) => void
327
+ }
328
+ home_prompt_right: {
329
+ workspace_id?: string
330
+ }
331
+ session_prompt: {
332
+ session_id: string
333
+ visible?: boolean
334
+ disabled?: boolean
335
+ on_submit?: () => void
336
+ ref?: (ref: TuiPromptRef | undefined) => void
337
+ }
338
+ session_prompt_right: {
339
+ session_id: string
340
+ }
341
+ home_bottom: {}
342
+ home_footer: {}
343
+ sidebar_title: {
344
+ session_id: string
345
+ title: string
346
+ share_url?: string
347
+ }
348
+ sidebar_content: {
349
+ session_id: string
350
+ }
351
+ sidebar_footer: {
352
+ session_id: string
353
+ }
354
+ }
355
+
356
+ export type TuiSlotMap<Slots extends Record<string, object> = {}> = TuiHostSlotMap & Slots
357
+
358
+ type TuiSlotShape<Name extends string, Slots extends Record<string, object>> = Name extends keyof TuiHostSlotMap
359
+ ? TuiHostSlotMap[Name]
360
+ : Name extends keyof Slots
361
+ ? Slots[Name]
362
+ : Record<string, unknown>
363
+
364
+ export type TuiSlotProps<Name extends string = string, Slots extends Record<string, object> = {}> = {
365
+ name: Name
366
+ mode?: SlotMode
367
+ children?: JSX.Element
368
+ } & TuiSlotShape<Name, Slots>
369
+
370
+ export type TuiSlotContext = {
371
+ theme: TuiTheme
372
+ }
373
+
374
+ type SlotCore<Slots extends Record<string, object> = {}> = SolidPlugin<TuiSlotMap<Slots>, TuiSlotContext>
375
+
376
+ export type TuiSlotPlugin<Slots extends Record<string, object> = {}> = Omit<SlotCore<Slots>, "id"> & {
377
+ id?: never
378
+ }
379
+
380
+ export type TuiSlots = {
381
+ register: {
382
+ (plugin: TuiSlotPlugin): string
383
+ <Slots extends Record<string, object>>(plugin: TuiSlotPlugin<Slots>): string
384
+ }
385
+ }
386
+
387
+ export type TuiEventBus = {
388
+ on: <Type extends Event["type"]>(type: Type, handler: (event: Extract<Event, { type: Type }>) => void) => () => void
389
+ }
390
+
391
+ export type TuiDispose = () => void | Promise<void>
392
+
393
+ export type TuiLifecycle = {
394
+ readonly signal: AbortSignal
395
+ onDispose: (fn: TuiDispose) => () => void
396
+ }
397
+
398
+ export type TuiPluginState = "first" | "updated" | "same"
399
+
400
+ export type TuiPluginEntry = {
401
+ id: string
402
+ source: "file" | "npm" | "internal"
403
+ spec: string
404
+ target: string
405
+ requested?: string
406
+ version?: string
407
+ modified?: number
408
+ first_time: number
409
+ last_time: number
410
+ time_changed: number
411
+ load_count: number
412
+ fingerprint: string
413
+ }
414
+
415
+ export type TuiPluginMeta = TuiPluginEntry & {
416
+ state: TuiPluginState
417
+ }
418
+
419
+ export type TuiPluginStatus = {
420
+ id: string
421
+ source: TuiPluginEntry["source"]
422
+ spec: string
423
+ target: string
424
+ enabled: boolean
425
+ active: boolean
426
+ }
427
+
428
+ export type TuiPluginInstallOptions = {
429
+ global?: boolean
430
+ }
431
+
432
+ export type TuiPluginInstallResult =
433
+ | {
434
+ ok: true
435
+ dir: string
436
+ tui: boolean
437
+ }
438
+ | {
439
+ ok: false
440
+ message: string
441
+ missing?: boolean
442
+ }
443
+
444
+ export type TuiWorkspace = {
445
+ current: () => string | undefined
446
+ set: (workspaceID?: string) => void
447
+ }
448
+
449
+ export type TuiPluginApi = {
450
+ app: TuiApp
451
+ command: {
452
+ register: (cb: () => TuiCommand[]) => () => void
453
+ trigger: (value: string) => void
454
+ show: () => void
455
+ }
456
+ route: {
457
+ register: (routes: TuiRouteDefinition[]) => () => void
458
+ navigate: (name: string, params?: Record<string, unknown>) => void
459
+ readonly current: TuiRouteCurrent
460
+ }
461
+ ui: {
462
+ Dialog: (props: TuiDialogProps) => JSX.Element
463
+ DialogAlert: (props: TuiDialogAlertProps) => JSX.Element
464
+ DialogConfirm: (props: TuiDialogConfirmProps) => JSX.Element
465
+ DialogPrompt: (props: TuiDialogPromptProps) => JSX.Element
466
+ DialogSelect: <Value = unknown>(props: TuiDialogSelectProps<Value>) => JSX.Element
467
+ Slot: <Name extends string>(props: TuiSlotProps<Name>) => JSX.Element | null
468
+ Prompt: (props: TuiPromptProps) => JSX.Element
469
+ toast: (input: TuiToast) => void
470
+ dialog: TuiDialogStack
471
+ }
472
+ keybind: {
473
+ match: (key: string, evt: ParsedKey) => boolean
474
+ print: (key: string) => string
475
+ create: (defaults: TuiKeybindMap, overrides?: Record<string, unknown>) => TuiKeybindSet
476
+ }
477
+ readonly tuiConfig: Frozen<TuiConfigView>
478
+ kv: TuiKV
479
+ state: TuiState
480
+ theme: TuiTheme
481
+ client: SaeeolClient
482
+ event: TuiEventBus
483
+ renderer: CliRenderer
484
+ slots: TuiSlots
485
+ plugins: {
486
+ list: () => ReadonlyArray<TuiPluginStatus>
487
+ activate: (id: string) => Promise<boolean>
488
+ deactivate: (id: string) => Promise<boolean>
489
+ add: (spec: string) => Promise<boolean>
490
+ install: (spec: string, options?: TuiPluginInstallOptions) => Promise<TuiPluginInstallResult>
491
+ }
492
+ lifecycle: TuiLifecycle
493
+ }
494
+
495
+ export type TuiPlugin = (api: TuiPluginApi, options: PluginOptions | undefined, meta: TuiPluginMeta) => Promise<void>
496
+
497
+ export type TuiPluginModule = {
498
+ id?: string
499
+ tui: TuiPlugin
500
+ server?: never
501
+ }
@@ -1,3 +0,0 @@
1
- import type { Plugin } from "@saeeol/plugin";
2
- export declare const FolderWorkspacePlugin: Plugin;
3
- export default FolderWorkspacePlugin;
@@ -1,30 +0,0 @@
1
- import { mkdir, rm } from "node:fs/promises";
2
- export const FolderWorkspacePlugin = async ({ experimental_workspace }) => {
3
- experimental_workspace.register("folder", {
4
- name: "Folder",
5
- description: "Create a blank folder",
6
- configure(config) {
7
- const rand = "" + Math.random();
8
- return {
9
- ...config,
10
- directory: `/tmp/folder/folder-${rand}`,
11
- };
12
- },
13
- async create(config) {
14
- if (!config.directory)
15
- return;
16
- await mkdir(config.directory, { recursive: true });
17
- },
18
- async remove(config) {
19
- await rm(config.directory, { recursive: true, force: true });
20
- },
21
- target(config) {
22
- return {
23
- type: "local",
24
- directory: config.directory,
25
- };
26
- },
27
- });
28
- return {};
29
- };
30
- export default FolderWorkspacePlugin;
package/dist/example.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { Plugin } from "./index.js";
2
- export declare const ExamplePlugin: Plugin;
package/dist/example.js DELETED
@@ -1,16 +0,0 @@
1
- import { tool } from "./tool.js";
2
- export const ExamplePlugin = async (_ctx) => {
3
- return {
4
- tool: {
5
- mytool: tool({
6
- description: "This is a custom tool",
7
- args: {
8
- foo: tool.schema.string().describe("foo"),
9
- },
10
- async execute(args) {
11
- return `Hello ${args.foo}!`;
12
- },
13
- }),
14
- },
15
- };
16
- };