opencode-top 3.2.1 → 3.3.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/bin/octop.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { dirname, join } from "path";
3
- import { fileURLToPath } from "url";
3
+ import { fileURLToPath, pathToFileURL } from "url";
4
4
 
5
5
  const __dirname = dirname(fileURLToPath(import.meta.url));
6
- await import(join(__dirname, "..", "dist", "cli.mjs"));
6
+ await import(pathToFileURL(join(__dirname, "..", "dist", "cli.mjs")).href);
package/dist/cli.mjs CHANGED
@@ -17935,10 +17935,10 @@ var Ink = class {
17935
17935
  this.fullStaticOutput += staticOutput;
17936
17936
  }
17937
17937
  if (outputHeight >= this.options.stdout.rows) {
17938
- this.log.clear();
17939
- if (this.fullStaticOutput) this.options.stdout.write(this.fullStaticOutput);
17940
- this.log(output);
17941
- this.lastOutput = output;
17938
+ if (output !== this.lastOutput) {
17939
+ this.log(output);
17940
+ this.lastOutput = output;
17941
+ }
17942
17942
  return;
17943
17943
  }
17944
17944
  if (hasStaticOutput) {
@@ -18427,29 +18427,19 @@ var TABS = [
18427
18427
  { id: "overview", label: "Overview", key: "3" }
18428
18428
  ];
18429
18429
  function TabBarInner({ activeScreen, lastRefresh }) {
18430
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { paddingX: 1, borderStyle: "single", borderColor: colors.border, flexDirection: "row", children: [
18431
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: colors.accent, bold: true, children: [
18432
- "OCMonitor",
18433
- " "
18434
- ] }),
18430
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Box_default, { paddingX: 1, height: 1, flexDirection: "row", children: [
18431
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.accent, bold: true, children: "oc-top " }),
18435
18432
  TABS.map((tab2) => {
18436
18433
  const isActive = tab2.id === activeScreen;
18437
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { marginRight: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
18438
- Text,
18439
- {
18440
- color: isActive ? colors.accent : colors.textDim,
18441
- bold: isActive,
18442
- children: [
18443
- "[",
18444
- tab2.key,
18445
- "]",
18446
- isActive ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: colors.text, children: [
18447
- " ",
18448
- tab2.label
18449
- ] }) : ` ${tab2.label}`
18450
- ]
18451
- }
18452
- ) }, tab2.id);
18434
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { marginRight: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: isActive ? colors.accent : colors.textDim, bold: isActive, children: [
18435
+ "[",
18436
+ tab2.key,
18437
+ "]",
18438
+ isActive ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { color: colors.text, children: [
18439
+ " ",
18440
+ tab2.label
18441
+ ] }) : ` ${tab2.label}`
18442
+ ] }) }, tab2.id);
18453
18443
  }),
18454
18444
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexGrow: 1 }),
18455
18445
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: colors.textDim, children: lastRefresh.toLocaleTimeString() })
@@ -18464,7 +18454,7 @@ var import_react28 = __toESM(require_react(), 1);
18464
18454
  var import_react23 = __toESM(require_react(), 1);
