herm-tui 1.0.0-dev.1 → 1.0.0-dev.3
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/db.worker.js +81 -0
- package/highlights-eq9cgrbb.scm +604 -0
- package/highlights-ghv9g403.scm +205 -0
- package/highlights-hk7bwhj4.scm +284 -0
- package/highlights-r812a2qc.scm +150 -0
- package/highlights-x6tmsnaa.scm +115 -0
- package/index.js +10374 -0
- package/injections-73j83es3.scm +27 -0
- package/package.json +14 -64
- package/parser.worker.js +8 -0
- package/tree-sitter-3jzf13jk.wasm +0 -0
- package/tree-sitter-javascript-nd0q4pe9.wasm +0 -0
- package/tree-sitter-markdown-411r6y9b.wasm +0 -0
- package/tree-sitter-markdown_inline-j5349f42.wasm +0 -0
- package/tree-sitter-typescript-zxjzwt75.wasm +0 -0
- package/tree-sitter-zig-e78zbjpm.wasm +0 -0
- package/scripts/postinstall.ts +0 -29
- package/src/app/gateway.tsx +0 -83
- package/src/app/gatewayEvents.ts +0 -203
- package/src/app/launch.ts +0 -41
- package/src/app/skin.tsx +0 -31
- package/src/app/spawnHistory.ts +0 -75
- package/src/app/tabs.ts +0 -23
- package/src/app/turnReducer.ts +0 -390
- package/src/app/useAppKeys.ts +0 -268
- package/src/app/useAtRefPopover.ts +0 -99
- package/src/app/useInputHistory.ts +0 -66
- package/src/app/useSession.ts +0 -102
- package/src/app/useSlashCommands.ts +0 -70
- package/src/app/useSlashPopover.ts +0 -48
- package/src/app.tsx +0 -917
- package/src/commands/slash.ts +0 -151
- package/src/components/avatar/AnimatedAvatar.tsx +0 -66
- package/src/components/avatar/eikon.ts +0 -144
- package/src/components/avatar/states/error.ts +0 -1155
- package/src/components/avatar/states/idle.ts +0 -1155
- package/src/components/avatar/states/index.ts +0 -30
- package/src/components/avatar/states/listening.ts +0 -1155
- package/src/components/avatar/states/speaking.ts +0 -1155
- package/src/components/avatar/states/thinking.ts +0 -1155
- package/src/components/avatar/states/working.ts +0 -1155
- package/src/components/chat/AtRefPopover.tsx +0 -54
- package/src/components/chat/CodeBlock.tsx +0 -67
- package/src/components/chat/Composer.tsx +0 -347
- package/src/components/chat/DiffBlock.tsx +0 -116
- package/src/components/chat/ErrorBlock.tsx +0 -70
- package/src/components/chat/MediaChip.tsx +0 -114
- package/src/components/chat/MessageItem.tsx +0 -282
- package/src/components/chat/MessageList.tsx +0 -114
- package/src/components/chat/PromptCard.tsx +0 -359
- package/src/components/chat/SlashPopover.tsx +0 -158
- package/src/components/chat/ThoughtCloud.tsx +0 -185
- package/src/components/chat/TypingIndicator.tsx +0 -25
- package/src/components/chat/tool/Subagent.tsx +0 -75
- package/src/components/chat/tool/frame.tsx +0 -69
- package/src/components/chat/tool/index.tsx +0 -65
- package/src/components/chat/tool/preview.ts +0 -57
- package/src/components/sidebar/ContextGauge.tsx +0 -102
- package/src/components/sidebar/Sidebar.tsx +0 -143
- package/src/components/tabs/TabBar.tsx +0 -50
- package/src/components/ui/FileLink.tsx +0 -52
- package/src/config/index.ts +0 -156
- package/src/config/lane.ts +0 -161
- package/src/config/models.ts +0 -95
- package/src/config/rules.ts +0 -80
- package/src/config/schema.ts +0 -308
- package/src/dialogs/alert.tsx +0 -52
- package/src/dialogs/chafa.tsx +0 -72
- package/src/dialogs/confirm.tsx +0 -58
- package/src/dialogs/curator.tsx +0 -153
- package/src/dialogs/eikon-picker.tsx +0 -95
- package/src/dialogs/help.tsx +0 -80
- package/src/dialogs/history.tsx +0 -92
- package/src/dialogs/info.tsx +0 -115
- package/src/dialogs/keys.tsx +0 -170
- package/src/dialogs/logs.tsx +0 -42
- package/src/dialogs/message.tsx +0 -38
- package/src/dialogs/model-picker.tsx +0 -123
- package/src/dialogs/new-profile.tsx +0 -69
- package/src/dialogs/new-task.tsx +0 -103
- package/src/dialogs/profile.tsx +0 -55
- package/src/dialogs/rollback.tsx +0 -190
- package/src/dialogs/spawn-history.tsx +0 -80
- package/src/dialogs/text-prompt.tsx +0 -68
- package/src/dialogs/theme-picker.tsx +0 -50
- package/src/home/index.ts +0 -23
- package/src/home/store.ts +0 -267
- package/src/index.tsx +0 -113
- package/src/keys/catalog.ts +0 -115
- package/src/keys/chord.ts +0 -125
- package/src/keys/conflicts.ts +0 -48
- package/src/keys/context.tsx +0 -112
- package/src/keys/index.ts +0 -5
- package/src/keys/list.ts +0 -94
- package/src/keys/oc-compat.ts +0 -87
- package/src/tabs/Agents.tsx +0 -607
- package/src/tabs/Analytics.tsx +0 -154
- package/src/tabs/Chat.tsx +0 -50
- package/src/tabs/Config.tsx +0 -605
- package/src/tabs/Context.tsx +0 -599
- package/src/tabs/Cron.tsx +0 -294
- package/src/tabs/Env.tsx +0 -227
- package/src/tabs/Kanban.tsx +0 -367
- package/src/tabs/Memory.tsx +0 -294
- package/src/tabs/Sessions.tsx +0 -786
- package/src/tabs/Skills.tsx +0 -507
- package/src/tabs/Toolsets.tsx +0 -266
- package/src/theme/builtin.ts +0 -78
- package/src/theme/context.tsx +0 -106
- package/src/theme/index.ts +0 -4
- package/src/theme/resolve.ts +0 -134
- package/src/theme/syntax.ts +0 -31
- package/src/theme/themes/aura.json +0 -69
- package/src/theme/themes/ayu.json +0 -80
- package/src/theme/themes/carbonfox.json +0 -248
- package/src/theme/themes/catppuccin-frappe.json +0 -233
- package/src/theme/themes/catppuccin-macchiato.json +0 -233
- package/src/theme/themes/catppuccin.json +0 -112
- package/src/theme/themes/cobalt2.json +0 -228
- package/src/theme/themes/cursor.json +0 -249
- package/src/theme/themes/dracula.json +0 -219
- package/src/theme/themes/everforest.json +0 -241
- package/src/theme/themes/flexoki.json +0 -237
- package/src/theme/themes/github.json +0 -233
- package/src/theme/themes/gruvbox.json +0 -242
- package/src/theme/themes/kanagawa.json +0 -77
- package/src/theme/themes/lucent-orng.json +0 -237
- package/src/theme/themes/material.json +0 -235
- package/src/theme/themes/matrix.json +0 -77
- package/src/theme/themes/mercury.json +0 -252
- package/src/theme/themes/monokai.json +0 -221
- package/src/theme/themes/nightowl.json +0 -221
- package/src/theme/themes/nord.json +0 -223
- package/src/theme/themes/one-dark.json +0 -84
- package/src/theme/themes/opencode.json +0 -245
- package/src/theme/themes/orng.json +0 -249
- package/src/theme/themes/osaka-jade.json +0 -93
- package/src/theme/themes/palenight.json +0 -222
- package/src/theme/themes/rosepine.json +0 -234
- package/src/theme/themes/solarized.json +0 -223
- package/src/theme/themes/synthwave84.json +0 -226
- package/src/theme/themes/tokyonight.json +0 -243
- package/src/theme/themes/vercel.json +0 -245
- package/src/theme/themes/vesper.json +0 -218
- package/src/theme/themes/zenburn.json +0 -223
- package/src/theme/types.ts +0 -119
- package/src/types/message.ts +0 -97
- package/src/ui/ChafaImage.tsx +0 -64
- package/src/ui/Splash.tsx +0 -118
- package/src/ui/borders.ts +0 -28
- package/src/ui/command.tsx +0 -104
- package/src/ui/dialog-select.tsx +0 -164
- package/src/ui/dialog.tsx +0 -102
- package/src/ui/fmt.ts +0 -82
- package/src/ui/kv.tsx +0 -28
- package/src/ui/shell.tsx +0 -45
- package/src/ui/spinner.tsx +0 -59
- package/src/ui/splash-art.ts +0 -123
- package/src/ui/table.tsx +0 -117
- package/src/ui/ticker.tsx +0 -90
- package/src/ui/toast.tsx +0 -130
- package/src/utils/categorical.ts +0 -77
- package/src/utils/chafa.ts +0 -173
- package/src/utils/clipboard.ts +0 -67
- package/src/utils/context-segments.ts +0 -317
- package/src/utils/control.ts +0 -495
- package/src/utils/drop.ts +0 -25
- package/src/utils/editor.ts +0 -33
- package/src/utils/fuzzy.ts +0 -45
- package/src/utils/gateway-client.ts +0 -253
- package/src/utils/gateway-types.ts +0 -282
- package/src/utils/git.ts +0 -57
- package/src/utils/hermes-analytics.ts +0 -134
- package/src/utils/hermes-home.ts +0 -821
- package/src/utils/hermes-kanban.ts +0 -154
- package/src/utils/hermes-profiles.ts +0 -217
- package/src/utils/interpolate.ts +0 -31
- package/src/utils/math-unicode.ts +0 -818
- package/src/utils/memory-activity.ts +0 -140
- package/src/utils/open-file.ts +0 -13
- package/src/utils/paths.ts +0 -52
- package/src/utils/perf.ts +0 -235
- package/src/utils/preferences.ts +0 -150
- package/src/utils/sessions-db.ts +0 -396
- package/src/utils/subagent-tree.ts +0 -146
- package/src/utils/terminal-reset.ts +0 -129
- package/src/utils/tips.ts +0 -67
- package/src/utils/tokens.ts +0 -87
package/src/app/gatewayEvents.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
// Maps a GatewayEvent to a turn-reducer Action plus fire-and-forget side effects.
|
|
2
|
-
|
|
3
|
-
import * as perf from "../utils/perf"
|
|
4
|
-
import * as spawnHistory from "./spawnHistory"
|
|
5
|
-
import type { GatewayEvent, GatewaySkin, SessionInfo } from "../utils/gateway-types"
|
|
6
|
-
import type { Action } from "./turnReducer"
|
|
7
|
-
import { pid, type Usage } from "../types/message"
|
|
8
|
-
|
|
9
|
-
export type Side = {
|
|
10
|
-
onReady?: () => void
|
|
11
|
-
onSessionInfo?: (info: SessionInfo) => void
|
|
12
|
-
onUsage?: (u: Usage) => void
|
|
13
|
-
onTurnComplete?: () => void
|
|
14
|
-
onBackground?: (task_id: string, text: string) => void
|
|
15
|
-
onBtw?: (text: string) => void
|
|
16
|
-
onStatus?: (text: string) => void
|
|
17
|
-
onSkin?: (skin: GatewaySkin | null | undefined) => void
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function count(o: Record<string, string[]> | undefined): number {
|
|
21
|
-
return o ? Object.values(o).reduce((n, v) => n + v.length, 0) : 0
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function mapEvent(ev: GatewayEvent, side: Side): Action | null {
|
|
25
|
-
switch (ev.type) {
|
|
26
|
-
case "gateway.ready":
|
|
27
|
-
side.onReady?.()
|
|
28
|
-
if (ev.payload?.skin) side.onSkin?.(ev.payload.skin)
|
|
29
|
-
return null
|
|
30
|
-
|
|
31
|
-
case "session.info": {
|
|
32
|
-
const si = ev.payload
|
|
33
|
-
side.onSessionInfo?.(si)
|
|
34
|
-
const label = si.model
|
|
35
|
-
? `Connected — ${si.model} · ${count(si.tools)} tools · ${count(si.skills)} skills`
|
|
36
|
-
: "Connected to Hermes"
|
|
37
|
-
if (si.credential_warning) side.onStatus?.(si.credential_warning)
|
|
38
|
-
return { kind: "system", text: label }
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
case "message.start":
|
|
42
|
-
perf.count("stream:start")
|
|
43
|
-
perf.mem("stream-start")
|
|
44
|
-
return { kind: "message.start" }
|
|
45
|
-
|
|
46
|
-
case "message.delta": {
|
|
47
|
-
const chunk = ev.payload?.text ?? ""
|
|
48
|
-
if (!chunk) return null
|
|
49
|
-
perf.count("stream:chunk")
|
|
50
|
-
return { kind: "message.delta", chunk }
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
case "message.complete": {
|
|
54
|
-
perf.count("stream:done")
|
|
55
|
-
perf.mem("stream-done")
|
|
56
|
-
const p = ev.payload
|
|
57
|
-
if (p?.usage) side.onUsage?.(p.usage)
|
|
58
|
-
side.onTurnComplete?.()
|
|
59
|
-
// The gateway reports in-agent failures via status (exceptions come
|
|
60
|
-
// as a separate `error` event). Without this branch a failed API
|
|
61
|
-
// call ends the turn with no visible output.
|
|
62
|
-
if (p?.status === "error")
|
|
63
|
-
return { kind: "error", text: p.text || "request failed — see messages above" }
|
|
64
|
-
if (p?.status === "interrupted")
|
|
65
|
-
return { kind: "message.complete", text: (p.text || "") + "\n\n*[interrupted]*", usage: p?.usage }
|
|
66
|
-
return { kind: "message.complete", text: p?.text ?? undefined, usage: p?.usage }
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
case "tool.start":
|
|
70
|
-
return {
|
|
71
|
-
kind: "tool.start",
|
|
72
|
-
id: ev.payload.tool_id,
|
|
73
|
-
name: ev.payload.name ?? "unknown",
|
|
74
|
-
preview: ev.payload.context,
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
case "tool.progress":
|
|
78
|
-
return { kind: "tool.progress", name: ev.payload.name, preview: ev.payload.preview }
|
|
79
|
-
|
|
80
|
-
case "tool.generating":
|
|
81
|
-
return { kind: "tool.generating", name: ev.payload.name }
|
|
82
|
-
|
|
83
|
-
case "tool.complete":
|
|
84
|
-
return {
|
|
85
|
-
kind: "tool.complete",
|
|
86
|
-
id: ev.payload.tool_id,
|
|
87
|
-
summary: ev.payload.summary,
|
|
88
|
-
error: ev.payload.error,
|
|
89
|
-
inline_diff: ev.payload.inline_diff,
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
case "thinking.delta":
|
|
93
|
-
// Cosmetic spinner text from the agent's status line, not model
|
|
94
|
-
// reasoning. Surface as transient status only.
|
|
95
|
-
side.onStatus?.(ev.payload?.text ?? "")
|
|
96
|
-
return null
|
|
97
|
-
|
|
98
|
-
case "reasoning.delta":
|
|
99
|
-
case "reasoning.available": {
|
|
100
|
-
const text = ev.payload?.text
|
|
101
|
-
if (!text) return null
|
|
102
|
-
return { kind: "thinking", text, final: ev.type === "reasoning.available" }
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
case "subagent.start":
|
|
106
|
-
case "subagent.thinking":
|
|
107
|
-
case "subagent.tool":
|
|
108
|
-
case "subagent.progress":
|
|
109
|
-
case "subagent.complete": {
|
|
110
|
-
const sub = ev.type.slice(9) as "start" | "thinking" | "tool" | "progress" | "complete"
|
|
111
|
-
// Feed the turn-wide accumulator so the completed tree can be
|
|
112
|
-
// persisted (spawn_tree.save) and the Agents tab can read live
|
|
113
|
-
// tool trails without its own event listener.
|
|
114
|
-
spawnHistory.record(sub, ev.payload)
|
|
115
|
-
return { kind: "subagent", event: sub, payload: ev.payload }
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
case "error":
|
|
119
|
-
return { kind: "error", text: ev.payload?.message ?? "Unknown error" }
|
|
120
|
-
|
|
121
|
-
case "clarify.request":
|
|
122
|
-
return { kind: "prompt", id: ev.payload.request_id,
|
|
123
|
-
req: { variant: "clarify", ...ev.payload } }
|
|
124
|
-
|
|
125
|
-
case "approval.request":
|
|
126
|
-
// Approval has no request_id upstream — the gateway's approval
|
|
127
|
-
// responder is a single pending slot. Mint a unique part id so
|
|
128
|
-
// multiple approvals in one turn don't alias each other when
|
|
129
|
-
// prompt.answered updates by id.
|
|
130
|
-
return { kind: "prompt", id: `approval-${pid()}`,
|
|
131
|
-
req: { variant: "approval", ...ev.payload } }
|
|
132
|
-
|
|
133
|
-
case "sudo.request":
|
|
134
|
-
return { kind: "prompt", id: ev.payload.request_id,
|
|
135
|
-
req: { variant: "sudo", ...ev.payload } }
|
|
136
|
-
|
|
137
|
-
case "secret.request":
|
|
138
|
-
return { kind: "prompt", id: ev.payload.request_id,
|
|
139
|
-
req: { variant: "secret", ...ev.payload } }
|
|
140
|
-
|
|
141
|
-
case "background.complete":
|
|
142
|
-
side.onBackground?.(ev.payload.task_id, ev.payload.text)
|
|
143
|
-
return null
|
|
144
|
-
|
|
145
|
-
case "review.summary": {
|
|
146
|
-
// Self-improvement background review saved a skill patch or
|
|
147
|
-
// memory entry. Upstream tui_gateway emits this so clients can
|
|
148
|
-
// surface the mutation — without it, the file change happens
|
|
149
|
-
// silently. Python side already formats the text with a 💾
|
|
150
|
-
// prefix, so we pass through verbatim (trimmed). Guard blank
|
|
151
|
-
// payloads: upstream does the same, and a blank system line is
|
|
152
|
-
// noise. No toast — these fire stochastically post-turn and
|
|
153
|
-
// per-event toasting would spam.
|
|
154
|
-
const text = String(ev.payload?.text ?? "").trim()
|
|
155
|
-
if (!text) return null
|
|
156
|
-
return { kind: "system", text }
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
case "btw.complete":
|
|
160
|
-
side.onBtw?.(ev.payload.text)
|
|
161
|
-
return null
|
|
162
|
-
|
|
163
|
-
case "gateway.stderr": {
|
|
164
|
-
// Error-ish stderr lines (tracebacks, HTTP 4xx/5xx, auth failures)
|
|
165
|
-
// surface inline; benign chatter stays in gw.tail() only (/logs).
|
|
166
|
-
const line = ev.payload.line
|
|
167
|
-
if (/error|fail|traceback|exception|\b[45]\d\d\b|refused|denied|unauthori/i.test(line))
|
|
168
|
-
return { kind: "system", text: line.slice(0, 200) }
|
|
169
|
-
return null
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
case "skin.changed":
|
|
173
|
-
side.onSkin?.(ev.payload)
|
|
174
|
-
return null
|
|
175
|
-
|
|
176
|
-
case "gateway.start_timeout":
|
|
177
|
-
return { kind: "error", text: `gateway startup timed out (${ev.payload?.python ?? "python"} @ ${ev.payload?.cwd ?? "?"})` }
|
|
178
|
-
|
|
179
|
-
case "gateway.protocol_error":
|
|
180
|
-
return { kind: "system", text: `protocol error: ${ev.payload?.preview ?? "?"}` }
|
|
181
|
-
|
|
182
|
-
case "browser.progress": {
|
|
183
|
-
// Streamed during /browser connect (upstream e75082901). Surface as
|
|
184
|
-
// transcript rows so long CDP attach work isn't a 60s black box.
|
|
185
|
-
const text = ev.payload?.message ?? ""
|
|
186
|
-
if (!text) return null
|
|
187
|
-
return ev.payload?.level === "error"
|
|
188
|
-
? { kind: "error", text }
|
|
189
|
-
: { kind: "system", text: `· ${text}` }
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
case "status.update": {
|
|
193
|
-
const kind = ev.payload?.kind
|
|
194
|
-
const text = ev.payload?.text ?? ""
|
|
195
|
-
side.onStatus?.(text)
|
|
196
|
-
// Generic "status" is cosmetic; lifecycle/error/warn carry real
|
|
197
|
-
// signal (retries, fallbacks, auth failures) and must persist.
|
|
198
|
-
if (!kind || kind === "status") return null
|
|
199
|
-
return { kind: "system", text }
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return null
|
|
203
|
-
}
|
package/src/app/launch.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// Launch intent parsed from argv before the renderer starts.
|
|
2
|
-
// Bare `herm` → fresh session (splash shows continue-prompt).
|
|
3
|
-
// `-c` / `--continue` / `--resume [id]` → resume, no splash.
|
|
4
|
-
|
|
5
|
-
import pkg from "../../package.json" with { type: "json" }
|
|
6
|
-
|
|
7
|
-
export const VERSION = pkg.version
|
|
8
|
-
|
|
9
|
-
export type Launch =
|
|
10
|
-
| { mode: "new"; splash?: boolean }
|
|
11
|
-
| { mode: "resume"; sid?: string }
|
|
12
|
-
|
|
13
|
-
/** Parse process argv (everything after the script path). No deps. */
|
|
14
|
-
export function parseLaunch(argv: readonly string[]): Launch {
|
|
15
|
-
let splash = true
|
|
16
|
-
for (let i = 0; i < argv.length; i++) {
|
|
17
|
-
const a = argv[i]
|
|
18
|
-
if (a === "--no-splash") { splash = false; continue }
|
|
19
|
-
if (a === "-c" || a === "--continue") return { mode: "resume" }
|
|
20
|
-
if (a === "--resume") {
|
|
21
|
-
const next = argv[i + 1]
|
|
22
|
-
// Treat a following non-flag token as the session id.
|
|
23
|
-
return next && !next.startsWith("-")
|
|
24
|
-
? { mode: "resume", sid: next }
|
|
25
|
-
: { mode: "resume" }
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return { mode: "new", splash }
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const HELP = `\
|
|
32
|
-
herm — OpenTUI client for hermes-agent
|
|
33
|
-
|
|
34
|
-
Usage:
|
|
35
|
-
herm start a fresh session
|
|
36
|
-
herm -c, --continue resume the last real TUI session
|
|
37
|
-
herm --resume [id] resume last (or the given) session
|
|
38
|
-
herm --no-splash skip the launch splash
|
|
39
|
-
herm -v, --version print version
|
|
40
|
-
herm -h, --help show this help
|
|
41
|
-
`
|
package/src/app/skin.tsx
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// Active Hermes skin — branding strings surfaced to UI.
|
|
2
|
-
// The gateway emits skin.changed with the full skin payload;
|
|
3
|
-
// app.tsx reduces it into this context. Consumers read agentName
|
|
4
|
-
// (message headers, announcements) and the raw branding map for
|
|
5
|
-
// future needs (prompt_symbol, welcome, etc.).
|
|
6
|
-
|
|
7
|
-
import { createContext, useContext, memo, type ReactNode } from "react"
|
|
8
|
-
import type { GatewaySkin } from "../utils/gateway-types"
|
|
9
|
-
|
|
10
|
-
export type SkinState = {
|
|
11
|
-
skin?: GatewaySkin
|
|
12
|
-
/** Preferred display label for the assistant in chat. */
|
|
13
|
-
agentName: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const DEFAULT: SkinState = { agentName: "Hermes" }
|
|
17
|
-
|
|
18
|
-
const Ctx = createContext<SkinState>(DEFAULT)
|
|
19
|
-
|
|
20
|
-
export function deriveSkin(skin?: GatewaySkin | null): SkinState {
|
|
21
|
-
const name = skin?.branding?.agent_name?.trim()
|
|
22
|
-
return { skin: skin ?? undefined, agentName: name || "Hermes" }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const SkinProvider = memo(({ value, children }: { value: SkinState; children: ReactNode }) => (
|
|
26
|
-
<Ctx.Provider value={value}>{children}</Ctx.Provider>
|
|
27
|
-
))
|
|
28
|
-
|
|
29
|
-
export function useSkin(): SkinState {
|
|
30
|
-
return useContext(Ctx)
|
|
31
|
-
}
|
package/src/app/spawnHistory.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
// Accumulates subagent.* events across a turn so the completed spawn
|
|
2
|
-
// tree can be persisted via `spawn_tree.save` and later browsed with
|
|
3
|
-
// `spawn_tree.list`/`load`. The accumulator is module-level (one turn
|
|
4
|
-
// runs at a time per session); `flush()` is called from the app-level
|
|
5
|
-
// onTurnComplete side-effect.
|
|
6
|
-
|
|
7
|
-
import type { Gateway } from "./gateway"
|
|
8
|
-
import type { SubagentPayload, SpawnSubagent } from "../utils/gateway-types"
|
|
9
|
-
|
|
10
|
-
type Event = "start" | "thinking" | "tool" | "progress" | "complete"
|
|
11
|
-
|
|
12
|
-
const TRAIL_MAX = 20
|
|
13
|
-
const acc = new Map<string, SpawnSubagent>()
|
|
14
|
-
|
|
15
|
-
export function record(ev: Event, p: SubagentPayload): void {
|
|
16
|
-
const id = p.subagent_id
|
|
17
|
-
if (!id) return
|
|
18
|
-
const now = Date.now() / 1000
|
|
19
|
-
|
|
20
|
-
if (ev === "start") {
|
|
21
|
-
acc.set(id, {
|
|
22
|
-
subagent_id: id,
|
|
23
|
-
parent_id: p.parent_id ?? null,
|
|
24
|
-
depth: p.depth ?? 0,
|
|
25
|
-
goal: p.goal,
|
|
26
|
-
model: p.model,
|
|
27
|
-
started_at: now,
|
|
28
|
-
tool_count: 0,
|
|
29
|
-
status: "running",
|
|
30
|
-
trail: [],
|
|
31
|
-
})
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const r = acc.get(id)
|
|
36
|
-
if (!r) return
|
|
37
|
-
|
|
38
|
-
if (ev === "tool" && p.tool_name) {
|
|
39
|
-
r.tool_count++
|
|
40
|
-
r.trail = [...(r.trail ?? []), { name: p.tool_name, preview: p.tool_preview }].slice(-TRAIL_MAX)
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (ev === "complete") {
|
|
45
|
-
r.status = p.status ?? "completed"
|
|
46
|
-
r.finished_at = now
|
|
47
|
-
r.input_tokens = p.input_tokens
|
|
48
|
-
r.output_tokens = p.output_tokens
|
|
49
|
-
r.cost_usd = p.cost_usd
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Live read for the Agents-tab detail panel (running children only). */
|
|
54
|
-
export function trail(id: string): ReadonlyArray<{ name: string; preview?: string }> {
|
|
55
|
-
return acc.get(id)?.trail ?? []
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Persist the turn's tree (best-effort) and clear the accumulator. */
|
|
59
|
-
export function flush(gw: Gateway, sessionId: string): void {
|
|
60
|
-
if (acc.size === 0) return
|
|
61
|
-
const subagents = [...acc.values()]
|
|
62
|
-
acc.clear()
|
|
63
|
-
|
|
64
|
-
const roots = subagents.filter(s => s.parent_id == null)
|
|
65
|
-
const label = (roots.slice(0, 2).map(s => s.goal).join(" · ") || `${subagents.length} subagents`).slice(0, 120)
|
|
66
|
-
const started = Math.min(...subagents.map(s => s.started_at))
|
|
67
|
-
|
|
68
|
-
gw.request("spawn_tree.save", {
|
|
69
|
-
session_id: sessionId,
|
|
70
|
-
label,
|
|
71
|
-
started_at: started,
|
|
72
|
-
finished_at: Date.now() / 1000,
|
|
73
|
-
subagents,
|
|
74
|
-
}).catch(() => {})
|
|
75
|
-
}
|
package/src/app/tabs.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export const TABS = [
|
|
2
|
-
{ name: "Chat", description: "Main chat interface" },
|
|
3
|
-
{ name: "Context", description: "Context and session info" },
|
|
4
|
-
{ name: "Sessions", description: "Session history" },
|
|
5
|
-
{ name: "Agents", description: "Profiles and running subagents" },
|
|
6
|
-
{ name: "Analytics", description: "Token usage and costs" },
|
|
7
|
-
{ name: "Skills", description: "Installed skills browser" },
|
|
8
|
-
{ name: "Cron", description: "Scheduled job manager" },
|
|
9
|
-
{ name: "Toolsets", description: "Available toolsets manager" },
|
|
10
|
-
{ name: "Config", description: "Configuration editor" },
|
|
11
|
-
{ name: "Env", description: "API keys & env variables" },
|
|
12
|
-
{ name: "Memory", description: "Agent memory browser" },
|
|
13
|
-
{ name: "Kanban", description: "Multi-agent task board" },
|
|
14
|
-
] as const
|
|
15
|
-
|
|
16
|
-
export const TAB_MAX = TABS.length - 1
|
|
17
|
-
export const CHAT_TAB = 0
|
|
18
|
-
|
|
19
|
-
/** Slash-command names that jump to a tab (F5.3). */
|
|
20
|
-
export const TAB_SLASH: Record<string, number> = Object.fromEntries(
|
|
21
|
-
TABS.map((t, i) => [t.name.toLowerCase(), i]),
|
|
22
|
-
)
|
|
23
|
-
TAB_SLASH.insights = TAB_SLASH.analytics
|