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.
Files changed (52) hide show
  1. package/dist/_version.d.ts +1 -1
  2. package/dist/tui.js +1 -1
  3. package/dist/v2.js +1 -1
  4. package/package.json +17 -4
  5. package/dist/_version.js +0 -2
  6. package/dist/clipboard.js +0 -85
  7. package/dist/core/color.js +0 -68
  8. package/dist/core/format.js +0 -113
  9. package/dist/core/index.js +0 -6
  10. package/dist/core/kv.js +0 -64
  11. package/dist/core/state-machine.js +0 -27
  12. package/dist/core/types.js +0 -9
  13. package/dist/core/usage.js +0 -1
  14. package/dist/i18n.js +0 -353
  15. package/dist/index.js +0 -528
  16. package/dist/panel/SubAgentPanel.js +0 -1644
  17. package/dist/panel/entry-map.js +0 -99
  18. package/dist/panel/panel-api.js +0 -1
  19. package/dist/panel/session-routing.js +0 -4
  20. package/dist/panel/store.js +0 -5
  21. package/dist/server.js +0 -14
  22. package/dist/v2/commands.js +0 -434
  23. package/dist/v2/db.js +0 -341
  24. package/dist/v2/index.js +0 -85
  25. package/dist/v2/settings-menu.js +0 -242
  26. package/dist/v2/theme.js +0 -12
  27. package/dist/v2/types.js +0 -6
  28. package/dist/v2/v2-panel-api.js +0 -623
  29. package/src/_version.ts +0 -2
  30. package/src/clipboard.ts +0 -134
  31. package/src/core/color.ts +0 -70
  32. package/src/core/format.ts +0 -105
  33. package/src/core/index.ts +0 -6
  34. package/src/core/kv.ts +0 -78
  35. package/src/core/state-machine.ts +0 -46
  36. package/src/core/types.ts +0 -85
  37. package/src/core/usage.ts +0 -16
  38. package/src/i18n.ts +0 -365
  39. package/src/index.tsx +0 -584
  40. package/src/panel/SubAgentPanel.tsx +0 -1877
  41. package/src/panel/entry-map.ts +0 -116
  42. package/src/panel/panel-api.ts +0 -100
  43. package/src/panel/session-routing.ts +0 -10
  44. package/src/panel/store.ts +0 -8
  45. package/src/server.ts +0 -19
  46. package/src/v2/commands.ts +0 -422
  47. package/src/v2/db.ts +0 -346
  48. package/src/v2/index.tsx +0 -149
  49. package/src/v2/settings-menu.ts +0 -259
  50. package/src/v2/theme.ts +0 -14
  51. package/src/v2/types.ts +0 -167
  52. package/src/v2/v2-panel-api.ts +0 -520
@@ -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
- }