18465
18455
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
18466
18456
  function StatusBarInner({ hints, info }) {
18467
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { paddingX: 1, borderStyle: "single", borderColor: colors.border, flexDirection: "row", children: [
18457
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Box_default, { paddingX: 1, height: 1, flexDirection: "row", children: [
18468
18458
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { color: colors.textDim, children: hints }),
18469
18459
  info && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
18470
18460
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { flexGrow: 1 }),
@@ -20955,6 +20945,15 @@ function formatCost(d) {
20955
20945
  if (d.lessThan(0.01)) return `$${d.toFixed(4)}`;
20956
20946
  return `$${d.toFixed(2)}`;
20957
20947
  }
20948
+ function formatDate(ts) {
20949
+ if (!ts) return "";
20950
+ const d = new Date(ts);
20951
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
20952
+ const dd = String(d.getDate()).padStart(2, "0");
20953
+ const hh = String(d.getHours()).padStart(2, "0");
20954
+ const min2 = String(d.getMinutes()).padStart(2, "0");
20955
+ return `${mm}/${dd} ${hh}:${min2}`;
20956
+ }
20958
20957
  function AgentTreeInner({ workflows, selectedId, flatNodes, maxHeight = 20 }) {
20959
20958
  const headerHeight = 2;
20960
20959
  const visibleCount = Math.max(1, maxHeight - headerHeight);
@@ -20980,7 +20979,8 @@ function AgentTreeInner({ workflows, selectedId, flatNodes, maxHeight = 20 }) {
20980
20979
  const indent = " ".repeat(node.depth);
20981
20980
  const prefix = node.depth === 0 ? node.hasChildren ? "\u25B6 " : "\u25CF " : node.hasChildren ? "\u251C\u25B6 " : "\u251C\u2500 ";
20982
20981
  const label = node.depth === 0 ? truncate2(node.session.title ?? node.session.projectName ?? "Untitled", 22) : truncate2(`[${agentName ?? "?"}] ${node.session.title ?? ""}`, 20);
20983
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "row", children: [
20982
+ const date = formatDate(node.session.timeCreated);
20983
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "row", height: 1, children: [
20984
20984
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { width: 1 }),
20985
20985
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
20986
20986
  Text,
@@ -20996,6 +20996,10 @@ function AgentTreeInner({ workflows, selectedId, flatNodes, maxHeight = 20 }) {
20996
20996
  }
20997
20997
  ),
20998
20998
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexGrow: 1 }),
20999
+ date && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: colors.textDim, children: [
21000
+ date,
21001
+ " "
21002
+ ] }),
20999
21003
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.textDim, dimColor: true, children: formatTokens(tokens.total) }),
21000
21004
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { width: 1 }),
21001
21005
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: colors.success, children: formatCost(cost) }),
@@ -21261,7 +21265,9 @@ function buildLines(session, contentWidth, expandedIds) {
21261
21265
  modelId: interaction.modelId,
21262
21266
  agent: interaction.agent ?? null,
21263
21267
  duration: dur,
21264
- time: formatTime(interaction.time.created)
21268
+ time: formatTime(interaction.time.created),
21269
+ tokensIn: interaction.tokens.input + interaction.tokens.cacheRead,
21270
+ tokensOut: interaction.tokens.output
21265
21271
  });
21266
21272
  for (const part of interaction.parts) {
21267
21273
  if (part.type === "tool") {
@@ -21338,6 +21344,11 @@ function wrapText2(text, maxLen) {
21338
21344
  }
21339
21345
  return out;
21340
21346
  }
21347
+ function formatTokens4(n) {
21348
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
21349
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
21350
+ return String(n);
21351
+ }
21341
21352
  function formatTime(ts) {
21342
21353
  if (!ts) return "";
21343
21354
  return new Date(ts).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
@@ -21462,13 +21473,23 @@ function MessagesPanelInner({ session, maxHeight, isActive }) {
21462
21473
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "row", height: 1, children: [
21463
21474
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { color: isCursor ? colors.accent : colors.textDim, children: isCursor ? "\u203A" : " " }),
21464
21475
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { color: isCursor ? colors.accent : colors.purple, bold: true, children: "\u25C6 " }),
21465
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { color: isCursor ? colors.accent : colors.info, children: truncate4(line.modelId, 26) }),
21476
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { color: isCursor ? colors.accent : colors.info, children: truncate4(line.modelId, 22) }),
21466
21477
  line.agent && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { color: colors.cyan, children: [
21467
21478
  " [",
21468
21479
  line.agent,
21469
21480
  "]"
21470
21481
  ] }),
21471
21482
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { flexGrow: 1 }),
21483
+ line.tokensIn > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { color: colors.textDim, children: [
21484
+ "\u2193",
21485
+ formatTokens4(line.tokensIn),
21486
+ " "
21487
+ ] }),
21488
+ line.tokensOut > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { color: colors.textDim, children: [
21489
+ "\u2191",
21490
+ formatTokens4(line.tokensOut),
21491
+ " "
21492
+ ] }),
21472
21493
  line.duration && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { color: colors.textDim, children: [
21473
21494
  line.duration,
21474
21495
  " "
@@ -21898,7 +21919,7 @@ var SparkLine = (0, import_react30.memo)(SparkLineInner);
21898
21919
 
21899
21920
  // src/ui/screens/OverviewScreen.tsx
21900
21921
  var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
21901
- function formatTokens4(n) {
21922
+ function formatTokens5(n) {
21902
21923
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
21903
21924
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
21904
21925
  return n.toString();
@@ -21979,16 +22000,16 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
21979
22000
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textDim, children: [
21980
22001
  workflows.length,
21981
22002
  " workflows ",
21982
- stats.totalTokens.total > 0 ? formatTokens4(stats.totalTokens.total) + " tokens" : ""
22003
+ stats.totalTokens.total > 0 ? formatTokens5(stats.totalTokens.total) + " tokens" : ""
21983
22004
  ] })
21984
22005
  ] }),
