opencode-subagent-magazine 1.6.0-beta.2 → 1.6.0-beta.4
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/README.md +3 -1
- package/dist/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/core/kv.d.ts +1 -0
- package/dist/core/kv.js +1 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/i18n.d.ts +2 -0
- package/dist/i18n.js +8 -0
- package/dist/index.js +17 -2
- package/dist/panel/SubAgentPanel.d.ts +1 -0
- package/dist/panel/SubAgentPanel.js +54 -37
- package/dist/panel/entry-map.d.ts +6 -0
- package/dist/panel/entry-map.js +25 -0
- package/dist/tui.js +128 -56
- package/dist/v2/commands.js +13 -0
- package/dist/v2/index.js +3 -2
- package/dist/v2.js +124 -56
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/core/color.ts +70 -70
- package/src/core/format.ts +61 -61
- package/src/core/index.ts +6 -6
- package/src/core/kv.ts +37 -36
- package/src/core/state-machine.ts +46 -46
- package/src/core/types.ts +2 -0
- package/src/core/usage.ts +16 -16
- package/src/i18n.ts +8 -0
- package/src/index.tsx +472 -454
- package/src/panel/SubAgentPanel.tsx +59 -37
- package/src/panel/entry-map.ts +39 -0
- package/src/panel/store.ts +8 -8
- package/src/v2/commands.ts +264 -251
- package/src/v2/index.tsx +102 -98
- package/src/v2/theme.ts +14 -14
- package/src/v2/types.ts +165 -165
- package/tui/index.js +11 -11
package/src/v2/index.tsx
CHANGED
|
@@ -1,98 +1,102 @@
|
|
|
1
|
-
/** @jsxImportSource @opentui/solid */
|
|
2
|
-
|
|
3
|
-
import { createSignal } from "solid-js"
|
|
4
|
-
import type { Context, PluginModule } from "./types"
|
|
5
|
-
import { createPanelApi } from "./v2-panel-api"
|
|
6
|
-
import { makeCommands } from "./commands"
|
|
7
|
-
import { mapTheme } from "./theme"
|
|
8
|
-
import { SubAgentPanel } from "../panel/SubAgentPanel"
|
|
9
|
-
import type { PanelApi } from "../panel/panel-api"
|
|
10
|
-
import type { Lang, SortOrder, ScrollMode, SharedSignals } from "../core/types"
|
|
11
|
-
import { SETTING_KEYS } from "../core/kv"
|
|
12
|
-
import { LANG_META, detectLang } from "../i18n"
|
|
13
|
-
|
|
14
|
-
/** 面板根组件:keymap.layer 必须在组件渲染上下文注册(setup 内调用报
|
|
15
|
-
* Keymap.Provider missing),再渲染共享 SubAgentPanel。 */
|
|
16
|
-
function PluginRoot(props: {
|
|
17
|
-
context: Context
|
|
18
|
-
api: PanelApi
|
|
19
|
-
signals: SharedSignals
|
|
20
|
-
sessionID: string
|
|
21
|
-
}) {
|
|
22
|
-
props.context.keymap.layer(() => ({
|
|
23
|
-
mode: "global" as const,
|
|
24
|
-
commands: makeCommands(props.context, props.api, props.signals),
|
|
25
|
-
}))
|
|
26
|
-
return (
|
|
27
|
-
<SubAgentPanel
|
|
28
|
-
api={props.api}
|
|
29
|
-
theme={mapTheme(props.context.theme)}
|
|
30
|
-
lang={props.signals.lang}
|
|
31
|
-
maxEntries={props.signals.maxEntries}
|
|
32
|
-
sortOrder={props.signals.sortOrder}
|
|
33
|
-
scrollMode={props.signals.scrollMode}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
let
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const [
|
|
62
|
-
const [
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
1
|
+
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
|
|
3
|
+
import { createSignal } from "solid-js"
|
|
4
|
+
import type { Context, PluginModule } from "./types"
|
|
5
|
+
import { createPanelApi } from "./v2-panel-api"
|
|
6
|
+
import { makeCommands } from "./commands"
|
|
7
|
+
import { mapTheme } from "./theme"
|
|
8
|
+
import { SubAgentPanel } from "../panel/SubAgentPanel"
|
|
9
|
+
import type { PanelApi } from "../panel/panel-api"
|
|
10
|
+
import type { Lang, SortOrder, ScrollMode, SharedSignals } from "../core/types"
|
|
11
|
+
import { SETTING_KEYS } from "../core/kv"
|
|
12
|
+
import { LANG_META, detectLang } from "../i18n"
|
|
13
|
+
|
|
14
|
+
/** 面板根组件:keymap.layer 必须在组件渲染上下文注册(setup 内调用报
|
|
15
|
+
* Keymap.Provider missing),再渲染共享 SubAgentPanel。 */
|
|
16
|
+
function PluginRoot(props: {
|
|
17
|
+
context: Context
|
|
18
|
+
api: PanelApi
|
|
19
|
+
signals: SharedSignals
|
|
20
|
+
sessionID: string
|
|
21
|
+
}) {
|
|
22
|
+
props.context.keymap.layer(() => ({
|
|
23
|
+
mode: "global" as const,
|
|
24
|
+
commands: makeCommands(props.context, props.api, props.signals),
|
|
25
|
+
}))
|
|
26
|
+
return (
|
|
27
|
+
<SubAgentPanel
|
|
28
|
+
api={props.api}
|
|
29
|
+
theme={mapTheme(props.context.theme)}
|
|
30
|
+
lang={props.signals.lang}
|
|
31
|
+
maxEntries={props.signals.maxEntries}
|
|
32
|
+
sortOrder={props.signals.sortOrder}
|
|
33
|
+
scrollMode={props.signals.scrollMode}
|
|
34
|
+
borderVisible={props.signals.borderVisible}
|
|
35
|
+
sessionId={props.sessionID}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** V2 入口:setup 创建共享信号 + PanelApi + 命令 layer + 侧边栏槽位。
|
|
41
|
+
* 行为对齐 V1 tui()(信号初始值从 KV 恢复;侧边栏渲染共享 SubAgentPanel)。 */
|
|
42
|
+
const mod: PluginModule & { server: () => Promise<Record<string, never>> } = {
|
|
43
|
+
id: "opencode-subagent-magazine",
|
|
44
|
+
setup(context: Context) {
|
|
45
|
+
// settings 惰性 getter(闭包引用信号变量——运行时已赋值)
|
|
46
|
+
let lang!: () => Lang
|
|
47
|
+
let maxEntries!: () => number
|
|
48
|
+
let sortOrder!: () => SortOrder
|
|
49
|
+
let scrollMode!: () => ScrollMode
|
|
50
|
+
const api = createPanelApi(context, {
|
|
51
|
+
lang: () => lang(),
|
|
52
|
+
maxEntries: () => maxEntries(),
|
|
53
|
+
sortOrder: () => sortOrder(),
|
|
54
|
+
scrollMode: () => scrollMode(),
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// 信号初始值从 KV 恢复(对齐 V1 tui())
|
|
58
|
+
const storedLang = String(api.kv.get(SETTING_KEYS.lang, ""))
|
|
59
|
+
const initialLang: Lang =
|
|
60
|
+
LANG_META.some((m) => m.code === storedLang) ? (storedLang as Lang) : detectLang()
|
|
61
|
+
const [langSignal, setLang] = createSignal<Lang>(initialLang)
|
|
62
|
+
const [maxSignal, setMaxEntries] = createSignal<number>(Number(api.kv.get(SETTING_KEYS.maxEntries, "10")) || 10)
|
|
63
|
+
const [orderSignal, setSortOrder] = createSignal<SortOrder>(
|
|
64
|
+
String(api.kv.get(SETTING_KEYS.order, "desc")) === "asc" ? "asc" : "desc",
|
|
65
|
+
)
|
|
66
|
+
const [scrollSignal, setScrollMode] = createSignal<ScrollMode>(
|
|
67
|
+
String(api.kv.get(SETTING_KEYS.scrollMode, "wheel")) === "click" ? "click" : "wheel",
|
|
68
|
+
)
|
|
69
|
+
const [borderSignal, setBorderVisible] = createSignal<boolean>(
|
|
70
|
+
(api.kv.get(SETTING_KEYS.border, false) as boolean) === true,
|
|
71
|
+
)
|
|
72
|
+
lang = langSignal
|
|
73
|
+
maxEntries = maxSignal
|
|
74
|
+
sortOrder = orderSignal
|
|
75
|
+
scrollMode = scrollSignal
|
|
76
|
+
|
|
77
|
+
const signals: SharedSignals = {
|
|
78
|
+
lang, setLang, maxEntries, setMaxEntries, sortOrder, setSortOrder, scrollMode, setScrollMode, borderVisible: borderSignal, setBorderVisible, sessionId: "",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 命令 layer(组件内注册——见 PluginRoot)
|
|
82
|
+
// 侧边栏面板(共享 SubAgentPanel——V1/V2 同一组件)
|
|
83
|
+
context.ui.slot({
|
|
84
|
+
prepend: "sidebar.content",
|
|
85
|
+
render: (props) => {
|
|
86
|
+
signals.sessionId = String(props.sessionID ?? "")
|
|
87
|
+
return (
|
|
88
|
+
<PluginRoot
|
|
89
|
+
context={context}
|
|
90
|
+
api={api}
|
|
91
|
+
signals={signals}
|
|
92
|
+
sessionID={String(props.sessionID ?? "")}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
},
|
|
98
|
+
// V1 server 空实现(兼容标记):v2 加载 setup,V1 检测需要 server 字段识别为插件
|
|
99
|
+
server: async () => ({}),
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default mod
|
package/src/v2/theme.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type { Context } from "./types"
|
|
2
|
-
|
|
3
|
-
/** V2 theme → V1 形状映射(组件按 primary/text/textMuted/… 字段消费)。 */
|
|
4
|
-
export function mapTheme(theme: Context["theme"]): Record<string, unknown> {
|
|
5
|
-
return {
|
|
6
|
-
primary: theme.hue.interactive[300],
|
|
7
|
-
text: theme.text.default,
|
|
8
|
-
textMuted: theme.text.subdued,
|
|
9
|
-
success: theme.text.feedback.success.default,
|
|
10
|
-
warning: theme.text.feedback.warning.default,
|
|
11
|
-
error: theme.text.feedback.error.default,
|
|
12
|
-
border: theme.text.subdued,
|
|
13
|
-
}
|
|
14
|
-
}
|
|
1
|
+
import type { Context } from "./types"
|
|
2
|
+
|
|
3
|
+
/** V2 theme → V1 形状映射(组件按 primary/text/textMuted/… 字段消费)。 */
|
|
4
|
+
export function mapTheme(theme: Context["theme"]): Record<string, unknown> {
|
|
5
|
+
return {
|
|
6
|
+
primary: theme.hue.interactive[300],
|
|
7
|
+
text: theme.text.default,
|
|
8
|
+
textMuted: theme.text.subdued,
|
|
9
|
+
success: theme.text.feedback.success.default,
|
|
10
|
+
warning: theme.text.feedback.warning.default,
|
|
11
|
+
error: theme.text.feedback.error.default,
|
|
12
|
+
border: theme.text.subdued,
|
|
13
|
+
}
|
|
14
|
+
}
|
package/src/v2/types.ts
CHANGED
|
@@ -1,165 +1,165 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* V2 (opencode2) TUI plugin API — 最小本地类型(实验版)。
|
|
3
|
-
* 运行时由 opencode2 提供,此处仅用于本地类型检查;
|
|
4
|
-
* 结构对应 v2 分支 packages/plugin/src/tui/context.ts。
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export interface App {
|
|
8
|
-
readonly version: string
|
|
9
|
-
readonly channel: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface Theme {
|
|
13
|
-
readonly hue: {
|
|
14
|
-
readonly interactive: { readonly 300: string }
|
|
15
|
-
readonly accent: { readonly 500: string }
|
|
16
|
-
}
|
|
17
|
-
readonly text: {
|
|
18
|
-
readonly default: string
|
|
19
|
-
readonly subdued: string
|
|
20
|
-
readonly feedback: {
|
|
21
|
-
readonly success: { readonly default: string }
|
|
22
|
-
readonly error: { readonly default: string }
|
|
23
|
-
readonly warning: { readonly default: string }
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface TokenUsage {
|
|
29
|
-
input?: number
|
|
30
|
-
output?: number
|
|
31
|
-
reasoning?: number
|
|
32
|
-
cache?: { read?: number; write?: number }
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface MessageInfo {
|
|
36
|
-
readonly id: string
|
|
37
|
-
readonly type: string
|
|
38
|
-
readonly agent?: string
|
|
39
|
-
readonly model?: string
|
|
40
|
-
readonly time: { readonly created: number; readonly completed?: number }
|
|
41
|
-
readonly cost?: unknown
|
|
42
|
-
readonly tokens?: TokenUsage
|
|
43
|
-
readonly content?: unknown[]
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface SessionInfo {
|
|
47
|
-
readonly id: string
|
|
48
|
-
readonly title?: string
|
|
49
|
-
readonly time?: { readonly created: number; readonly updated: number }
|
|
50
|
-
readonly model?: string
|
|
51
|
-
readonly agent?: string
|
|
52
|
-
readonly parentID?: string
|
|
53
|
-
readonly cost?: number
|
|
54
|
-
readonly tokens?: TokenUsage
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface Data {
|
|
58
|
-
readonly session: {
|
|
59
|
-
get(sessionID: string): SessionInfo | undefined
|
|
60
|
-
list(): SessionInfo[]
|
|
61
|
-
cost(sessionID: string): number
|
|
62
|
-
status(sessionID: string): string
|
|
63
|
-
interrupt(sessionID: string): Promise<void>
|
|
64
|
-
readonly message: {
|
|
65
|
-
list(sessionID: string): MessageInfo[]
|
|
66
|
-
sync(sessionID: string): Promise<void>
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
readonly location: {
|
|
70
|
-
readonly provider: { list(location?: unknown): unknown[] }
|
|
71
|
-
readonly model: { list(location?: unknown): unknown[] }
|
|
72
|
-
readonly mcp: { readonly server: { list(location?: unknown): unknown[] } }
|
|
73
|
-
}
|
|
74
|
-
readonly on: (type: string, handler: (event: unknown) => void) => () => void
|
|
75
|
-
readonly listen: (handler: (event: unknown) => void) => () => void
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export interface Storage {
|
|
79
|
-
store<Value extends object>(
|
|
80
|
-
key: string,
|
|
81
|
-
options: { readonly initial: Value },
|
|
82
|
-
): readonly [Value, (mutation: (draft: Value) => void) => Promise<void>]
|
|
83
|
-
memory<Value extends object>(
|
|
84
|
-
key: string,
|
|
85
|
-
options: { readonly initial: Value },
|
|
86
|
-
): readonly [Value, (mutation: (draft: Value) => void) => void]
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export type SlotClaim = {
|
|
90
|
-
readonly render: (input: Record<string, any>) => unknown
|
|
91
|
-
} & (
|
|
92
|
-
| { readonly append: string; readonly prepend?: never; readonly before?: never; readonly after?: never; readonly replace?: never }
|
|
93
|
-
| { readonly prepend: string; readonly append?: never; readonly before?: never; readonly after?: never; readonly replace?: never }
|
|
94
|
-
| { readonly before: string; readonly append?: never; readonly prepend?: never; readonly after?: never; readonly replace?: never }
|
|
95
|
-
| { readonly after: string; readonly append?: never; readonly prepend?: never; readonly before?: never; readonly replace?: never }
|
|
96
|
-
| { readonly replace: string; readonly append?: never; readonly prepend?: never; readonly before?: never; readonly after?: never }
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
export interface KeymapCommand {
|
|
100
|
-
readonly id?: string
|
|
101
|
-
readonly title?: string
|
|
102
|
-
readonly description?: string
|
|
103
|
-
readonly group?: string
|
|
104
|
-
readonly palette?: true
|
|
105
|
-
readonly slash?: { readonly name: string; readonly aliases?: string[]; readonly arguments?: true }
|
|
106
|
-
readonly namespace?: string
|
|
107
|
-
readonly name?: string
|
|
108
|
-
readonly desc?: string
|
|
109
|
-
readonly category?: string
|
|
110
|
-
readonly slashName?: string
|
|
111
|
-
readonly slashAliases?: string[]
|
|
112
|
-
readonly run: (input?: string) => void | false | Promise<void>
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** 最小 client 面(运行时由 V2 提供——取消走 session.interrupt)。 */
|
|
116
|
-
export interface ClientLike {
|
|
117
|
-
readonly session: {
|
|
118
|
-
interrupt(input: { sessionID: string; continue?: boolean }): Promise<unknown>
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export interface Context {
|
|
123
|
-
readonly app: App
|
|
124
|
-
readonly options: Record<string, any>
|
|
125
|
-
readonly location: { readonly directory?: string } | undefined
|
|
126
|
-
readonly renderer: { readonly terminalWidth: number }
|
|
127
|
-
readonly theme: Theme
|
|
128
|
-
readonly data: Data
|
|
129
|
-
readonly client: ClientLike
|
|
130
|
-
readonly storage: Storage
|
|
131
|
-
readonly ui: {
|
|
132
|
-
slot(claim: SlotClaim): () => void
|
|
133
|
-
readonly toast: {
|
|
134
|
-
show(options: { readonly message: string; readonly title?: string; readonly variant?: string }): void
|
|
135
|
-
}
|
|
136
|
-
readonly dialog: {
|
|
137
|
-
prompt(options: { readonly title: string; readonly message?: string; readonly placeholder?: string }): Promise<string | undefined>
|
|
138
|
-
select<Value>(options: {
|
|
139
|
-
readonly title: string
|
|
140
|
-
readonly placeholder?: string
|
|
141
|
-
readonly options: readonly {
|
|
142
|
-
readonly title: string
|
|
143
|
-
readonly value: Value
|
|
144
|
-
readonly description?: string
|
|
145
|
-
readonly category?: string
|
|
146
|
-
readonly disabled?: boolean
|
|
147
|
-
}[]
|
|
148
|
-
readonly current?: Value
|
|
149
|
-
}): Promise<Value | undefined>
|
|
150
|
-
}
|
|
151
|
-
readonly router: {
|
|
152
|
-
current(): { readonly type?: string; readonly sessionID?: string; readonly params?: Record<string, unknown> }
|
|
153
|
-
navigate(route: { type: string; sessionID?: string; params?: Record<string, unknown> }): void
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
readonly keymap: {
|
|
157
|
-
layer(input: () => { readonly commands?: readonly KeymapCommand[] }): void
|
|
158
|
-
shortcuts(id: string): readonly string[]
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export type PluginModule = {
|
|
163
|
-
readonly id: string
|
|
164
|
-
readonly setup: (context: Context) => void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>
|
|
165
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* V2 (opencode2) TUI plugin API — 最小本地类型(实验版)。
|
|
3
|
+
* 运行时由 opencode2 提供,此处仅用于本地类型检查;
|
|
4
|
+
* 结构对应 v2 分支 packages/plugin/src/tui/context.ts。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface App {
|
|
8
|
+
readonly version: string
|
|
9
|
+
readonly channel: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Theme {
|
|
13
|
+
readonly hue: {
|
|
14
|
+
readonly interactive: { readonly 300: string }
|
|
15
|
+
readonly accent: { readonly 500: string }
|
|
16
|
+
}
|
|
17
|
+
readonly text: {
|
|
18
|
+
readonly default: string
|
|
19
|
+
readonly subdued: string
|
|
20
|
+
readonly feedback: {
|
|
21
|
+
readonly success: { readonly default: string }
|
|
22
|
+
readonly error: { readonly default: string }
|
|
23
|
+
readonly warning: { readonly default: string }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TokenUsage {
|
|
29
|
+
input?: number
|
|
30
|
+
output?: number
|
|
31
|
+
reasoning?: number
|
|
32
|
+
cache?: { read?: number; write?: number }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface MessageInfo {
|
|
36
|
+
readonly id: string
|
|
37
|
+
readonly type: string
|
|
38
|
+
readonly agent?: string
|
|
39
|
+
readonly model?: string
|
|
40
|
+
readonly time: { readonly created: number; readonly completed?: number }
|
|
41
|
+
readonly cost?: unknown
|
|
42
|
+
readonly tokens?: TokenUsage
|
|
43
|
+
readonly content?: unknown[]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface SessionInfo {
|
|
47
|
+
readonly id: string
|
|
48
|
+
readonly title?: string
|
|
49
|
+
readonly time?: { readonly created: number; readonly updated: number }
|
|
50
|
+
readonly model?: string
|
|
51
|
+
readonly agent?: string
|
|
52
|
+
readonly parentID?: string
|
|
53
|
+
readonly cost?: number
|
|
54
|
+
readonly tokens?: TokenUsage
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface Data {
|
|
58
|
+
readonly session: {
|
|
59
|
+
get(sessionID: string): SessionInfo | undefined
|
|
60
|
+
list(): SessionInfo[]
|
|
61
|
+
cost(sessionID: string): number
|
|
62
|
+
status(sessionID: string): string
|
|
63
|
+
interrupt(sessionID: string): Promise<void>
|
|
64
|
+
readonly message: {
|
|
65
|
+
list(sessionID: string): MessageInfo[]
|
|
66
|
+
sync(sessionID: string): Promise<void>
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
readonly location: {
|
|
70
|
+
readonly provider: { list(location?: unknown): unknown[] }
|
|
71
|
+
readonly model: { list(location?: unknown): unknown[] }
|
|
72
|
+
readonly mcp: { readonly server: { list(location?: unknown): unknown[] } }
|
|
73
|
+
}
|
|
74
|
+
readonly on: (type: string, handler: (event: unknown) => void) => () => void
|
|
75
|
+
readonly listen: (handler: (event: unknown) => void) => () => void
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface Storage {
|
|
79
|
+
store<Value extends object>(
|
|
80
|
+
key: string,
|
|
81
|
+
options: { readonly initial: Value },
|
|
82
|
+
): readonly [Value, (mutation: (draft: Value) => void) => Promise<void>]
|
|
83
|
+
memory<Value extends object>(
|
|
84
|
+
key: string,
|
|
85
|
+
options: { readonly initial: Value },
|
|
86
|
+
): readonly [Value, (mutation: (draft: Value) => void) => void]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type SlotClaim = {
|
|
90
|
+
readonly render: (input: Record<string, any>) => unknown
|
|
91
|
+
} & (
|
|
92
|
+
| { readonly append: string; readonly prepend?: never; readonly before?: never; readonly after?: never; readonly replace?: never }
|
|
93
|
+
| { readonly prepend: string; readonly append?: never; readonly before?: never; readonly after?: never; readonly replace?: never }
|
|
94
|
+
| { readonly before: string; readonly append?: never; readonly prepend?: never; readonly after?: never; readonly replace?: never }
|
|
95
|
+
| { readonly after: string; readonly append?: never; readonly prepend?: never; readonly before?: never; readonly replace?: never }
|
|
96
|
+
| { readonly replace: string; readonly append?: never; readonly prepend?: never; readonly before?: never; readonly after?: never }
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
export interface KeymapCommand {
|
|
100
|
+
readonly id?: string
|
|
101
|
+
readonly title?: string
|
|
102
|
+
readonly description?: string
|
|
103
|
+
readonly group?: string
|
|
104
|
+
readonly palette?: true
|
|
105
|
+
readonly slash?: { readonly name: string; readonly aliases?: string[]; readonly arguments?: true }
|
|
106
|
+
readonly namespace?: string
|
|
107
|
+
readonly name?: string
|
|
108
|
+
readonly desc?: string
|
|
109
|
+
readonly category?: string
|
|
110
|
+
readonly slashName?: string
|
|
111
|
+
readonly slashAliases?: string[]
|
|
112
|
+
readonly run: (input?: string) => void | false | Promise<void>
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** 最小 client 面(运行时由 V2 提供——取消走 session.interrupt)。 */
|
|
116
|
+
export interface ClientLike {
|
|
117
|
+
readonly session: {
|
|
118
|
+
interrupt(input: { sessionID: string; continue?: boolean }): Promise<unknown>
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface Context {
|
|
123
|
+
readonly app: App
|
|
124
|
+
readonly options: Record<string, any>
|
|
125
|
+
readonly location: { readonly directory?: string } | undefined
|
|
126
|
+
readonly renderer: { readonly terminalWidth: number }
|
|
127
|
+
readonly theme: Theme
|
|
128
|
+
readonly data: Data
|
|
129
|
+
readonly client: ClientLike
|
|
130
|
+
readonly storage: Storage
|
|
131
|
+
readonly ui: {
|
|
132
|
+
slot(claim: SlotClaim): () => void
|
|
133
|
+
readonly toast: {
|
|
134
|
+
show(options: { readonly message: string; readonly title?: string; readonly variant?: string }): void
|
|
135
|
+
}
|
|
136
|
+
readonly dialog: {
|
|
137
|
+
prompt(options: { readonly title: string; readonly message?: string; readonly placeholder?: string }): Promise<string | undefined>
|
|
138
|
+
select<Value>(options: {
|
|
139
|
+
readonly title: string
|
|
140
|
+
readonly placeholder?: string
|
|
141
|
+
readonly options: readonly {
|
|
142
|
+
readonly title: string
|
|
143
|
+
readonly value: Value
|
|
144
|
+
readonly description?: string
|
|
145
|
+
readonly category?: string
|
|
146
|
+
readonly disabled?: boolean
|
|
147
|
+
}[]
|
|
148
|
+
readonly current?: Value
|
|
149
|
+
}): Promise<Value | undefined>
|
|
150
|
+
}
|
|
151
|
+
readonly router: {
|
|
152
|
+
current(): { readonly type?: string; readonly sessionID?: string; readonly params?: Record<string, unknown> }
|
|
153
|
+
navigate(route: { type: string; sessionID?: string; params?: Record<string, unknown> }): void
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
readonly keymap: {
|
|
157
|
+
layer(input: () => { readonly commands?: readonly KeymapCommand[] }): void
|
|
158
|
+
shortcuts(id: string): readonly string[]
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type PluginModule = {
|
|
163
|
+
readonly id: string
|
|
164
|
+
readonly setup: (context: Context) => void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>
|
|
165
|
+
}
|
package/tui/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// tui/index.js——V1/V2 共用入口(双格式)
|
|
2
|
-
// - V1(opencode):exports["./tui"] → 本文件——readV1Plugin 读 tui 字段(V1 面板)
|
|
3
|
-
// - V2(opencode2):exports["./tui"] → 本文件——isPlugin 读 setup 字段(V2 面板)
|
|
4
|
-
import tuiMod from "./../dist/tui.js"
|
|
5
|
-
import v2Mod from "./../dist/v2.js"
|
|
6
|
-
|
|
7
|
-
export default {
|
|
8
|
-
id: "opencode-subagent-magazine",
|
|
9
|
-
tui: tuiMod.tui,
|
|
10
|
-
setup: v2Mod.setup,
|
|
11
|
-
}
|
|
1
|
+
// tui/index.js——V1/V2 共用入口(双格式)
|
|
2
|
+
// - V1(opencode):exports["./tui"] → 本文件——readV1Plugin 读 tui 字段(V1 面板)
|
|
3
|
+
// - V2(opencode2):exports["./tui"] → 本文件——isPlugin 读 setup 字段(V2 面板)
|
|
4
|
+
import tuiMod from "./../dist/tui.js"
|
|
5
|
+
import v2Mod from "./../dist/v2.js"
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
id: "opencode-subagent-magazine",
|
|
9
|
+
tui: tuiMod.tui,
|
|
10
|
+
setup: v2Mod.setup,
|
|
11
|
+
}
|