open-multi-agent-kit 0.92.0 → 0.93.0
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/CHANGELOG.md +15 -0
- package/README.md +2 -2
- package/dist/core/agent-session.d.ts +29 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +81 -14
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +5 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +5 -7
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +12 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +28 -15
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/builtin/command-safety-gate.d.ts +8 -0
- package/dist/core/extensions/builtin/command-safety-gate.d.ts.map +1 -1
- package/dist/core/extensions/builtin/command-safety-gate.js +23 -0
- package/dist/core/extensions/builtin/command-safety-gate.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +4 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +5 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-resolver.d.ts +41 -3
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +17 -9
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +3 -1
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/reasoning-router-v4-weights.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4-weights.js +9 -3
- package/dist/core/reasoning-router-v4-weights.js.map +1 -1
- package/dist/core/reasoning-router-v4.d.ts.map +1 -1
- package/dist/core/reasoning-router-v4.js +94 -24
- package/dist/core/reasoning-router-v4.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +11 -5
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-file-compaction.d.ts.map +1 -1
- package/dist/core/session-file-compaction.js +39 -5
- package/dist/core/session-file-compaction.js.map +1 -1
- package/dist/core/session-termination.d.ts.map +1 -1
- package/dist/core/session-termination.js +1 -1
- package/dist/core/session-termination.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +38 -11
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-box.d.ts +27 -0
- package/dist/modes/interactive/components/control-panel-box.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-box.js +60 -8
- package/dist/modes/interactive/components/control-panel-box.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-layout.js +100 -45
- package/dist/modes/interactive/components/control-panel-layout.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-runtime-status.d.ts +9 -0
- package/dist/modes/interactive/components/control-panel-runtime-status.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-runtime-status.js +10 -8
- package/dist/modes/interactive/components/control-panel-runtime-status.js.map +1 -1
- package/dist/modes/interactive/components/control-panel-sparkles.d.ts +5 -0
- package/dist/modes/interactive/components/control-panel-sparkles.d.ts.map +1 -1
- package/dist/modes/interactive/components/control-panel-sparkles.js +14 -9
- package/dist/modes/interactive/components/control-panel-sparkles.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +10 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +3 -3
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/status-sidebar.d.ts +49 -0
- package/dist/modes/interactive/components/status-sidebar.d.ts.map +1 -0
- package/dist/modes/interactive/components/status-sidebar.js +253 -0
- package/dist/modes/interactive/components/status-sidebar.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +9 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +94 -20
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/omk-neon-control.json +13 -13
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +19 -8
- package/dist/utils/clipboard.js.map +1 -1
- package/docs/compaction.md +7 -0
- package/docs/docs.json +4 -0
- package/docs/environment-variables.md +90 -0
- package/docs/index.md +1 -0
- package/docs/rpc.md +5 -2
- package/docs/settings.md +1 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/agents.test.ts +86 -0
- package/examples/extensions/subagent/agents.ts +18 -4
- package/examples/extensions/subagent/capabilities.ts +15 -1
- package/examples/extensions/subagent/domain-profiles.ts +272 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +15 -15
- package/package.json +10 -7
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { truncateToWidth, visibleWidth } from "omk-tui";
|
|
2
|
+
import { loadMcpInventory } from "../../../core/mcp-inventory.js";
|
|
3
|
+
import { theme } from "../theme/theme.js";
|
|
4
|
+
import { boxBottom, boxTextLine, boxTop, sidebarRule } from "./control-panel-box.js";
|
|
5
|
+
import { classifyMcpStability } from "./control-panel-runtime-status.js";
|
|
6
|
+
import { formatBytes, formatCwdForFooter, formatPackageIntake, formatTokens } from "./footer.js";
|
|
7
|
+
import { keyText } from "./keybinding-hints.js";
|
|
8
|
+
export const STATUS_SIDEBAR_WIDTH = 34;
|
|
9
|
+
export const STATUS_SIDEBAR_MAX_WIDTH = 48;
|
|
10
|
+
export const STATUS_SIDEBAR_MIN_WIDTH = 96;
|
|
11
|
+
/** Blank columns between the main content and the pinned rail (part of the reserved gutter). */
|
|
12
|
+
export const STATUS_SIDEBAR_GUTTER_GAP = 1;
|
|
13
|
+
/**
|
|
14
|
+
* Responsive rail width: ~26% of the terminal, clamped to [34, 48] so the rail
|
|
15
|
+
* grows on fullscreen terminals while the content column stays dominant.
|
|
16
|
+
* The pinned overlay and the reserved gutter must both use this function.
|
|
17
|
+
*/
|
|
18
|
+
export function statusSidebarWidth(termWidth) {
|
|
19
|
+
return Math.max(STATUS_SIDEBAR_WIDTH, Math.min(STATUS_SIDEBAR_MAX_WIDTH, Math.floor(termWidth * 0.26)));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Responsive MCP roster rows: taller terminals list more servers before the
|
|
23
|
+
* "+N more" collapse. ~24 rows of the rail are fixed chrome (header, model,
|
|
24
|
+
* context, tokens, system), the rest is available to the roster.
|
|
25
|
+
*/
|
|
26
|
+
export function mcpMaxRows(termRows) {
|
|
27
|
+
return Math.max(4, Math.min(18, termRows - 24));
|
|
28
|
+
}
|
|
29
|
+
const METER_CELLS = 12;
|
|
30
|
+
const METER_MAX_CELLS = 24;
|
|
31
|
+
/** Rolling window of CPU samples feeding the activity sparkline (wide rails show more history). */
|
|
32
|
+
const SPARK_WINDOW = 44;
|
|
33
|
+
/** Minimum interval between sparkline samples so the rail animates, not jitters. */
|
|
34
|
+
const SPARK_SAMPLE_MS = 1000;
|
|
35
|
+
/** MCP inventory is read from disk; cache it so per-frame renders stay cheap. */
|
|
36
|
+
const MCP_CACHE_TTL_MS = 5000;
|
|
37
|
+
const SPARK_CHARS = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
|
|
38
|
+
/**
|
|
39
|
+
* Fixed right-rail sidebar that shows the bottom-bar (footer) status vertically,
|
|
40
|
+
* styled after opencode's pinned side rails plus a live MCP server roster.
|
|
41
|
+
*
|
|
42
|
+
* Pinned via the `pinStatusSidebar` setting (or OMK_PIN_STATUS_SIDEBAR=1) and
|
|
43
|
+
* toggled with app.sidebar.toggle (Ctrl+Q). While pinned, the bottom footer is
|
|
44
|
+
* removed so the same data is not rendered twice.
|
|
45
|
+
*/
|
|
46
|
+
export class StatusSidebarComponent {
|
|
47
|
+
getSession;
|
|
48
|
+
footerData;
|
|
49
|
+
getAutoCompactEnabled;
|
|
50
|
+
getTerminalRows;
|
|
51
|
+
// --- living elements: rolling CPU sparkline + cached MCP roster ---
|
|
52
|
+
cpuHistory = [];
|
|
53
|
+
lastSparkSampleAt = 0;
|
|
54
|
+
mcpCache;
|
|
55
|
+
constructor(getSession, footerData, getAutoCompactEnabled, getTerminalRows = () => 32) {
|
|
56
|
+
this.getSession = getSession;
|
|
57
|
+
this.footerData = footerData;
|
|
58
|
+
this.getAutoCompactEnabled = getAutoCompactEnabled;
|
|
59
|
+
this.getTerminalRows = getTerminalRows;
|
|
60
|
+
}
|
|
61
|
+
invalidate() {
|
|
62
|
+
// Mostly stateless: status recomputes from the live session each render.
|
|
63
|
+
// Only the sparkline history and MCP cache persist across frames.
|
|
64
|
+
}
|
|
65
|
+
render(width) {
|
|
66
|
+
const session = this.getSession();
|
|
67
|
+
const state = session.state;
|
|
68
|
+
const lines = [boxTop(width, "STATUS RAIL")];
|
|
69
|
+
// --- Live header: session uptime + CPU activity sparkline ---
|
|
70
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "up ")}${theme.fg("accent", formatUptime(process.uptime()))}`));
|
|
71
|
+
lines.push(boxTextLine(width, this.sparkline(width)));
|
|
72
|
+
// --- Location ---
|
|
73
|
+
const cwd = formatCwdForFooter(session.sessionManager.getCwd(), process.env.HOME || process.env.USERPROFILE);
|
|
74
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "cwd ")}${theme.fg("text", cwd)}`));
|
|
75
|
+
const branch = this.footerData.getGitBranch();
|
|
76
|
+
if (branch) {
|
|
77
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "git ")}${theme.fg("accent", branch)}`));
|
|
78
|
+
}
|
|
79
|
+
const sessionName = session.sessionManager.getSessionName();
|
|
80
|
+
if (sessionName) {
|
|
81
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "sess ")}${theme.fg("text", sessionName)}`));
|
|
82
|
+
}
|
|
83
|
+
// --- Model ---
|
|
84
|
+
lines.push(sidebarRule(width, "MODEL"));
|
|
85
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "id ")}${theme.fg("accent", state.model?.id ?? "no-model")}`));
|
|
86
|
+
if (state.model?.reasoning) {
|
|
87
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "think ")}${theme.fg("mdCode", state.thinkingLevel || "off")}`));
|
|
88
|
+
}
|
|
89
|
+
// --- Context ---
|
|
90
|
+
lines.push(sidebarRule(width, "CONTEXT"));
|
|
91
|
+
const contextUsage = session.getContextUsage();
|
|
92
|
+
const contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;
|
|
93
|
+
const percent = contextUsage?.percent ?? null;
|
|
94
|
+
const auto = this.getAutoCompactEnabled() ? " (auto)" : "";
|
|
95
|
+
const percentLabel = percent === null
|
|
96
|
+
? `?/${formatTokens(contextWindow)}${auto}`
|
|
97
|
+
: `${percent.toFixed(1)}%/${formatTokens(contextWindow)}${auto}`;
|
|
98
|
+
const percentColor = percent !== null && percent > 90 ? "error" : percent !== null && percent > 70 ? "warning" : "success";
|
|
99
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "ctx ")}${theme.fg(percentColor, percentLabel)}`));
|
|
100
|
+
lines.push(boxTextLine(width, meter(percent, width)));
|
|
101
|
+
// --- Tokens (cumulative across all session entries, mirrors the footer) ---
|
|
102
|
+
let totalInput = 0;
|
|
103
|
+
let totalOutput = 0;
|
|
104
|
+
let totalCacheRead = 0;
|
|
105
|
+
let totalCacheWrite = 0;
|
|
106
|
+
let totalCost = 0;
|
|
107
|
+
for (const entry of session.sessionManager.getEntries()) {
|
|
108
|
+
if (entry.type === "message" && entry.message.role === "assistant") {
|
|
109
|
+
totalInput += entry.message.usage.input;
|
|
110
|
+
totalOutput += entry.message.usage.output;
|
|
111
|
+
totalCacheRead += entry.message.usage.cacheRead;
|
|
112
|
+
totalCacheWrite += entry.message.usage.cacheWrite;
|
|
113
|
+
totalCost += entry.message.usage.cost.total;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
lines.push(sidebarRule(width, "TOKENS"));
|
|
117
|
+
lines.push(boxTextLine(width, `${theme.fg("success", `↑${formatTokens(totalInput)}`)} ${theme.fg("accent", `↓${formatTokens(totalOutput)}`)}`));
|
|
118
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", `R${formatTokens(totalCacheRead)}`)} ${theme.fg("muted", `W${formatTokens(totalCacheWrite)}`)}`));
|
|
119
|
+
const usingSubscription = state.model ? session.modelRegistry.isUsingOAuth(state.model) : false;
|
|
120
|
+
if (totalCost || usingSubscription) {
|
|
121
|
+
lines.push(boxTextLine(width, `${theme.fg("muted", "cost ")}${theme.fg("warning", `$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`)}`));
|
|
122
|
+
}
|
|
123
|
+
// --- MCP roster (opencode-style server list with stability dots) ---
|
|
124
|
+
lines.push(...this.mcpSection(width, session.sessionManager.getCwd()));
|
|
125
|
+
// --- System ---
|
|
126
|
+
lines.push(sidebarRule(width, "SYSTEM"));
|
|
127
|
+
const cpu = this.footerData.getCpuPercent();
|
|
128
|
+
const mem = this.footerData.getMemoryRssBytes();
|
|
129
|
+
const sysParts = [];
|
|
130
|
+
if (cpu !== null)
|
|
131
|
+
sysParts.push(`cpu ${cpu.toFixed(0)}%`);
|
|
132
|
+
if (mem !== null)
|
|
133
|
+
sysParts.push(`mem ${formatBytes(mem)}`);
|
|
134
|
+
if (sysParts.length > 0) {
|
|
135
|
+
lines.push(boxTextLine(width, theme.fg("muted", sysParts.join(" "))));
|
|
136
|
+
}
|
|
137
|
+
lines.push(boxTextLine(width, theme.fg("dim", formatPackageIntake(this.footerData.getPackageIntakeSummary()))));
|
|
138
|
+
// --- Extension statuses ---
|
|
139
|
+
const statuses = this.footerData.getExtensionStatuses();
|
|
140
|
+
if (statuses.size > 0) {
|
|
141
|
+
lines.push(sidebarRule(width, "EXT"));
|
|
142
|
+
for (const [key, value] of statuses) {
|
|
143
|
+
lines.push(boxTextLine(width, `${theme.fg("mdCode", key)} ${theme.fg("muted", value)}`));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
lines.push(boxTextLine(width, theme.fg("dim", `${keyText("app.sidebar.toggle")} unpin`)));
|
|
147
|
+
lines.push(boxBottom(width));
|
|
148
|
+
return lines;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* MCP server roster with a stable/total counter in the section rule and a
|
|
152
|
+
* stability dot per server. Reads are cached so the rail stays cheap to render.
|
|
153
|
+
*/
|
|
154
|
+
mcpSection(width, cwd) {
|
|
155
|
+
const entries = this.loadMcpEntries(cwd);
|
|
156
|
+
const stable = entries.filter((entry) => classifyMcpStability(entry) === "stable").length;
|
|
157
|
+
const countColor = entries.length === 0 ? "dim" : stable === entries.length ? "success" : "warning";
|
|
158
|
+
const count = entries.length === 0 ? "0" : `${stable}/${entries.length}`;
|
|
159
|
+
const lines = [railRule(width, "MCP", theme.fg(countColor, count))];
|
|
160
|
+
if (entries.length === 0) {
|
|
161
|
+
lines.push(boxTextLine(width, theme.fg("dim", "none configured")));
|
|
162
|
+
return lines;
|
|
163
|
+
}
|
|
164
|
+
const shown = entries.slice(0, mcpMaxRows(this.getTerminalRows()));
|
|
165
|
+
for (const entry of shown) {
|
|
166
|
+
lines.push(boxTextLine(width, mcpRow(entry, width)));
|
|
167
|
+
}
|
|
168
|
+
const hidden = entries.length - shown.length;
|
|
169
|
+
if (hidden > 0) {
|
|
170
|
+
lines.push(boxTextLine(width, theme.fg("dim", `+${hidden} more…`)));
|
|
171
|
+
}
|
|
172
|
+
return lines;
|
|
173
|
+
}
|
|
174
|
+
loadMcpEntries(cwd) {
|
|
175
|
+
const now = Date.now();
|
|
176
|
+
if (this.mcpCache && this.mcpCache.cwd === cwd && now - this.mcpCache.at < MCP_CACHE_TTL_MS) {
|
|
177
|
+
return this.mcpCache.entries;
|
|
178
|
+
}
|
|
179
|
+
let entries = [];
|
|
180
|
+
try {
|
|
181
|
+
entries = loadMcpInventory(cwd).entries;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
entries = [];
|
|
185
|
+
}
|
|
186
|
+
this.mcpCache = { at: now, cwd, entries };
|
|
187
|
+
return entries;
|
|
188
|
+
}
|
|
189
|
+
/** Rolling CPU sparkline — a living pulse along the top of the rail. */
|
|
190
|
+
sparkline(width) {
|
|
191
|
+
const now = Date.now();
|
|
192
|
+
const cpu = this.footerData.getCpuPercent();
|
|
193
|
+
if (cpu !== null && now - this.lastSparkSampleAt >= SPARK_SAMPLE_MS) {
|
|
194
|
+
this.lastSparkSampleAt = now;
|
|
195
|
+
this.cpuHistory.push(Math.max(0, Math.min(100, cpu)));
|
|
196
|
+
if (this.cpuHistory.length > SPARK_WINDOW) {
|
|
197
|
+
this.cpuHistory.shift();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const inner = Math.max(0, width - 4);
|
|
201
|
+
const label = theme.fg("muted", "act ");
|
|
202
|
+
const cells = Math.max(0, inner - visibleWidth(label));
|
|
203
|
+
if (cells === 0 || this.cpuHistory.length === 0) {
|
|
204
|
+
return `${label}${theme.fg("borderMuted", "▁".repeat(Math.max(0, cells)))}`;
|
|
205
|
+
}
|
|
206
|
+
// Right-align the window so the sparkline grows in from the left edge.
|
|
207
|
+
const window = this.cpuHistory.slice(-cells);
|
|
208
|
+
const bars = window.map((sample) => SPARK_CHARS[Math.min(7, Math.floor(sample / 12.6))]).join("");
|
|
209
|
+
const pad = "▁".repeat(Math.max(0, cells - window.length));
|
|
210
|
+
return `${label}${theme.fg("borderMuted", pad)}${theme.fg("accent", bars)}`;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** Section rule with a right-aligned counter, e.g. `│─ MCP ─────── 22/24 │`. */
|
|
214
|
+
function railRule(width, label, right) {
|
|
215
|
+
const left = `${theme.fg("borderMuted", "─")}${theme.fg("accent", ` ${label} `)}`;
|
|
216
|
+
const rightText = ` ${right} `;
|
|
217
|
+
const fill = Math.max(0, width - 2 - visibleWidth(left) - visibleWidth(rightText));
|
|
218
|
+
const line = `${theme.fg("borderMuted", "│")}${left}${theme.fg("borderMuted", "─".repeat(fill))}${rightText}${theme.fg("borderMuted", "│")}`;
|
|
219
|
+
return visibleWidth(line) <= width ? line : truncateToWidth(line, width, "");
|
|
220
|
+
}
|
|
221
|
+
/** One MCP server row: stability dot + name, truncated to the rail width. */
|
|
222
|
+
function mcpRow(entry, width) {
|
|
223
|
+
const stability = classifyMcpStability(entry);
|
|
224
|
+
const dot = stability === "stable"
|
|
225
|
+
? theme.fg("success", "●")
|
|
226
|
+
: stability === "overridden"
|
|
227
|
+
? theme.fg("dim", "◐")
|
|
228
|
+
: theme.fg("warning", "○");
|
|
229
|
+
const nameColor = stability === "stable" ? "text" : stability === "overridden" ? "dim" : "warning";
|
|
230
|
+
const nameWidth = Math.max(1, width - 4 - 2); // frame (4) + dot + space (2)
|
|
231
|
+
const name = truncateToWidth(entry.name, nameWidth, "…");
|
|
232
|
+
return `${dot} ${theme.fg(nameColor, name)}`;
|
|
233
|
+
}
|
|
234
|
+
function formatUptime(seconds) {
|
|
235
|
+
const total = Math.max(0, Math.floor(seconds));
|
|
236
|
+
const h = Math.floor(total / 3600);
|
|
237
|
+
const m = Math.floor((total % 3600) / 60);
|
|
238
|
+
const s = total % 60;
|
|
239
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
240
|
+
return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${pad(m)}:${pad(s)}`;
|
|
241
|
+
}
|
|
242
|
+
function meter(percent, width) {
|
|
243
|
+
// Fill the rail: frame (4) + space + up to "100%" (4) stay reserved.
|
|
244
|
+
const cells = Math.max(METER_CELLS, Math.min(METER_MAX_CELLS, width - 9));
|
|
245
|
+
if (percent === null) {
|
|
246
|
+
return `${theme.fg("borderMuted", "░".repeat(cells))} ${theme.fg("muted", "??%")}`;
|
|
247
|
+
}
|
|
248
|
+
const clamped = Math.max(0, Math.min(100, percent));
|
|
249
|
+
const filled = Math.round((clamped / 100) * cells);
|
|
250
|
+
const color = clamped >= 85 ? "warning" : clamped >= 65 ? "mdCode" : "success";
|
|
251
|
+
return `${theme.fg(color, "█".repeat(filled))}${theme.fg("borderMuted", "░".repeat(cells - filled))} ${theme.fg(color, `${Math.round(clamped)}%`)}`;
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=status-sidebar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-sidebar.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/status-sidebar.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Component } from \"omk-tui\";\nimport { truncateToWidth, visibleWidth } from \"omk-tui\";\nimport type { AgentSession } from \"../../../core/agent-session.ts\";\nimport type { ReadonlyFooterDataProvider } from \"../../../core/footer-data-provider.ts\";\nimport { loadMcpInventory, type McpServerEntry } from \"../../../core/mcp-inventory.ts\";\nimport { type ThemeColor, theme } from \"../theme/theme.ts\";\nimport { boxBottom, boxTextLine, boxTop, sidebarRule } from \"./control-panel-box.ts\";\nimport { classifyMcpStability } from \"./control-panel-runtime-status.ts\";\nimport { formatBytes, formatCwdForFooter, formatPackageIntake, formatTokens } from \"./footer.ts\";\nimport { keyText } from \"./keybinding-hints.ts\";\n\nexport const STATUS_SIDEBAR_WIDTH = 34;\nexport const STATUS_SIDEBAR_MAX_WIDTH = 48;\nexport const STATUS_SIDEBAR_MIN_WIDTH = 96;\n/** Blank columns between the main content and the pinned rail (part of the reserved gutter). */\nexport const STATUS_SIDEBAR_GUTTER_GAP = 1;\n\n/**\n * Responsive rail width: ~26% of the terminal, clamped to [34, 48] so the rail\n * grows on fullscreen terminals while the content column stays dominant.\n * The pinned overlay and the reserved gutter must both use this function.\n */\nexport function statusSidebarWidth(termWidth: number): number {\n\treturn Math.max(STATUS_SIDEBAR_WIDTH, Math.min(STATUS_SIDEBAR_MAX_WIDTH, Math.floor(termWidth * 0.26)));\n}\n\n/**\n * Responsive MCP roster rows: taller terminals list more servers before the\n * \"+N more\" collapse. ~24 rows of the rail are fixed chrome (header, model,\n * context, tokens, system), the rest is available to the roster.\n */\nexport function mcpMaxRows(termRows: number): number {\n\treturn Math.max(4, Math.min(18, termRows - 24));\n}\n\nconst METER_CELLS = 12;\nconst METER_MAX_CELLS = 24;\n/** Rolling window of CPU samples feeding the activity sparkline (wide rails show more history). */\nconst SPARK_WINDOW = 44;\n/** Minimum interval between sparkline samples so the rail animates, not jitters. */\nconst SPARK_SAMPLE_MS = 1000;\n/** MCP inventory is read from disk; cache it so per-frame renders stay cheap. */\nconst MCP_CACHE_TTL_MS = 5000;\n\nconst SPARK_CHARS = [\"▁\", \"▂\", \"▃\", \"▄\", \"▅\", \"▆\", \"▇\", \"█\"] as const;\n\n/**\n * Fixed right-rail sidebar that shows the bottom-bar (footer) status vertically,\n * styled after opencode's pinned side rails plus a live MCP server roster.\n *\n * Pinned via the `pinStatusSidebar` setting (or OMK_PIN_STATUS_SIDEBAR=1) and\n * toggled with app.sidebar.toggle (Ctrl+Q). While pinned, the bottom footer is\n * removed so the same data is not rendered twice.\n */\nexport class StatusSidebarComponent implements Component {\n\tprivate getSession: () => AgentSession;\n\tprivate footerData: ReadonlyFooterDataProvider;\n\tprivate getAutoCompactEnabled: () => boolean;\n\tprivate getTerminalRows: () => number;\n\n\t// --- living elements: rolling CPU sparkline + cached MCP roster ---\n\tprivate cpuHistory: number[] = [];\n\tprivate lastSparkSampleAt = 0;\n\tprivate mcpCache: { at: number; cwd: string; entries: McpServerEntry[] } | undefined;\n\n\tconstructor(\n\t\tgetSession: () => AgentSession,\n\t\tfooterData: ReadonlyFooterDataProvider,\n\t\tgetAutoCompactEnabled: () => boolean,\n\t\tgetTerminalRows: () => number = () => 32,\n\t) {\n\t\tthis.getSession = getSession;\n\t\tthis.footerData = footerData;\n\t\tthis.getAutoCompactEnabled = getAutoCompactEnabled;\n\t\tthis.getTerminalRows = getTerminalRows;\n\t}\n\n\tinvalidate(): void {\n\t\t// Mostly stateless: status recomputes from the live session each render.\n\t\t// Only the sparkline history and MCP cache persist across frames.\n\t}\n\n\trender(width: number): string[] {\n\t\tconst session = this.getSession();\n\t\tconst state = session.state;\n\t\tconst lines: string[] = [boxTop(width, \"STATUS RAIL\")];\n\n\t\t// --- Live header: session uptime + CPU activity sparkline ---\n\t\tlines.push(\n\t\t\tboxTextLine(width, `${theme.fg(\"muted\", \"up \")}${theme.fg(\"accent\", formatUptime(process.uptime()))}`),\n\t\t);\n\t\tlines.push(boxTextLine(width, this.sparkline(width)));\n\n\t\t// --- Location ---\n\t\tconst cwd = formatCwdForFooter(session.sessionManager.getCwd(), process.env.HOME || process.env.USERPROFILE);\n\t\tlines.push(boxTextLine(width, `${theme.fg(\"muted\", \"cwd \")}${theme.fg(\"text\", cwd)}`));\n\t\tconst branch = this.footerData.getGitBranch();\n\t\tif (branch) {\n\t\t\tlines.push(boxTextLine(width, `${theme.fg(\"muted\", \"git \")}${theme.fg(\"accent\", branch)}`));\n\t\t}\n\t\tconst sessionName = session.sessionManager.getSessionName();\n\t\tif (sessionName) {\n\t\t\tlines.push(boxTextLine(width, `${theme.fg(\"muted\", \"sess \")}${theme.fg(\"text\", sessionName)}`));\n\t\t}\n\n\t\t// --- Model ---\n\t\tlines.push(sidebarRule(width, \"MODEL\"));\n\t\tlines.push(\n\t\t\tboxTextLine(width, `${theme.fg(\"muted\", \"id \")}${theme.fg(\"accent\", state.model?.id ?? \"no-model\")}`),\n\t\t);\n\t\tif (state.model?.reasoning) {\n\t\t\tlines.push(\n\t\t\t\tboxTextLine(width, `${theme.fg(\"muted\", \"think \")}${theme.fg(\"mdCode\", state.thinkingLevel || \"off\")}`),\n\t\t\t);\n\t\t}\n\n\t\t// --- Context ---\n\t\tlines.push(sidebarRule(width, \"CONTEXT\"));\n\t\tconst contextUsage = session.getContextUsage();\n\t\tconst contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;\n\t\tconst percent = contextUsage?.percent ?? null;\n\t\tconst auto = this.getAutoCompactEnabled() ? \" (auto)\" : \"\";\n\t\tconst percentLabel =\n\t\t\tpercent === null\n\t\t\t\t? `?/${formatTokens(contextWindow)}${auto}`\n\t\t\t\t: `${percent.toFixed(1)}%/${formatTokens(contextWindow)}${auto}`;\n\t\tconst percentColor: ThemeColor =\n\t\t\tpercent !== null && percent > 90 ? \"error\" : percent !== null && percent > 70 ? \"warning\" : \"success\";\n\t\tlines.push(boxTextLine(width, `${theme.fg(\"muted\", \"ctx \")}${theme.fg(percentColor, percentLabel)}`));\n\t\tlines.push(boxTextLine(width, meter(percent, width)));\n\n\t\t// --- Tokens (cumulative across all session entries, mirrors the footer) ---\n\t\tlet totalInput = 0;\n\t\tlet totalOutput = 0;\n\t\tlet totalCacheRead = 0;\n\t\tlet totalCacheWrite = 0;\n\t\tlet totalCost = 0;\n\t\tfor (const entry of session.sessionManager.getEntries()) {\n\t\t\tif (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\t\ttotalInput += entry.message.usage.input;\n\t\t\t\ttotalOutput += entry.message.usage.output;\n\t\t\t\ttotalCacheRead += entry.message.usage.cacheRead;\n\t\t\t\ttotalCacheWrite += entry.message.usage.cacheWrite;\n\t\t\t\ttotalCost += entry.message.usage.cost.total;\n\t\t\t}\n\t\t}\n\t\tlines.push(sidebarRule(width, \"TOKENS\"));\n\t\tlines.push(\n\t\t\tboxTextLine(\n\t\t\t\twidth,\n\t\t\t\t`${theme.fg(\"success\", `↑${formatTokens(totalInput)}`)} ${theme.fg(\"accent\", `↓${formatTokens(totalOutput)}`)}`,\n\t\t\t),\n\t\t);\n\t\tlines.push(\n\t\t\tboxTextLine(\n\t\t\t\twidth,\n\t\t\t\t`${theme.fg(\"muted\", `R${formatTokens(totalCacheRead)}`)} ${theme.fg(\"muted\", `W${formatTokens(totalCacheWrite)}`)}`,\n\t\t\t),\n\t\t);\n\t\tconst usingSubscription = state.model ? session.modelRegistry.isUsingOAuth(state.model) : false;\n\t\tif (totalCost || usingSubscription) {\n\t\t\tlines.push(\n\t\t\t\tboxTextLine(\n\t\t\t\t\twidth,\n\t\t\t\t\t`${theme.fg(\"muted\", \"cost \")}${theme.fg(\"warning\", `$${totalCost.toFixed(3)}${usingSubscription ? \" (sub)\" : \"\"}`)}`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// --- MCP roster (opencode-style server list with stability dots) ---\n\t\tlines.push(...this.mcpSection(width, session.sessionManager.getCwd()));\n\n\t\t// --- System ---\n\t\tlines.push(sidebarRule(width, \"SYSTEM\"));\n\t\tconst cpu = this.footerData.getCpuPercent();\n\t\tconst mem = this.footerData.getMemoryRssBytes();\n\t\tconst sysParts: string[] = [];\n\t\tif (cpu !== null) sysParts.push(`cpu ${cpu.toFixed(0)}%`);\n\t\tif (mem !== null) sysParts.push(`mem ${formatBytes(mem)}`);\n\t\tif (sysParts.length > 0) {\n\t\t\tlines.push(boxTextLine(width, theme.fg(\"muted\", sysParts.join(\" \"))));\n\t\t}\n\t\tlines.push(boxTextLine(width, theme.fg(\"dim\", formatPackageIntake(this.footerData.getPackageIntakeSummary()))));\n\n\t\t// --- Extension statuses ---\n\t\tconst statuses = this.footerData.getExtensionStatuses();\n\t\tif (statuses.size > 0) {\n\t\t\tlines.push(sidebarRule(width, \"EXT\"));\n\t\t\tfor (const [key, value] of statuses) {\n\t\t\t\tlines.push(boxTextLine(width, `${theme.fg(\"mdCode\", key)} ${theme.fg(\"muted\", value)}`));\n\t\t\t}\n\t\t}\n\n\t\tlines.push(boxTextLine(width, theme.fg(\"dim\", `${keyText(\"app.sidebar.toggle\")} unpin`)));\n\t\tlines.push(boxBottom(width));\n\t\treturn lines;\n\t}\n\n\t/**\n\t * MCP server roster with a stable/total counter in the section rule and a\n\t * stability dot per server. Reads are cached so the rail stays cheap to render.\n\t */\n\tprivate mcpSection(width: number, cwd: string): string[] {\n\t\tconst entries = this.loadMcpEntries(cwd);\n\t\tconst stable = entries.filter((entry) => classifyMcpStability(entry) === \"stable\").length;\n\t\tconst countColor: ThemeColor = entries.length === 0 ? \"dim\" : stable === entries.length ? \"success\" : \"warning\";\n\t\tconst count = entries.length === 0 ? \"0\" : `${stable}/${entries.length}`;\n\n\t\tconst lines: string[] = [railRule(width, \"MCP\", theme.fg(countColor, count))];\n\t\tif (entries.length === 0) {\n\t\t\tlines.push(boxTextLine(width, theme.fg(\"dim\", \"none configured\")));\n\t\t\treturn lines;\n\t\t}\n\n\t\tconst shown = entries.slice(0, mcpMaxRows(this.getTerminalRows()));\n\t\tfor (const entry of shown) {\n\t\t\tlines.push(boxTextLine(width, mcpRow(entry, width)));\n\t\t}\n\t\tconst hidden = entries.length - shown.length;\n\t\tif (hidden > 0) {\n\t\t\tlines.push(boxTextLine(width, theme.fg(\"dim\", `+${hidden} more…`)));\n\t\t}\n\t\treturn lines;\n\t}\n\n\tprivate loadMcpEntries(cwd: string): McpServerEntry[] {\n\t\tconst now = Date.now();\n\t\tif (this.mcpCache && this.mcpCache.cwd === cwd && now - this.mcpCache.at < MCP_CACHE_TTL_MS) {\n\t\t\treturn this.mcpCache.entries;\n\t\t}\n\t\tlet entries: McpServerEntry[] = [];\n\t\ttry {\n\t\t\tentries = loadMcpInventory(cwd).entries;\n\t\t} catch {\n\t\t\tentries = [];\n\t\t}\n\t\tthis.mcpCache = { at: now, cwd, entries };\n\t\treturn entries;\n\t}\n\n\t/** Rolling CPU sparkline — a living pulse along the top of the rail. */\n\tprivate sparkline(width: number): string {\n\t\tconst now = Date.now();\n\t\tconst cpu = this.footerData.getCpuPercent();\n\t\tif (cpu !== null && now - this.lastSparkSampleAt >= SPARK_SAMPLE_MS) {\n\t\t\tthis.lastSparkSampleAt = now;\n\t\t\tthis.cpuHistory.push(Math.max(0, Math.min(100, cpu)));\n\t\t\tif (this.cpuHistory.length > SPARK_WINDOW) {\n\t\t\t\tthis.cpuHistory.shift();\n\t\t\t}\n\t\t}\n\n\t\tconst inner = Math.max(0, width - 4);\n\t\tconst label = theme.fg(\"muted\", \"act \");\n\t\tconst cells = Math.max(0, inner - visibleWidth(label));\n\t\tif (cells === 0 || this.cpuHistory.length === 0) {\n\t\t\treturn `${label}${theme.fg(\"borderMuted\", \"▁\".repeat(Math.max(0, cells)))}`;\n\t\t}\n\n\t\t// Right-align the window so the sparkline grows in from the left edge.\n\t\tconst window = this.cpuHistory.slice(-cells);\n\t\tconst bars = window.map((sample) => SPARK_CHARS[Math.min(7, Math.floor(sample / 12.6))]).join(\"\");\n\t\tconst pad = \"▁\".repeat(Math.max(0, cells - window.length));\n\t\treturn `${label}${theme.fg(\"borderMuted\", pad)}${theme.fg(\"accent\", bars)}`;\n\t}\n}\n\n/** Section rule with a right-aligned counter, e.g. `│─ MCP ─────── 22/24 │`. */\nfunction railRule(width: number, label: string, right: string): string {\n\tconst left = `${theme.fg(\"borderMuted\", \"─\")}${theme.fg(\"accent\", ` ${label} `)}`;\n\tconst rightText = ` ${right} `;\n\tconst fill = Math.max(0, width - 2 - visibleWidth(left) - visibleWidth(rightText));\n\tconst line = `${theme.fg(\"borderMuted\", \"│\")}${left}${theme.fg(\"borderMuted\", \"─\".repeat(fill))}${rightText}${theme.fg(\"borderMuted\", \"│\")}`;\n\treturn visibleWidth(line) <= width ? line : truncateToWidth(line, width, \"\");\n}\n\n/** One MCP server row: stability dot + name, truncated to the rail width. */\nfunction mcpRow(entry: McpServerEntry, width: number): string {\n\tconst stability = classifyMcpStability(entry);\n\tconst dot =\n\t\tstability === \"stable\"\n\t\t\t? theme.fg(\"success\", \"●\")\n\t\t\t: stability === \"overridden\"\n\t\t\t\t? theme.fg(\"dim\", \"◐\")\n\t\t\t\t: theme.fg(\"warning\", \"○\");\n\tconst nameColor: ThemeColor = stability === \"stable\" ? \"text\" : stability === \"overridden\" ? \"dim\" : \"warning\";\n\tconst nameWidth = Math.max(1, width - 4 - 2); // frame (4) + dot + space (2)\n\tconst name = truncateToWidth(entry.name, nameWidth, \"…\");\n\treturn `${dot} ${theme.fg(nameColor, name)}`;\n}\n\nfunction formatUptime(seconds: number): string {\n\tconst total = Math.max(0, Math.floor(seconds));\n\tconst h = Math.floor(total / 3600);\n\tconst m = Math.floor((total % 3600) / 60);\n\tconst s = total % 60;\n\tconst pad = (n: number) => n.toString().padStart(2, \"0\");\n\treturn h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${pad(m)}:${pad(s)}`;\n}\n\nfunction meter(percent: number | null, width: number): string {\n\t// Fill the rail: frame (4) + space + up to \"100%\" (4) stay reserved.\n\tconst cells = Math.max(METER_CELLS, Math.min(METER_MAX_CELLS, width - 9));\n\tif (percent === null) {\n\t\treturn `${theme.fg(\"borderMuted\", \"░\".repeat(cells))} ${theme.fg(\"muted\", \"??%\")}`;\n\t}\n\tconst clamped = Math.max(0, Math.min(100, percent));\n\tconst filled = Math.round((clamped / 100) * cells);\n\tconst color: ThemeColor = clamped >= 85 ? \"warning\" : clamped >= 65 ? \"mdCode\" : \"success\";\n\treturn `${theme.fg(color, \"█\".repeat(filled))}${theme.fg(\"borderMuted\", \"░\".repeat(cells - filled))} ${theme.fg(color, `${Math.round(clamped)}%`)}`;\n}\n"]}
|
|
@@ -90,6 +90,9 @@ export declare class InteractiveMode {
|
|
|
90
90
|
private widgetContainerAbove;
|
|
91
91
|
private widgetContainerBelow;
|
|
92
92
|
private customFooter;
|
|
93
|
+
private statusSidebar;
|
|
94
|
+
private statusSidebarPinned;
|
|
95
|
+
private footerSlot;
|
|
93
96
|
private headerContainer;
|
|
94
97
|
private builtInHeader;
|
|
95
98
|
private customHeader;
|
|
@@ -184,6 +187,12 @@ export declare class InteractiveMode {
|
|
|
184
187
|
*/
|
|
185
188
|
private renderWidgets;
|
|
186
189
|
private renderWidgetContainer;
|
|
190
|
+
/** The pinned rail is only shown (and its gutter reserved) when the terminal is large enough. */
|
|
191
|
+
private isStatusSidebarVisible;
|
|
192
|
+
/**
|
|
193
|
+
* Toggle the pinned status sidebar: bottom bar data moves to a fixed right rail.
|
|
194
|
+
*/
|
|
195
|
+
private toggleStatusSidebar;
|
|
187
196
|
/**
|
|
188
197
|
* Set a custom footer component, or restore the built-in footer.
|
|
189
198
|
*/
|