opencode-subagent-magazine 1.7.1 → 1.7.2
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/dist/_version.d.ts +1 -1
- package/dist/tui.js +1 -1
- package/dist/v2.js +1 -1
- package/package.json +17 -4
- package/dist/_version.js +0 -2
- package/dist/clipboard.js +0 -85
- package/dist/core/color.js +0 -68
- package/dist/core/format.js +0 -113
- package/dist/core/index.js +0 -6
- package/dist/core/kv.js +0 -64
- package/dist/core/state-machine.js +0 -27
- package/dist/core/types.js +0 -9
- package/dist/core/usage.js +0 -1
- package/dist/i18n.js +0 -353
- package/dist/index.js +0 -528
- package/dist/panel/SubAgentPanel.js +0 -1644
- package/dist/panel/entry-map.js +0 -99
- package/dist/panel/panel-api.js +0 -1
- package/dist/panel/session-routing.js +0 -4
- package/dist/panel/store.js +0 -5
- package/dist/server.js +0 -14
- package/dist/v2/commands.js +0 -434
- package/dist/v2/db.js +0 -341
- package/dist/v2/index.js +0 -85
- package/dist/v2/settings-menu.js +0 -242
- package/dist/v2/theme.js +0 -12
- package/dist/v2/types.js +0 -6
- package/dist/v2/v2-panel-api.js +0 -623
- package/src/_version.ts +0 -2
- package/src/clipboard.ts +0 -134
- package/src/core/color.ts +0 -70
- package/src/core/format.ts +0 -105
- package/src/core/index.ts +0 -6
- package/src/core/kv.ts +0 -78
- package/src/core/state-machine.ts +0 -46
- package/src/core/types.ts +0 -85
- package/src/core/usage.ts +0 -16
- package/src/i18n.ts +0 -365
- package/src/index.tsx +0 -584
- package/src/panel/SubAgentPanel.tsx +0 -1877
- package/src/panel/entry-map.ts +0 -116
- package/src/panel/panel-api.ts +0 -100
- package/src/panel/session-routing.ts +0 -10
- package/src/panel/store.ts +0 -8
- package/src/server.ts +0 -19
- package/src/v2/commands.ts +0 -422
- package/src/v2/db.ts +0 -346
- package/src/v2/index.tsx +0 -149
- package/src/v2/settings-menu.ts +0 -259
- package/src/v2/theme.ts +0 -14
- package/src/v2/types.ts +0 -167
- package/src/v2/v2-panel-api.ts +0 -520
package/src/v2/settings-menu.ts
DELETED
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
import type { Context } from "./types"
|
|
2
|
-
import type { PanelApi } from "../panel/panel-api"
|
|
3
|
-
import type { Lang, SortOrder, ScrollMode, SharedSignals, TimeFormat } from "../core/types"
|
|
4
|
-
import { SETTING_KEYS, readTTLDays } from "../core/kv"
|
|
5
|
-
import { TIME_FORMATS, TIME_FORMAT_SAMPLES } from "../core/format"
|
|
6
|
-
import { LANG_META, createT } from "../i18n"
|
|
7
|
-
|
|
8
|
-
/** 与侧栏设置共用的 TTL 周期:3/7/14/30 天或无限期。 */
|
|
9
|
-
const TTL_VALUES = [3, 7, 14, 30, 0]
|
|
10
|
-
|
|
11
|
-
/** 链式原生对话框之间的延迟,让宿主能关闭上一个对话框。 */
|
|
12
|
-
const nextTick = () => new Promise<void>((resolve) => setTimeout(resolve, 0))
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 原生设置菜单(visual-cache 风格):用单个选择列表展示每项设置
|
|
16
|
-
* 及其当前值;选中某项会打开对应的编辑器,
|
|
17
|
-
* 随后菜单重新打开,直到用户关闭(Esc / Close)。
|
|
18
|
-
*/
|
|
19
|
-
export function openSettingsMenu(context: Context, api: PanelApi, signals: SharedSignals): void {
|
|
20
|
-
runSettingsMenu(context, api, signals).catch((err) => {
|
|
21
|
-
try { context.ui.toast.show({ message: String(err), variant: "error" }) } catch {}
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async function runSettingsMenu(context: Context, api: PanelApi, signals: SharedSignals): Promise<void> {
|
|
26
|
-
const t = createT(() => signals.lang())
|
|
27
|
-
const kv = api.kv
|
|
28
|
-
const onOff = (v: boolean) => (v ? t("settings.on") : t("settings.off"))
|
|
29
|
-
const langLabel = () => LANG_META.find((m) => m.code === signals.lang())?.label ?? signals.lang()
|
|
30
|
-
const ttlTitle = (d: number) => (d === 0 ? t("ttl.unlimited") : t(d === 3 ? "ttl.3d" : d === 7 ? "ttl.7d" : d === 14 ? "ttl.14d" : "ttl.30d"))
|
|
31
|
-
const ttlLabel = () => ttlTitle(readTTLDays(kv))
|
|
32
|
-
const orderLabel = () => (signals.sortOrder() === "desc" ? t("order.desc") : t("order.asc"))
|
|
33
|
-
const scrollLabel = () => (signals.scrollMode() === "wheel" ? t("scroll.wheel") : t("scroll.click"))
|
|
34
|
-
const toast = (item: string, value: string) =>
|
|
35
|
-
context.ui.toast.show({ message: t("settings.saved", { item, value }) })
|
|
36
|
-
|
|
37
|
-
while (true) {
|
|
38
|
-
const category = t("settings.section.general")
|
|
39
|
-
const choice = await context.ui.dialog.select<string>({
|
|
40
|
-
title: t("settings.title"),
|
|
41
|
-
options: [
|
|
42
|
-
{ title: t("settings.lang"), value: "lang", description: langLabel(), category },
|
|
43
|
-
{ title: t("settings.max"), value: "max", description: String(signals.maxEntries()), category },
|
|
44
|
-
{ title: t("settings.order"), value: "order", description: orderLabel(), category },
|
|
45
|
-
{ title: t("settings.scroll"), value: "scroll", description: scrollLabel(), category },
|
|
46
|
-
{ title: t("settings.ttl"), value: "ttl", description: ttlLabel(), category },
|
|
47
|
-
{ title: t("settings.border"), value: "border", description: onOff(signals.borderVisible()), category },
|
|
48
|
-
{ title: t("settings.showEntryCost"), value: "cost", description: onOff(signals.showEntryCost()), category },
|
|
49
|
-
{ title: t("settings.showEntryTime"), value: "time", description: onOff(signals.showEntryTime()), category },
|
|
50
|
-
{ title: t("settings.timeFormat"), value: "timefmt", description: TIME_FORMAT_SAMPLES[signals.timeFormat()], category },
|
|
51
|
-
{ title: t("settings.showEntryTokens"), value: "tokens", description: onOff(signals.showEntryTokens()), category },
|
|
52
|
-
{ title: t("settings.showOrigin"), value: "origin", description: onOff(signals.showOrigin()), category },
|
|
53
|
-
{ title: t("settings.dbSync"), value: "dbsync", description: onOff(signals.dbSync()), category },
|
|
54
|
-
{ title: t("settings.close"), value: "close" },
|
|
55
|
-
],
|
|
56
|
-
})
|
|
57
|
-
if (choice === undefined || choice === "close") return
|
|
58
|
-
|
|
59
|
-
// ── 语言 ──
|
|
60
|
-
if (choice === "lang") {
|
|
61
|
-
const picked = await context.ui.dialog.select<Lang>({
|
|
62
|
-
title: t("settings.lang"),
|
|
63
|
-
options: LANG_META.map((m) => ({ title: m.label, value: m.code })),
|
|
64
|
-
current: signals.lang(),
|
|
65
|
-
})
|
|
66
|
-
if (picked) {
|
|
67
|
-
signals.setLang(picked)
|
|
68
|
-
kv.set(SETTING_KEYS.lang, picked)
|
|
69
|
-
toast(t("settings.lang"), LANG_META.find((m) => m.code === picked)?.label ?? picked)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ── 最大可见条目数 ──
|
|
74
|
-
if (choice === "max") {
|
|
75
|
-
const val = await context.ui.dialog.prompt({
|
|
76
|
-
title: t("settings.max"),
|
|
77
|
-
message: "1–50",
|
|
78
|
-
placeholder: String(signals.maxEntries()),
|
|
79
|
-
})
|
|
80
|
-
if (val !== undefined) {
|
|
81
|
-
const n = parseInt(val.trim(), 10)
|
|
82
|
-
if (Number.isNaN(n)) {
|
|
83
|
-
context.ui.toast.show({ message: t("settings.invalid"), variant: "warning" })
|
|
84
|
-
} else {
|
|
85
|
-
const clamped = Math.max(1, Math.min(50, n))
|
|
86
|
-
signals.setMaxEntries(clamped)
|
|
87
|
-
kv.set(SETTING_KEYS.maxEntries, clamped)
|
|
88
|
-
toast(t("settings.max"), String(clamped))
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// ── 排序方式 ──
|
|
94
|
-
if (choice === "order") {
|
|
95
|
-
const picked = await context.ui.dialog.select<SortOrder>({
|
|
96
|
-
title: t("settings.order"),
|
|
97
|
-
options: [
|
|
98
|
-
{ title: t("order.desc"), value: "desc" },
|
|
99
|
-
{ title: t("order.asc"), value: "asc" },
|
|
100
|
-
],
|
|
101
|
-
current: signals.sortOrder(),
|
|
102
|
-
})
|
|
103
|
-
if (picked) {
|
|
104
|
-
signals.setSortOrder(picked)
|
|
105
|
-
kv.set(SETTING_KEYS.order, picked)
|
|
106
|
-
toast(t("settings.order"), picked === "desc" ? t("order.desc") : t("order.asc"))
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ── 滚动模式 ──
|
|
111
|
-
if (choice === "scroll") {
|
|
112
|
-
const picked = await context.ui.dialog.select<ScrollMode>({
|
|
113
|
-
title: t("settings.scroll"),
|
|
114
|
-
options: [
|
|
115
|
-
{ title: t("scroll.wheel"), value: "wheel" },
|
|
116
|
-
{ title: t("scroll.click"), value: "click" },
|
|
117
|
-
],
|
|
118
|
-
current: signals.scrollMode(),
|
|
119
|
-
})
|
|
120
|
-
if (picked) {
|
|
121
|
-
signals.setScrollMode(picked)
|
|
122
|
-
kv.set(SETTING_KEYS.scrollMode, picked)
|
|
123
|
-
toast(t("settings.scroll"), picked === "wheel" ? t("scroll.wheel") : t("scroll.click"))
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ── TTL / 保留期 ──
|
|
128
|
-
if (choice === "ttl") {
|
|
129
|
-
const picked = await context.ui.dialog.select<number>({
|
|
130
|
-
title: t("settings.ttl"),
|
|
131
|
-
options: TTL_VALUES.map((d) => ({ title: ttlTitle(d), value: d })),
|
|
132
|
-
current: readTTLDays(kv),
|
|
133
|
-
})
|
|
134
|
-
if (picked !== undefined) {
|
|
135
|
-
kv.set(SETTING_KEYS.ttlDays, String(picked))
|
|
136
|
-
toast(t("settings.ttl"), ttlTitle(picked))
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// ── 边框 ──
|
|
141
|
-
if (choice === "border") {
|
|
142
|
-
const picked = await context.ui.dialog.select<boolean>({
|
|
143
|
-
title: t("settings.border"),
|
|
144
|
-
options: [
|
|
145
|
-
{ title: t("settings.on"), value: true },
|
|
146
|
-
{ title: t("settings.off"), value: false },
|
|
147
|
-
],
|
|
148
|
-
current: signals.borderVisible(),
|
|
149
|
-
})
|
|
150
|
-
if (picked !== undefined) {
|
|
151
|
-
signals.setBorderVisible(picked)
|
|
152
|
-
kv.set(SETTING_KEYS.border, picked)
|
|
153
|
-
toast(t("settings.border"), onOff(picked))
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// ── 单条目费用 ──
|
|
158
|
-
if (choice === "cost") {
|
|
159
|
-
const picked = await context.ui.dialog.select<boolean>({
|
|
160
|
-
title: t("settings.showEntryCost"),
|
|
161
|
-
options: [
|
|
162
|
-
{ title: t("settings.on"), value: true },
|
|
163
|
-
{ title: t("settings.off"), value: false },
|
|
164
|
-
],
|
|
165
|
-
current: signals.showEntryCost(),
|
|
166
|
-
})
|
|
167
|
-
if (picked !== undefined) {
|
|
168
|
-
signals.setShowEntryCost(picked)
|
|
169
|
-
kv.set(SETTING_KEYS.showEntryCost, picked)
|
|
170
|
-
toast(t("settings.showEntryCost"), onOff(picked))
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// ── 单条目时间 ──
|
|
175
|
-
if (choice === "time") {
|
|
176
|
-
const picked = await context.ui.dialog.select<boolean>({
|
|
177
|
-
title: t("settings.showEntryTime"),
|
|
178
|
-
options: [
|
|
179
|
-
{ title: t("settings.on"), value: true },
|
|
180
|
-
{ title: t("settings.off"), value: false },
|
|
181
|
-
],
|
|
182
|
-
current: signals.showEntryTime(),
|
|
183
|
-
})
|
|
184
|
-
if (picked !== undefined) {
|
|
185
|
-
signals.setShowEntryTime(picked)
|
|
186
|
-
kv.set(SETTING_KEYS.showEntryTime, picked)
|
|
187
|
-
toast(t("settings.showEntryTime"), onOff(picked))
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// ── 时间格式 ──
|
|
192
|
-
if (choice === "timefmt") {
|
|
193
|
-
const picked = await context.ui.dialog.select<TimeFormat>({
|
|
194
|
-
title: t("settings.timeFormat"),
|
|
195
|
-
options: TIME_FORMATS.map((f) => ({ title: `${f} — ${TIME_FORMAT_SAMPLES[f]}`, value: f })),
|
|
196
|
-
current: signals.timeFormat(),
|
|
197
|
-
})
|
|
198
|
-
if (picked) {
|
|
199
|
-
signals.setTimeFormat(picked)
|
|
200
|
-
kv.set(SETTING_KEYS.timeFormat, picked)
|
|
201
|
-
toast(t("settings.timeFormat"), TIME_FORMAT_SAMPLES[picked])
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// ── 单条目 token 数 ──
|
|
206
|
-
if (choice === "tokens") {
|
|
207
|
-
const picked = await context.ui.dialog.select<boolean>({
|
|
208
|
-
title: t("settings.showEntryTokens"),
|
|
209
|
-
options: [
|
|
210
|
-
{ title: t("settings.on"), value: true },
|
|
211
|
-
{ title: t("settings.off"), value: false },
|
|
212
|
-
],
|
|
213
|
-
current: signals.showEntryTokens(),
|
|
214
|
-
})
|
|
215
|
-
if (picked !== undefined) {
|
|
216
|
-
signals.setShowEntryTokens(picked)
|
|
217
|
-
kv.set(SETTING_KEYS.showEntryTokens, picked)
|
|
218
|
-
toast(t("settings.showEntryTokens"), onOff(picked))
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// ── Origin indicators ──
|
|
223
|
-
if (choice === "origin") {
|
|
224
|
-
const picked = await context.ui.dialog.select<boolean>({
|
|
225
|
-
title: t("settings.showOrigin"),
|
|
226
|
-
options: [
|
|
227
|
-
{ title: t("settings.on"), value: true },
|
|
228
|
-
{ title: t("settings.off"), value: false },
|
|
229
|
-
],
|
|
230
|
-
current: signals.showOrigin(),
|
|
231
|
-
})
|
|
232
|
-
if (picked !== undefined) {
|
|
233
|
-
signals.setShowOrigin(picked)
|
|
234
|
-
kv.set(SETTING_KEYS.showOrigin, picked)
|
|
235
|
-
toast(t("settings.showOrigin"), onOff(picked))
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// ── 本地数据库补全 ──
|
|
240
|
-
if (choice === "dbsync") {
|
|
241
|
-
const picked = await context.ui.dialog.select<boolean>({
|
|
242
|
-
title: t("settings.dbSync"),
|
|
243
|
-
options: [
|
|
244
|
-
{ title: t("settings.on"), value: true },
|
|
245
|
-
{ title: t("settings.off"), value: false },
|
|
246
|
-
],
|
|
247
|
-
current: signals.dbSync(),
|
|
248
|
-
})
|
|
249
|
-
if (picked !== undefined) {
|
|
250
|
-
signals.setDbSync(picked)
|
|
251
|
-
kv.set(SETTING_KEYS.dbSync, picked)
|
|
252
|
-
toast(t("settings.dbSync"), onOff(picked))
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// 让宿主先关闭编辑器,再重新打开菜单。
|
|
257
|
-
await nextTick()
|
|
258
|
-
}
|
|
259
|
-
}
|
package/src/v2/theme.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
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: () => {
|
|
158
|
-
readonly commands?: readonly KeymapCommand[]
|
|
159
|
-
}): void
|
|
160
|
-
shortcuts(id: string): readonly string[]
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export type PluginModule = {
|
|
165
|
-
readonly id: string
|
|
166
|
-
readonly setup: (context: Context) => void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>
|
|
167
|
-
}
|