opencode-top 3.3.6 → 3.4.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/README.md +15 -0
- package/dist/cli.mjs +202 -144
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,3 +73,18 @@ cd opencode-top
|
|
|
73
73
|
npm install
|
|
74
74
|
npm start live # run from source with tsx
|
|
75
75
|
```
|
|
76
|
+
|
|
77
|
+
## Maintenance
|
|
78
|
+
|
|
79
|
+
### Publishing a new version
|
|
80
|
+
|
|
81
|
+
1. Make and commit your changes
|
|
82
|
+
2. Bump the version in `package.json`
|
|
83
|
+
3. Build and publish:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm publish --access public
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The `prepublishOnly` script runs the build automatically before publishing.
|
|
90
|
+
The bin entry must point to `bin/octop.js` (not `bin/octop.mjs`) — `octop.js` loads the pre-built `dist/cli.mjs` and has no runtime dependencies.
|
package/dist/cli.mjs
CHANGED
|
@@ -18403,19 +18403,32 @@ var import_react32 = __toESM(require_react(), 1);
|
|
|
18403
18403
|
|
|
18404
18404
|
// src/ui/theme.ts
|
|
18405
18405
|
var colors = {
|
|
18406
|
-
bg: "#
|
|
18407
|
-
bgSecondary: "#
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
|
|
18411
|
-
|
|
18412
|
-
|
|
18406
|
+
bg: "#0a0d0a",
|
|
18407
|
+
bgSecondary: "#0f130f",
|
|
18408
|
+
bgHighlight: "#162016",
|
|
18409
|
+
border: "#1e2e1e",
|
|
18410
|
+
borderBright: "#2d4a2d",
|
|
18411
|
+
accent: "#4ade80",
|
|
18412
|
+
// bright green — primary accent
|
|
18413
|
+
accentDim: "#22543d",
|
|
18414
|
+
accentAlt: "#86efac",
|
|
18415
|
+
// light green
|
|
18416
|
+
text: "#d4e8d4",
|
|
18417
|
+
// slightly green-tinted white
|
|
18418
|
+
textDim: "#527a52",
|
|
18419
|
+
textMuted: "#2d4a2d",
|
|
18413
18420
|
success: "#4ade80",
|
|
18414
18421
|
warning: "#fbbf24",
|
|
18415
18422
|
error: "#f87171",
|
|
18416
|
-
info: "#
|
|
18417
|
-
|
|
18418
|
-
|
|
18423
|
+
info: "#6ee7b7",
|
|
18424
|
+
// mint/emerald
|
|
18425
|
+
purple: "#a3e635",
|
|
18426
|
+
// lime — replaces purple for section headers
|
|
18427
|
+
cyan: "#34d399",
|
|
18428
|
+
// emerald
|
|
18429
|
+
teal: "#2dd4bf",
|
|
18430
|
+
peach: "#86efac"
|
|
18431
|
+
// light green instead of orange
|
|
18419
18432
|
};
|
|
18420
18433
|
|
|
18421
18434
|
// src/ui/components/TabBar.tsx
|
|
@@ -18427,22 +18440,19 @@ var TABS = [
|
|
|
18427
18440
|
{ id: "overview", label: "Overview", key: "3" }
|
|
18428
18441
|
];
|
|
18429
18442
|
function TabBarInner({ activeScreen, lastRefresh }) {
|
|
18430
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, {
|
|
18431
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
18432
|
-
|
|
18433
|
-
|
|
18434
|
-
|
|
18435
|
-
|
|
18436
|
-
tab2.key,
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18440
|
-
|
|
18441
|
-
|
|
18442
|
-
|
|
18443
|
-
}),
|
|
18444
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexGrow: 1 }),
|
|
18445
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.textDim, children: lastRefresh.toLocaleTimeString() })
|
|
18443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { flexDirection: "column", height: 2, children: [
|
|
18444
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { paddingX: 1, height: 1, flexDirection: "row", alignItems: "center", children: [
|
|
18445
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.accent, bold: true, children: "\u25C6 oc-top" }),
|
|
18446
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.textMuted, children: " \u2502 " }),
|
|
18447
|
+
TABS.map((tab2, i) => {
|
|
18448
|
+
const isActive = tab2.id === activeScreen;
|
|
18449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { marginRight: 1, children: isActive ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { backgroundColor: colors.bgHighlight, color: colors.accent, bold: true, children: ` ${tab2.key}:${tab2.label} ` }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.textDim, children: ` ${tab2.key}:${tab2.label} ` }) }, tab2.id);
|
|
18450
|
+
}),
|
|
18451
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexGrow: 1 }),
|
|
18452
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.textMuted, children: "\u21BB " }),
|
|
18453
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.textDim, children: lastRefresh.toLocaleTimeString() })
|
|
18454
|
+
] }),
|
|
18455
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { paddingX: 0, height: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.border, children: "\u2500".repeat(200) }) })
|
|
18446
18456
|
] });
|
|
18447
18457
|
}
|
|
18448
18458
|
var TabBar = (0, import_react22.memo)(TabBarInner);
|
|
@@ -18454,11 +18464,14 @@ var import_react28 = __toESM(require_react(), 1);
|
|
|
18454
18464
|
var import_react23 = __toESM(require_react(), 1);
|
|
18455
18465
|
var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
18456
18466
|
function StatusBarInner({ hints, info }) {
|
|
18457
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, {
|
|
18458
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: colors.
|
|
18459
|
-
|
|
18460
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
18461
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
18467
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { flexDirection: "column", height: 2, children: [
|
|
18468
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { paddingX: 0, height: 1, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: colors.border, children: "\u2500".repeat(200) }) }),
|
|
18469
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { paddingX: 1, height: 1, flexDirection: "row", children: [
|
|
18470
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: colors.textMuted, children: hints }),
|
|
18471
|
+
info && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
18472
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { flexGrow: 1 }),
|
|
18473
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: colors.info, children: info })
|
|
18474
|
+
] })
|
|
18462
18475
|
] })
|
|
18463
18476
|
] });
|
|
18464
18477
|
}
|
|
@@ -20966,9 +20979,12 @@ function AgentTreeInner({ workflows, selectedId, flatNodes, maxHeight = 20 }) {
|
|
|
20966
20979
|
const visibleNodes = flatNodes.slice(startIndex, startIndex + visibleCount);
|
|
20967
20980
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, height: maxHeight, overflow: "hidden", children: [
|
|
20968
20981
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { marginBottom: 1, flexDirection: "row", children: [
|
|
20969
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.
|
|
20982
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.purple, bold: true, children: "SESSIONS" }),
|
|
20970
20983
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexGrow: 1 }),
|
|
20971
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
20984
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: colors.textMuted, children: [
|
|
20985
|
+
workflows.length,
|
|
20986
|
+
" workflows"
|
|
20987
|
+
] })
|
|
20972
20988
|
] }),
|
|
20973
20989
|
visibleNodes.map((node) => {
|
|
20974
20990
|
const isSelected = node.id === selectedId;
|
|
@@ -20977,32 +20993,19 @@ function AgentTreeInner({ workflows, selectedId, flatNodes, maxHeight = 20 }) {
|
|
|
20977
20993
|
const cost = getSessionCostSingle(node.session, pricing);
|
|
20978
20994
|
const agentName = node.session.interactions[0]?.agent ?? null;
|
|
20979
20995
|
const indent = " ".repeat(node.depth);
|
|
20980
|
-
const prefix = node.depth === 0 ? node.hasChildren ? "\
|
|
20996
|
+
const prefix = node.depth === 0 ? node.hasChildren ? "\u25B8 " : " " : node.hasChildren ? "\u2570\u25B8 " : "\u2570\u2500 ";
|
|
20981
20997
|
const label = node.depth === 0 ? truncate2(node.session.title ?? node.session.projectName ?? "Untitled", 22) : truncate2(`[${agentName ?? "?"}] ${node.session.title ?? ""}`, 20);
|
|
20982
20998
|
const date = formatDate(node.session.timeCreated);
|
|
20983
20999
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "row", height: 1, children: [
|
|
20984
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
20985
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
20986
|
-
Text,
|
|
20987
|
-
{
|
|
20988
|
-
color: isSelected ? void 0 : colors.text,
|
|
20989
|
-
backgroundColor: isSelected ? colors.accent : void 0,
|
|
20990
|
-
bold: isSelected,
|
|
20991
|
-
children: [
|
|
20992
|
-
indent,
|
|
20993
|
-
prefix,
|
|
20994
|
-
label
|
|
20995
|
-
]
|
|
20996
|
-
}
|
|
20997
|
-
),
|
|
21000
|
+
isSelected ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.bgHighlight, backgroundColor: colors.accent, bold: true, children: `\u25B6 ${indent}${prefix}${label}` }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: node.depth === 0 ? colors.text : colors.textDim, children: ` ${indent}${prefix}${label}` }),
|
|
20998
21001
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexGrow: 1 }),
|
|
20999
|
-
date && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: colors.
|
|
21002
|
+
date && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: colors.textMuted, children: [
|
|
21000
21003
|
date,
|
|
21001
21004
|
" "
|
|
21002
21005
|
] }),
|
|
21003
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.textDim,
|
|
21006
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.textDim, children: formatTokens(tokens.total) }),
|
|
21004
21007
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { width: 1 }),
|
|
21005
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.success, children: formatCost(cost) }),
|
|
21008
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: cost.greaterThan(0) ? colors.success : colors.textMuted, children: formatCost(cost) }),
|
|
21006
21009
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { width: 1 })
|
|
21007
21010
|
] }, node.id);
|
|
21008
21011
|
}),
|
|
@@ -21148,8 +21151,8 @@ function ProgressBar({
|
|
|
21148
21151
|
const filled = Math.round(pct * width);
|
|
21149
21152
|
const empty = width - filled;
|
|
21150
21153
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
|
|
21151
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color, children: "\
|
|
21152
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.
|
|
21154
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color, children: "\u2593".repeat(filled) }),
|
|
21155
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.textMuted, children: "\u2591".repeat(empty) }),
|
|
21153
21156
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: colors.textDim, children: [
|
|
21154
21157
|
" ",
|
|
21155
21158
|
Math.round(pct * 100),
|
|
@@ -21204,35 +21207,45 @@ function DetailsPanelInner({ workflow, height }) {
|
|
|
21204
21207
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexDirection: "column", paddingX: 1, height, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.textDim, children: "Select a session" }) });
|
|
21205
21208
|
}
|
|
21206
21209
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", paddingX: 1, height, overflow: "hidden", children: [
|
|
21207
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.accent, bold: true, children: "Details" }) }),
|
|
21208
21210
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
21209
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.
|
|
21210
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.
|
|
21211
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.accent, bold: true, children: data.title }),
|
|
21212
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: colors.textMuted, children: [
|
|
21213
|
+
"\u25CE ",
|
|
21214
|
+
data.project
|
|
21215
|
+
] })
|
|
21216
|
+
] }),
|
|
21217
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
21218
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.purple, bold: true, children: "\u2500\u2500 STATS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
21211
21219
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Tokens", value: formatTokens3(data.tokens) }),
|
|
21212
21220
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Cost", value: `$${data.cost.toFixed(4)}`, color: colors.success }),
|
|
21213
21221
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Duration", value: formatDuration(data.duration) }),
|
|
21214
21222
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Rate", value: `${data.outputRate.toFixed(0)} tok/s` }),
|
|
21215
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Calls", value: data.calls.toString() })
|
|
21216
|
-
|
|
21223
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Calls", value: data.calls.toString() })
|
|
21224
|
+
] }),
|
|
21225
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
21226
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.textMuted, children: "context" }),
|
|
21217
21227
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
21218
21228
|
ProgressBar,
|
|
21219
21229
|
{
|
|
21220
21230
|
value: data.contextUsage,
|
|
21221
21231
|
max: data.contextWindow,
|
|
21222
|
-
color: data.contextPct > 0.8 ? colors.warning : colors.
|
|
21232
|
+
color: data.contextPct > 0.8 ? colors.warning : colors.teal
|
|
21223
21233
|
}
|
|
21224
21234
|
)
|
|
21225
21235
|
] }),
|
|
21226
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.purple, bold: true, children: "
|
|
21236
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.purple, bold: true, children: "\u2500\u2500 MODELS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
|
|
21227
21237
|
Array.from(data.modelBreakdown.entries()).slice(0, 3).map(([model, stats]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21228
21238
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.text, children: model.slice(0, 25) }),
|
|
21229
21239
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexGrow: 1 }),
|
|
21230
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.
|
|
21240
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { color: colors.textMuted, children: [
|
|
21241
|
+
stats.count,
|
|
21242
|
+
"\xD7"
|
|
21243
|
+
] }),
|
|
21231
21244
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { width: 1 }),
|
|
21232
21245
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.info, children: formatTokens3(stats.tokens) })
|
|
21233
21246
|
] }, model)),
|
|
21234
21247
|
data.topTools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
21235
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.purple, bold: true, children: "
|
|
21248
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.purple, bold: true, children: "\u2500\u2500 TOOLS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
|
|
21236
21249
|
data.topTools.map((tool) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21237
21250
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.text, children: tool.name.slice(0, 20) }),
|
|
21238
21251
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexGrow: 1 }),
|
|
@@ -21244,7 +21257,7 @@ function DetailsPanelInner({ workflow, height }) {
|
|
|
21244
21257
|
] }, tool.name))
|
|
21245
21258
|
] }),
|
|
21246
21259
|
data.hasSubAgents && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
21247
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.purple, bold: true, children: "
|
|
21260
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: colors.purple, bold: true, children: "\u2500\u2500 AGENT CHAIN \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
|
|
21248
21261
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AgentChainGraph, { agentTree: data.agentTree })
|
|
21249
21262
|
] })
|
|
21250
21263
|
] });
|
|
@@ -21618,7 +21631,7 @@ function SessionsScreenInner({
|
|
|
21618
21631
|
}, [selectedNode, workflows]);
|
|
21619
21632
|
const leftWidth = Math.floor(terminalWidth * 0.35);
|
|
21620
21633
|
const rightWidth = terminalWidth - leftWidth - 2;
|
|
21621
|
-
const statusBarHeight =
|
|
21634
|
+
const statusBarHeight = 2;
|
|
21622
21635
|
const borderRows = 2;
|
|
21623
21636
|
const innerHeight = contentHeight - statusBarHeight - borderRows;
|
|
21624
21637
|
const panelHeight = contentHeight - statusBarHeight;
|
|
@@ -21669,8 +21682,8 @@ function SessionsScreenInner({
|
|
|
21669
21682
|
{
|
|
21670
21683
|
width: leftWidth,
|
|
21671
21684
|
height: panelHeight,
|
|
21672
|
-
borderStyle: "
|
|
21673
|
-
borderColor: colors.
|
|
21685
|
+
borderStyle: "round",
|
|
21686
|
+
borderColor: colors.borderBright,
|
|
21674
21687
|
flexDirection: "column",
|
|
21675
21688
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
21676
21689
|
AgentTree,
|
|
@@ -21692,16 +21705,16 @@ function SessionsScreenInner({
|
|
|
21692
21705
|
{
|
|
21693
21706
|
width: rightWidth,
|
|
21694
21707
|
height: panelHeight,
|
|
21695
|
-
borderStyle: "
|
|
21696
|
-
borderColor: colors.
|
|
21708
|
+
borderStyle: "round",
|
|
21709
|
+
borderColor: colors.borderBright,
|
|
21697
21710
|
flexDirection: "column",
|
|
21698
21711
|
children: [
|
|
21699
21712
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { paddingX: 1, height: 1, flexDirection: "row", children: [
|
|
21700
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, {
|
|
21701
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: colors.
|
|
21702
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, {
|
|
21713
|
+
rightMode === "stats" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { backgroundColor: colors.bgHighlight, color: colors.accent, bold: true, children: " Stats " }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: colors.textDim, children: " Stats " }),
|
|
21714
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: colors.textMuted, children: "\u2502" }),
|
|
21715
|
+
rightMode === "messages" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { backgroundColor: colors.bgHighlight, color: colors.accent, bold: true, children: " Messages " }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: colors.textDim, children: " Messages " }),
|
|
21703
21716
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Box_default, { flexGrow: 1 }),
|
|
21704
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: colors.
|
|
21717
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { color: colors.textMuted, children: "Tab:switch" })
|
|
21705
21718
|
] }),
|
|
21706
21719
|
rightMode === "stats" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DetailsPanel, { workflow: selectedWorkflow, height: innerHeight - 1 }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
21707
21720
|
MessagesPanel,
|
|
@@ -21766,10 +21779,10 @@ function SuccessBar({ successes, calls, width = 12 }) {
|
|
|
21766
21779
|
const pct = calls > 0 ? successes / calls : 0;
|
|
21767
21780
|
const filled = Math.round(pct * width);
|
|
21768
21781
|
const empty = width - filled;
|
|
21769
|
-
const color = pct >= 0.9 ? colors.
|
|
21782
|
+
const color = pct >= 0.9 ? colors.teal : pct >= 0.7 ? colors.warning : colors.error;
|
|
21770
21783
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { children: [
|
|
21771
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color, children: "\
|
|
21772
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21784
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color, children: "\u2593".repeat(filled) }),
|
|
21785
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "\u2591".repeat(empty) }),
|
|
21773
21786
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: colors.textDim, children: [
|
|
21774
21787
|
" ",
|
|
21775
21788
|
Math.round(pct * 100),
|
|
@@ -21797,7 +21810,8 @@ function ToolsScreenInner({ workflows, isActive, contentHeight, terminalWidth })
|
|
|
21797
21810
|
return copy.sort((a, b) => b.avgDurationMs - a.avgDurationMs);
|
|
21798
21811
|
}
|
|
21799
21812
|
}, [allTools, sortKey]);
|
|
21800
|
-
const
|
|
21813
|
+
const statusBarHeight = 2;
|
|
21814
|
+
const listHeight = contentHeight - statusBarHeight - 3;
|
|
21801
21815
|
const clampedIndex = Math.min(selectedIndex, Math.max(0, sortedTools.length - 1));
|
|
21802
21816
|
const selectedTool = sortedTools[clampedIndex] ?? null;
|
|
21803
21817
|
const startIndex = clampedIndex >= listHeight ? clampedIndex - listHeight + 1 : 0;
|
|
@@ -21824,84 +21838,70 @@ function ToolsScreenInner({ workflows, isActive, contentHeight, terminalWidth })
|
|
|
21824
21838
|
{ isActive }
|
|
21825
21839
|
);
|
|
21826
21840
|
const sortLabels = {
|
|
21827
|
-
calls: "
|
|
21828
|
-
failures: "
|
|
21829
|
-
avgTime: "
|
|
21841
|
+
calls: "calls",
|
|
21842
|
+
failures: "failures",
|
|
21843
|
+
avgTime: "avg-time"
|
|
21830
21844
|
};
|
|
21831
21845
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", width: terminalWidth, height: contentHeight, children: [
|
|
21832
21846
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { paddingX: 1, flexDirection: "row", children: [
|
|
21833
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.accent, bold: true, children: "
|
|
21847
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.accent, bold: true, children: "\u25C6 TOOLS" }),
|
|
21834
21848
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1 }),
|
|
21835
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.
|
|
21836
|
-
|
|
21837
|
-
|
|
21838
|
-
|
|
21839
|
-
|
|
21840
|
-
|
|
21841
|
-
"]",
|
|
21842
|
-
" "
|
|
21843
|
-
] }, k)),
|
|
21844
|
-
"Tab:cycle"
|
|
21845
|
-
] })
|
|
21849
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "sort: " }),
|
|
21850
|
+
["calls", "failures", "avgTime"].map((k) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: sortKey === k ? colors.teal : colors.textMuted, children: [
|
|
21851
|
+
sortKey === k ? `[${sortLabels[k]}]` : sortLabels[k],
|
|
21852
|
+
" "
|
|
21853
|
+
] }, k)),
|
|
21854
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "Tab:cycle" })
|
|
21846
21855
|
] }),
|
|
21847
21856
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "row", flexGrow: 1, children: [
|
|
21848
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { width: 36, flexDirection: "column", borderStyle: "
|
|
21857
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { width: 36, flexDirection: "column", borderStyle: "round", borderColor: colors.borderBright, children: [
|
|
21849
21858
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { paddingX: 1, flexDirection: "row", children: [
|
|
21850
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21859
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.purple, bold: true, children: "TOOL" }),
|
|
21851
21860
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1 }),
|
|
21852
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21853
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21861
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "calls " }),
|
|
21862
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "err" })
|
|
21854
21863
|
] }),
|
|
21855
|
-
visibleTools.map((tool
|
|
21864
|
+
visibleTools.map((tool) => {
|
|
21856
21865
|
const isSelected = tool.name === selectedTool?.name;
|
|
21857
21866
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "row", paddingX: 1, children: [
|
|
21858
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.
|
|
21859
|
-
Text,
|
|
21860
|
-
{
|
|
21861
|
-
color: isSelected ? colors.accent : colors.textDim,
|
|
21862
|
-
bold: isSelected,
|
|
21863
|
-
children: [
|
|
21864
|
-
isSelected ? "\u25B6 " : " ",
|
|
21865
|
-
truncate5(tool.name, 20)
|
|
21866
|
-
]
|
|
21867
|
-
}
|
|
21868
|
-
),
|
|
21867
|
+
isSelected ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.bgHighlight, backgroundColor: colors.accent, bold: true, children: `\u25B6 ${truncate5(tool.name, 20)}` }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textDim, children: ` ${truncate5(tool.name, 20)}` }),
|
|
21869
21868
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1 }),
|
|
21870
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21871
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21872
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: tool.failures > 0 ? colors.error : colors.
|
|
21869
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.accentAlt, children: tool.calls }),
|
|
21870
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: " " }),
|
|
21871
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: tool.failures > 0 ? colors.error : colors.textMuted, children: tool.failures })
|
|
21873
21872
|
] }, tool.name);
|
|
21874
21873
|
}),
|
|
21875
21874
|
allTools.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { paddingX: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textDim, children: "No tool data yet" }) })
|
|
21876
21875
|
] }),
|
|
21877
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1, flexDirection: "column", borderStyle: "
|
|
21878
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21876
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexGrow: 1, flexDirection: "column", borderStyle: "round", borderColor: colors.borderBright, paddingX: 1, children: selectedTool ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
21877
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.accent, bold: true, children: selectedTool.name }),
|
|
21879
21878
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { marginTop: 1, flexDirection: "column", children: [
|
|
21879
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.purple, bold: true, children: "\u2500\u2500 STATS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
21880
21880
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21881
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21881
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "Total calls" }) }),
|
|
21882
21882
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.text, children: selectedTool.calls })
|
|
21883
21883
|
] }),
|
|
21884
21884
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21885
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21885
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "Successes" }) }),
|
|
21886
21886
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.success, children: selectedTool.successes })
|
|
21887
21887
|
] }),
|
|
21888
21888
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21889
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21890
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: selectedTool.failures > 0 ? colors.error : colors.
|
|
21889
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "Failures" }) }),
|
|
21890
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: selectedTool.failures > 0 ? colors.error : colors.textMuted, children: selectedTool.failures })
|
|
21891
21891
|
] }),
|
|
21892
21892
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21893
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21893
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { width: 14, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "Avg time" }) }),
|
|
21894
21894
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.info, children: formatDuration3(selectedTool.avgDurationMs) })
|
|
21895
21895
|
] })
|
|
21896
21896
|
] }),
|
|
21897
21897
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { marginTop: 1, children: [
|
|
21898
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21898
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.textMuted, children: "success rate " }),
|
|
21899
21899
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SuccessBar, { successes: selectedTool.successes, calls: selectedTool.calls })
|
|
21900
21900
|
] }),
|
|
21901
21901
|
selectedTool.recentErrors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
21902
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.
|
|
21902
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.purple, bold: true, children: "\u2500\u2500 RECENT ERRORS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }) }),
|
|
21903
21903
|
selectedTool.recentErrors.map((err, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21904
|
-
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.error, children: "\
|
|
21904
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.error, children: "\u2717 " }),
|
|
21905
21905
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: colors.text, children: truncate5(err, 60) })
|
|
21906
21906
|
] }, i))
|
|
21907
21907
|
] })
|
|
@@ -21937,6 +21937,7 @@ var SparkLine = (0, import_react30.memo)(SparkLineInner);
|
|
|
21937
21937
|
|
|
21938
21938
|
// src/ui/screens/OverviewScreen.tsx
|
|
21939
21939
|
var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
|
|
21940
|
+
var TIME_FILTER_OPTIONS = [1, 7, 30, 90, 0];
|
|
21940
21941
|
function formatTokens5(n) {
|
|
21941
21942
|
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
21942
21943
|
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
@@ -21949,7 +21950,11 @@ function StatRow2({ label, value, color = colors.text }) {
|
|
|
21949
21950
|
] });
|
|
21950
21951
|
}
|
|
21951
21952
|
function SectionHeader({ title }) {
|
|
21952
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.
|
|
21953
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.purple, bold: true, children: [
|
|
21954
|
+
"\u2500\u2500 ",
|
|
21955
|
+
title.toUpperCase(),
|
|
21956
|
+
" "
|
|
21957
|
+
] }) });
|
|
21953
21958
|
}
|
|
21954
21959
|
function ErrorBar({
|
|
21955
21960
|
label,
|
|
@@ -21964,17 +21969,16 @@ function ErrorBar({
|
|
|
21964
21969
|
const errPct = calls > 0 ? Math.round(errors / calls * 100) : 0;
|
|
21965
21970
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
21966
21971
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { width: labelWidth, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.text, children: truncate6(label, labelWidth - 1) }) }),
|
|
21967
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.
|
|
21968
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: errors > 0 ? colors.error : colors.
|
|
21972
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.teal, children: "\u2593".repeat(okFilled) }),
|
|
21973
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: errors > 0 ? colors.error : colors.textMuted, children: "\u2593".repeat(errFilled) }),
|
|
21969
21974
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textDim, children: [
|
|
21970
21975
|
" ",
|
|
21971
|
-
calls
|
|
21972
|
-
" calls"
|
|
21976
|
+
calls
|
|
21973
21977
|
] }),
|
|
21974
21978
|
errors > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.error, children: [
|
|
21975
|
-
" ",
|
|
21979
|
+
" \u2717",
|
|
21976
21980
|
errors,
|
|
21977
|
-
"
|
|
21981
|
+
" (",
|
|
21978
21982
|
errPct,
|
|
21979
21983
|
"%)"
|
|
21980
21984
|
] })
|
|
@@ -21982,7 +21986,50 @@ function ErrorBar({
|
|
|
21982
21986
|
}
|
|
21983
21987
|
function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth }) {
|
|
21984
21988
|
const pricing = (0, import_react31.useMemo)(() => getAllPricing(), []);
|
|
21985
|
-
const
|
|
21989
|
+
const [timeFilterIdx, setTimeFilterIdx] = (0, import_react31.useState)(0);
|
|
21990
|
+
const [projectFilterIdx, setProjectFilterIdx] = (0, import_react31.useState)(0);
|
|
21991
|
+
const timeFilter = TIME_FILTER_OPTIONS[timeFilterIdx];
|
|
21992
|
+
const allProjects = (0, import_react31.useMemo)(() => {
|
|
21993
|
+
const projects = /* @__PURE__ */ new Set();
|
|
21994
|
+
for (const w of workflows) {
|
|
21995
|
+
const p = w.mainSession.projectName ?? "Unknown";
|
|
21996
|
+
projects.add(p);
|
|
21997
|
+
}
|
|
21998
|
+
return Array.from(projects).sort();
|
|
21999
|
+
}, [workflows]);
|
|
22000
|
+
const selectedProject = projectFilterIdx === 0 ? null : allProjects[projectFilterIdx - 1] ?? null;
|
|
22001
|
+
const filteredWorkflows = (0, import_react31.useMemo)(() => {
|
|
22002
|
+
let cutoff = 0;
|
|
22003
|
+
if (timeFilter === 1) {
|
|
22004
|
+
const today = /* @__PURE__ */ new Date();
|
|
22005
|
+
today.setHours(0, 0, 0, 0);
|
|
22006
|
+
cutoff = today.getTime();
|
|
22007
|
+
} else if (timeFilter > 1) {
|
|
22008
|
+
cutoff = Date.now() - timeFilter * 864e5;
|
|
22009
|
+
}
|
|
22010
|
+
return workflows.filter((w) => {
|
|
22011
|
+
const ts = w.mainSession.timeCreated;
|
|
22012
|
+
if (cutoff > 0 && (ts === null || ts < cutoff)) return false;
|
|
22013
|
+
if (selectedProject !== null) {
|
|
22014
|
+
const p = w.mainSession.projectName ?? "Unknown";
|
|
22015
|
+
if (p !== selectedProject) return false;
|
|
22016
|
+
}
|
|
22017
|
+
return true;
|
|
22018
|
+
});
|
|
22019
|
+
}, [workflows, timeFilter, selectedProject]);
|
|
22020
|
+
use_input_default((input) => {
|
|
22021
|
+
if (!isActive) return;
|
|
22022
|
+
if (input === "t") {
|
|
22023
|
+
setTimeFilterIdx((i) => (i + 1) % TIME_FILTER_OPTIONS.length);
|
|
22024
|
+
}
|
|
22025
|
+
if (input === "p") {
|
|
22026
|
+
setProjectFilterIdx((i) => (i + 1) % (allProjects.length + 1));
|
|
22027
|
+
}
|
|
22028
|
+
if (input === "P") {
|
|
22029
|
+
setProjectFilterIdx((i) => (i - 1 + allProjects.length + 1) % (allProjects.length + 1));
|
|
22030
|
+
}
|
|
22031
|
+
}, { isActive });
|
|
22032
|
+
const stats = (0, import_react31.useMemo)(() => computeOverviewStats(filteredWorkflows, pricing), [filteredWorkflows, pricing]);
|
|
21986
22033
|
const topModels = (0, import_react31.useMemo)(
|
|
21987
22034
|
() => Array.from(stats.modelBreakdown.entries()).sort((a, b) => b[1].calls - a[1].calls).slice(0, 4),
|
|
21988
22035
|
[stats]
|
|
@@ -22013,14 +22060,27 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
|
|
|
22013
22060
|
const midW = Math.max(26, Math.floor(terminalWidth * 0.3));
|
|
22014
22061
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", width: terminalWidth, height: contentHeight, children: [
|
|
22015
22062
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { paddingX: 1, flexDirection: "row", children: [
|
|
22016
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.accent, bold: true, children: "
|
|
22063
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.accent, bold: true, children: "\u25C6 OVERVIEW" }),
|
|
22017
22064
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1 }),
|
|
22018
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.
|
|
22065
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textMuted, children: [
|
|
22066
|
+
filteredWorkflows.length,
|
|
22067
|
+
"/",
|
|
22019
22068
|
workflows.length,
|
|
22020
|
-
" workflows
|
|
22021
|
-
|
|
22069
|
+
" workflows"
|
|
22070
|
+
] }),
|
|
22071
|
+
stats.totalTokens.total > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textMuted, children: [
|
|
22072
|
+
" ",
|
|
22073
|
+
formatTokens5(stats.totalTokens.total),
|
|
22074
|
+
" tokens"
|
|
22022
22075
|
] })
|
|
22023
22076
|
] }),
|
|
22077
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { paddingX: 1, flexDirection: "row", children: [
|
|
22078
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textMuted, children: "filter: " }),
|
|
22079
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: timeFilter === 0 ? colors.accent : colors.teal, bold: true, children: timeFilter === 0 ? "all time" : timeFilter === 1 ? "today" : `last ${timeFilter}d` }),
|
|
22080
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textMuted, children: " \xB7 " }),
|
|
22081
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: selectedProject ? colors.peach : colors.textMuted, children: selectedProject ? truncate6(selectedProject, 24) : "all projects" }),
|
|
22082
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textMuted, children: " (t/p)" })
|
|
22083
|
+
] }),
|
|
22024
22084
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", flexGrow: 1, paddingX: 1, children: [
|
|
22025
22085
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", width: leftW, children: [
|
|
22026
22086
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionHeader, { title: "Totals" }),
|
|
@@ -22030,7 +22090,7 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
|
|
|
22030
22090
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: " cache r/w", value: `${formatTokens5(stats.totalTokens.cacheRead)} / ${formatTokens5(stats.totalTokens.cacheWrite)}`, color: colors.textDim }),
|
|
22031
22091
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: "Total cost", value: `$${stats.totalCost.toFixed(4)}`, color: colors.success }),
|
|
22032
22092
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionHeader, { title: "Token trend (7d)" }),
|
|
22033
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "row", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SparkLine, { values: weeklyTokenValues, color: colors.
|
|
22093
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "row", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SparkLine, { values: weeklyTokenValues, color: colors.accentAlt }) }),
|
|
22034
22094
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
22035
22095
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textDim, children: stats.weeklyTokens[0]?.date.slice(3) ?? "" }),
|
|
22036
22096
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1 }),
|
|
@@ -22042,7 +22102,7 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
|
|
|
22042
22102
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textDim, children: stats.weeklyTokens[6]?.date.slice(3) ?? "" })
|
|
22043
22103
|
] }),
|
|
22044
22104
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionHeader, { title: "Sessions (7d)" }),
|
|
22045
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "row", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SparkLine, { values: weeklySessionValues, color: colors.
|
|
22105
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "row", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SparkLine, { values: weeklySessionValues, color: colors.purple }) }),
|
|
22046
22106
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
22047
22107
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textDim, children: stats.weeklySessions[0]?.date.slice(3) ?? "" }),
|
|
22048
22108
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1 }),
|
|
@@ -22055,7 +22115,7 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
|
|
|
22055
22115
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textDim, children: stats.weeklySessions[6]?.date.slice(3) ?? "" })
|
|
22056
22116
|
] }),
|
|
22057
22117
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionHeader, { title: "Hourly activity" }),
|
|
22058
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.
|
|
22118
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.teal, children: hourSpark }),
|
|
22059
22119
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
22060
22120
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textDim, children: "00" }),
|
|
22061
22121
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1 }),
|
|
@@ -22084,8 +22144,8 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
|
|
|
22084
22144
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionHeader, { title: "Top tools (calls / errors)" }),
|
|
22085
22145
|
topTools.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textDim, children: "No tool data" }) : topTools.map(([name, data]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
22086
22146
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { width: 10, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.text, children: truncate6(name, 9) }) }),
|
|
22087
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: data.errors > 0 ? colors.
|
|
22088
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.
|
|
22147
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: data.errors > 0 ? colors.peach : colors.accentAlt, children: "\u2593".repeat(Math.max(1, Math.round(data.calls / maxToolCalls * 12))) }),
|
|
22148
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textMuted, children: "\u2591".repeat(Math.max(0, 12 - Math.max(1, Math.round(data.calls / maxToolCalls * 12)))) }),
|
|
22089
22149
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textDim, children: [
|
|
22090
22150
|
" ",
|
|
22091
22151
|
data.calls
|
|
@@ -22119,8 +22179,8 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
|
|
|
22119
22179
|
const durStr = avg < 1e3 ? `${avg.toFixed(0)}ms` : `${(avg / 1e3).toFixed(1)}s`;
|
|
22120
22180
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", children: [
|
|
22121
22181
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { width: 12, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.text, children: truncate6(name, 10) }) }),
|
|
22122
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.
|
|
22123
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.
|
|
22182
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.peach, children: "\u2593".repeat(filled) }),
|
|
22183
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textMuted, children: "\u2591".repeat(barW - filled) }),
|
|
22124
22184
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textDim, children: [
|
|
22125
22185
|
" ",
|
|
22126
22186
|
durStr
|
|
@@ -22139,7 +22199,7 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
|
|
|
22139
22199
|
] }, model))
|
|
22140
22200
|
] })
|
|
22141
22201
|
] }),
|
|
22142
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBar, { hints: "1:sessions 2:tools r:refresh q:quit" })
|
|
22202
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatusBar, { hints: "1:sessions 2:tools t:time-filter p/P:project r:refresh q:quit" })
|
|
22143
22203
|
] });
|
|
22144
22204
|
}
|
|
22145
22205
|
var OverviewScreen = (0, import_react31.memo)(OverviewScreenInner);
|
|
@@ -22472,7 +22532,7 @@ function App2({ refreshInterval = 2e3 }) {
|
|
|
22472
22532
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { color: colors.textDim, children: "Press q to quit" }) })
|
|
22473
22533
|
] });
|
|
22474
22534
|
}
|
|
22475
|
-
const contentHeight = terminalHeight -
|
|
22535
|
+
const contentHeight = terminalHeight - 3;
|
|
22476
22536
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", width: terminalWidth, height: terminalHeight - 1, children: [
|
|
22477
22537
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TabBar, { activeScreen: screen, lastRefresh }),
|
|
22478
22538
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { width: terminalWidth, height: contentHeight, children: [
|
|
@@ -22508,9 +22568,7 @@ function App2({ refreshInterval = 2e3 }) {
|
|
|
22508
22568
|
}
|
|
22509
22569
|
|
|
22510
22570
|
// src/cli.ts
|
|
22511
|
-
|
|
22512
|
-
var require2 = createRequire(import.meta.url);
|
|
22513
|
-
var pkg = require2("../package.json");
|
|
22571
|
+
var pkg = true ? { version: "3.4.0", name: "opencode-top" } : devPkg();
|
|
22514
22572
|
program.name(pkg.name).version(pkg.version).description("Monitor OpenCode AI coding sessions");
|
|
22515
22573
|
program.command("live").description("Start live monitoring dashboard").option("-i, --interval <ms>", "Refresh interval in milliseconds", "2000").action((options) => {
|
|
22516
22574
|
const refreshInterval = Number.parseInt(options.interval, 10);
|