@lumoai/cli 1.37.0 → 1.38.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.
@@ -85,7 +85,7 @@ The command catalog below is a **map**: it lists every command grouped by domain
85
85
 
86
86
  **Cost (per-operation token read-out)** — see [task-context.md](references/task-context.md)
87
87
 
88
- - `lumo cost [--task <id>|--session <id>|--since <date>] [--by tool|model|member|session] [--json]` — per-operation (per-tool) token cost read-out. Attributes each model step's token delta to the tool(s) it ran (per-step where POST_TOOL_BATCH data exists, per-turn fallback otherwise), output vs cache_read shown separately, plus a per-step coverage line and a "heuristic" note (parallel tools split a step's tokens evenly). Scope is mutually exclusive: `--task` (one task) / `--session` (one Claude Code session) / `--since` (workspace window); default = workspace last-30-days. `--by` only changes which grouping is the headline (the others are still printed when non-trivial). For the per-task Top-5 inline, see `lumo task lineage`.
88
+ - `lumo cost [--task <id>|--session <id>|--since <date>] [--by tool|model|member|session] [--json]` — per-operation (per-tool) token cost read-out. Attributes each model step's token delta to the tool(s) it ran (per-step where POST_TOOL_BATCH data exists, per-turn fallback otherwise); each ranking row breaks the cost into output / input / cache_create / cache_read columns plus total, with a per-step coverage line and a "heuristic" note (parallel tools split a step's tokens evenly; output and cache_read attribute cleanly per step while input and cache_create are bursty, so per-tool figures for those two are coarse). Scope is mutually exclusive: `--task` (one task) / `--session` (one Claude Code session) / `--since` (workspace window); default = workspace last-30-days. `--by` only changes which grouping is the headline (the others are still printed when non-trivial). For the per-task Top-5 inline, see `lumo task lineage`.
89
89
 
90
90
  **Artifacts & Figma** — see [artifacts-figma.md](references/artifacts-figma.md)
91
91
 
@@ -187,8 +187,11 @@ Per-operation (per-tool) token cost read-out. Where `task lineage` answers
187
187
  token delta to the tool(s) that ran in it — **per-step** where the
188
188
  `POST_TOOL_BATCH` hook captured the tool list, **per-turn fallback** otherwise
189
189
  (a parallel-tool step splits its tokens evenly across the tools, hence the
190
- "heuristic" note). `output` (generation) and `cache_read` (~95%, structural
191
- turns × context) are shown in separate columns.
190
+ "heuristic" note). Each ranking row breaks the cost into four columns
191
+ `output` (generation), `input`, `cache_create`, `cache_read` (~95%, structural —
192
+ turns × context) — plus `total`. `output` and `cache_read` attribute cleanly
193
+ per step; `input` and `cache_create` are bursty (prompt + cache checkpoints), so
194
+ their per-tool figures are coarser.
192
195
 
193
196
  ```bash
194
197
  lumo cost --task LUM-42
@@ -10,15 +10,19 @@ function groupThousands(value) {
10
10
  .toString()
11
11
  .replace(/\B(?=(\d{3})+(?!\d))/g, ',');
12
12
  }
13
+ /** Render one ranking row: label + the four token categories + total, aligned. */
14
+ function rankRow(label, output, input, cacheCreate, cacheRead, total) {
15
+ return ` ${label.slice(0, 20).padEnd(20)} ${output.padStart(10)} ${input.padStart(10)} ${cacheCreate.padStart(12)} ${cacheRead.padStart(12)} ${total.padStart(12)}`;
16
+ }
13
17
  function rankTable(title, rows) {
14
18
  if (rows.length === 0)
15
19
  return '';
16
20
  const lines = [
17
21
  title,
18
- ' operation output cache_read total',
22
+ rankRow('operation', 'output', 'input', 'cache_create', 'cache_read', 'total'),
19
23
  ];
20
24
  for (const r of rows.slice(0, 20)) {
21
- lines.push(` ${r.label.slice(0, 20).padEnd(20)} ${groupThousands(r.output).padStart(10)} ${groupThousands(r.cacheRead).padStart(12)} ${groupThousands(r.total).padStart(12)}`);
25
+ lines.push(rankRow(r.label, groupThousands(r.output), groupThousands(r.input), groupThousands(r.cacheCreation), groupThousands(r.cacheRead), groupThousands(r.total)));
22
26
  }
23
27
  return lines.join('\n');
24
28
  }
@@ -39,7 +43,7 @@ function formatOperationCost(data, by) {
39
43
  : `${Math.round(data.coverage.perStepPct * 100)}%`;
40
44
  const out = [];
41
45
  out.push(`Per-operation cost — ${data.scope.kind} ${data.scope.label}`);
42
- out.push(`Total: output ${groupThousands(data.grandTotal.output)} · cache_read ${groupThousands(data.grandTotal.cacheRead)} · all ${groupThousands(data.grandTotal.total)} tokens`);
46
+ out.push(`Total: output ${groupThousands(data.grandTotal.output)} · input ${groupThousands(data.grandTotal.input)} · cache_create ${groupThousands(data.grandTotal.cacheCreation)} · cache_read ${groupThousands(data.grandTotal.cacheRead)} · all ${groupThousands(data.grandTotal.total)} tokens`);
43
47
  out.push(`Per-step attribution: ${pct} of ${data.coverage.toolTurns} tool-using turns (rest fall back to per-turn split)`);
44
48
  out.push('');
45
49
  out.push(rankTable(`By ${by}:`, primary));
@@ -52,7 +56,7 @@ function formatOperationCost(data, by) {
52
56
  if (by !== 'session' && data.bySession.length > 1)
53
57
  out.push('\n' + rankTable('By session:', data.bySession));
54
58
  out.push('');
55
- out.push('Note: token→tool attribution is heuristic — a model step that fires several tools in parallel splits its tokens evenly across them; cache_read (~95%) is structural (turns × context), shown alongside output (generation).');
59
+ out.push('Note: token→tool attribution is heuristic — a model step that fires several tools in parallel splits its tokens evenly across them. output (generation) and cache_read (~95%, structural turns × context) attribute cleanly per step; input and cache_create are bursty (prompt + cache checkpoints) and per-tool figures for those two are coarse.');
56
60
  return out.join('\n');
57
61
  }
58
62
  async function cost(opts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumoai/cli",
3
- "version": "1.37.0",
3
+ "version": "1.38.0",
4
4
  "description": "Lumo CLI — manage tasks and sessions from the terminal",
5
5
  "license": "MIT",
6
6
  "author": "cli@uselumo.ai",