21985
22006
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "row", flexGrow: 1, paddingX: 1, children: [
21986
22007
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", width: leftW, children: [
21987
22008
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionHeader, { title: "Totals" }),
21988
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: "Total tokens", value: formatTokens4(stats.totalTokens.total) }),
21989
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: " input", value: formatTokens4(stats.totalTokens.input), color: colors.info }),
21990
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: " output", value: formatTokens4(stats.totalTokens.output), color: colors.cyan }),
21991
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: " cache r/w", value: `${formatTokens4(stats.totalTokens.cacheRead)} / ${formatTokens4(stats.totalTokens.cacheWrite)}`, color: colors.textDim }),
22009
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: "Total tokens", value: formatTokens5(stats.totalTokens.total) }),
22010
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: " input", value: formatTokens5(stats.totalTokens.input), color: colors.info }),
22011
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: " output", value: formatTokens5(stats.totalTokens.output), color: colors.cyan }),
22012
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: " cache r/w", value: `${formatTokens5(stats.totalTokens.cacheRead)} / ${formatTokens5(stats.totalTokens.cacheWrite)}`, color: colors.textDim }),
21992
22013
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(StatRow2, { label: "Total cost", value: `$${stats.totalCost.toFixed(4)}`, color: colors.success }),
21993
22014
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionHeader, { title: "Token trend (7d)" }),
21994
22015
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "row", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SparkLine, { values: weeklyTokenValues, color: colors.cyan }) }),
@@ -21997,7 +22018,7 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
21997
22018
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1 }),
21998
22019
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textDim, children: [
21999
22020
  "peak ",
22000
- formatTokens4(maxWeeklyTokens)
22021
+ formatTokens5(maxWeeklyTokens)
22001
22022
  ] }),
22002
22023
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexGrow: 1 }),
22003
22024
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.textDim, children: stats.weeklyTokens[6]?.date.slice(3) ?? "" })
@@ -22095,7 +22116,7 @@ function OverviewScreenInner({ workflows, isActive, contentHeight, terminalWidth
22095
22116
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: colors.info, children: data.calls }),
22096
22117
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: colors.textDim, children: [
22097
22118
  " ",
22098
- formatTokens4(data.tokens)
22119
+ formatTokens5(data.tokens)
22099
22120
  ] })
22100
22121
  ] }, model))
22101
22122
  ] })
@@ -22433,7 +22454,7 @@ function App2({ refreshInterval = 2e3 }) {
22433
22454
  /* @__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" }) })
22434
22455
  ] });
22435
22456
  }
22436
- const contentHeight = terminalHeight - 3;
22457
+ const contentHeight = terminalHeight - 2;
22437
22458
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", width: terminalWidth, height: terminalHeight - 1, children: [
22438
22459
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TabBar, { activeScreen: screen, lastRefresh }),
22439
22460
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { width: terminalWidth, height: contentHeight, children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-top",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Monitor OpenCode AI coding sessions - Token usage, costs, and agent analytics",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,13 +1,8 @@
1
- --- /tmp/ink.js.orig 2026-03-15 03:32:19.803923699 +0100
2
- +++ node_modules/ink/build/ink.js 2026-03-15 03:32:24.220762248 +0100
3
- @@ -119,7 +119,9 @@
4
- this.fullStaticOutput += staticOutput;
5
- }
6
- if (outputHeight >= this.options.stdout.rows) {
7
- - this.options.stdout.write(ansiEscapes.clearTerminal + this.fullStaticOutput + output);
8
- + this.log.clear();
9
- + if (this.fullStaticOutput) this.options.stdout.write(this.fullStaticOutput);
10
- + this.log(output);
11
- this.lastOutput = output;
12
- return;
13
- }
1
+ 122,123c122,125
2
+ < this.options.stdout.write(ansiEscapes.clearTerminal + this.fullStaticOutput + output);
3
+ < this.lastOutput = output;
4
+ ---
5
+ > if (output !== this.lastOutput) {
6
+ > this.log(output);
7
+ > this.lastOutput = output;
8
+ > }