@kontextmind/kxm 0.7.178 → 0.7.179

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.
@@ -11,7 +11,7 @@
11
11
  "name": "kxm",
12
12
  "source": "./plugins/kxm",
13
13
  "description": "Durable workflows, peer agents, and kxm tui",
14
- "version": "0.7.178",
14
+ "version": "0.7.179",
15
15
  "category": "development",
16
16
  "tags": ["kxm", "multi-agent", "workflows", "mcp"]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -15,6 +15,17 @@ All notable user-facing changes are documented here. The project follows [Semant
15
15
  maps, roster, routes, gates, roles, and workflow definitions. Pi/OMP package
16
16
  discovery now loads the tracked extension bundle, so the private TUI
17
17
  workspace is bundled rather than becoming an unresolved runtime dependency.
18
+ - **OMP can opt into a focused KXM status band with live subscription limits.**
19
+ `kxm plugin install --omp --status-band` installs the shared extension and
20
+ selects an OMP custom layout with native active-subscription usage, metered
21
+ cost, context, model, mode, branch, pull request, and subagent signals. The KXM hook line
22
+ omits idle, zero-count, clean-ship, cost, and normal local-hub noise while
23
+ retaining degraded hub, active work, inbox, waiting, dirty/ahead, and update
24
+ signals. The work widget retains known metered cost and suppresses unknown
25
+ cost. The flag is explicit because it changes OMP user configuration; restart
26
+ OMP after applying it.
27
+ - Plugin installation now treats an interrupted harness process with no exit
28
+ status as a failure for Pi, OMP, and Claude Code instead of reporting success.
18
29
 
19
30
  - **Hub project identity and its access key live in `.kxm/config.yaml`.**
20
31
  `hub.local` and `hub.cloud` hold the URL, the project id to present, and a
@@ -2,7 +2,7 @@
2
2
  title: "Decisions"
3
3
  description: "Decisions of medium significance or higher made by automated KXM work in this repository. One entry per decision: the options evaluated with their weights, and why the selected option won. Recorded the turn the decision is taken."
4
4
  audience: "agents and maintainers"
5
- updated: "2026-10-02"
5
+ updated: "2026-10-11"
6
6
  ---
7
7
 
8
8
  # Decisions
@@ -172,3 +172,29 @@ Evidence: Evidence: merge-base 77beda4 predates the CLI restructure; merge-tree
172
172
  - Selected: stash-apply onto a fresh lane off `origin/main`, take upstream
173
173
  for claude-bridge, `dist`, and `package.json`, and merge the rest.
174
174
  Evidence: Evidence: `git diff HEAD origin/main` on the stale branch showed upstream's claude-bridge fix and curl downloader already landed; the lane port keeps both those and the npm/`--all` behavior.
175
+
176
+ ## 2026-10-11 — OMP subscription status integration (extension)
177
+
178
+ - Context: KXM's extension already owns a hook status line while OMP can
179
+ render OAuth subscription quota through its native cached `usage`
180
+ segment. Adding quota to KXM's line would duplicate OMP data; changing
181
+ the OMP layout during every plugin install would unexpectedly overwrite
182
+ an operator's chosen status line.
183
+ - Options:
184
+ - Run `omp usage` from the KXM extension — weight 0.1. Direct, but adds
185
+ process work to refreshes, duplicates OMP's cache and rendering, and
186
+ expands the credential-bearing boundary.
187
+ - Configure the native OMP segment on every install — weight 0.3.
188
+ Discoverable, but silently mutates unrelated user configuration.
189
+ - Add explicit `kxm plugin install --omp --status-band` opt-in and use
190
+ OMP's native `usage` segment — weight 0.9. No duplicate quota
191
+ implementation; configuration mutation is deliberate and verifiable.
192
+ - Selected: explicit opt-in. The installer snapshots the three global
193
+ status-line entries, writes the focused layout, verifies effective
194
+ values in the current working directory, restores prior values, and
195
+ resets entries that were previously absent or `null`.
196
+ - Solid recommendation: keep subscription quota in OMP's native `usage`
197
+ segment and KXM workflow state in the separate hook status line.
198
+ - Interim recommendation: use the opt-in installer until OMP exposes a
199
+ first-class transactional status-preset API.
200
+ Evidence: `plugins/kxm/src/cli/plugins.ts`, `plugins/kxm/src/session-work.ts`, and `test/core/cli.test.ts`.
@@ -13,7 +13,7 @@ Output shown under examples was captured from a source checkout, inside a throwa
13
13
  - [Task to command](#task-to-command)
14
14
  - Setup: [`init`](#kxm-init), [`config`](#kxm-config), [`completion`](#kxm-completion), [`trust`](#kxm-trust)
15
15
  - Hub and sessions: [`hub`](#kxm-hub-view), [`session`](#kxm-session), [`dash`](#kxm-dash), [`studio`](#kxm-studio)
16
- - Harnesses, models, and roles: [`harness`](#kxm-harness), [`auth`](#kxm-auth), [`update`](#kxm-update), [`models`](#kxm-models), [`routes`](#kxm-routes), [`role`](#kxm-role)
16
+ - Harnesses, models, and roles: [`harness`](#kxm-harness), [`plugin`](#kxm-plugin), [`auth`](#kxm-auth), [`update`](#kxm-update), [`models`](#kxm-models), [`routes`](#kxm-routes), [`role`](#kxm-role)
17
17
  - Running work: [`lane`](#kxm-lane), [`land`](#kxm-land), [`assign`](#kxm-assign), [`run`](#kxm-run), [`runs`](#kxm-runs), [`docs`](#kxm-docs), [`runtime`](#kxm-runtime), [`agent`](#kxm-agent), [`workflow`](#kxm-workflow), [`gate`](#kxm-gate), [`peer`](#kxm-peer), [`task`](#kxm-task), [`goal`](#kxm-goal), [`suggest`](#kxm-suggest), [`explain`](#kxm-explain)
18
18
  - Context and learning: [`context`](#kxm-context), [`memory`](#kxm-memory), [`skills`](#kxm-skills), [`improve`](#kxm-improve), [`routing`](#kxm-routing), [`prices`](#kxm-prices)
19
19
  - Operations: [`backup`](#kxm-backup), [`restore`](#kxm-restore), [`tenant`](#kxm-tenant), [`ssh`](#kxm-ssh), [`help`](#kxm-help)
@@ -699,13 +699,14 @@ Prints recent tasks (workflow runs) and plans (journal entries) from the local h
699
699
  - Side effects: on first use it mints a 24-hour operator session token and writes it to `<KXM_USER_CONFIG_DIR>/session.token` (mode 0600), and it caches the brief in `.kxm/state/session-brief.json`. Under `--dry-run` it still probes the hub and prints the brief, but it mints no token, writes neither file, and appends a `dry run: would write <file>` line for each (JSON: `dryRun` and `planned`); with no saved token the output carries no token. `--token --dry-run` plans only the token file.
700
700
  - The default text output ends with the session token, and `--token` prints only the token. Treat the output as a credential.
701
701
  - JSON (`kxm.session-brief.v1`) keys: `generatedAt`, `staleSeconds`, `source`, `hub` (`state`, `evidence`, `online`, `url`, `scope`), `stats`, `tasks`, `plans`, `statusLine`, `widgetLines`, `sessionToken`.
702
+ - The status line omits cost because harness-native bands already own that signal. The work widget includes known metered cost and suppresses unknown cost.
702
703
 
703
704
  ```bash
704
705
  kxm session brief
705
706
  ```
706
707
 
707
708
  ```text
708
- kxm hub:on · idle · dirty
709
+ kxm · dirty
709
710
 
710
711
  No recent tasks or plans.
711
712
 
@@ -717,7 +718,7 @@ kxm session brief --status
717
718
  ```
718
719
 
719
720
  ```text
720
- kxm hub:on · idle
721
+ kxm
721
722
  ```
722
723
 
723
724
  ```bash
@@ -725,7 +726,7 @@ kxm session brief --json
725
726
  ```
726
727
 
727
728
  ```text
728
- {"schema":"kxm.session-brief.v1","generatedAt":"2026-09-23T13:49:55.253Z","staleSeconds":5,"source":"legacy","hub":{"state":"off","evidence":"probed","online":false,"url":"http://127.0.0.1:59998","scope":"loopback"},"stats":{"activeTasks":0,"waitingTasks":0,"planCount":0,"inbox":0,"runTotal":0},"tasks":[],"plans":[],"statusLine":"kxm hub:off · idle",...,"sessionToken":"<token>"}
729
+ {"schema":"kxm.session-brief.v1","generatedAt":"2026-09-23T13:49:55.253Z","staleSeconds":5,"source":"legacy","hub":{"state":"off","evidence":"probed","online":false,"url":"http://127.0.0.1:59998","scope":"loopback"},"stats":{"activeTasks":0,"waitingTasks":0,"planCount":0,"inbox":0,"runTotal":0},"tasks":[],"plans":[],"statusLine":"kxm · hub:off",...,"sessionToken":"<token>"}
729
730
  ```
730
731
 
731
732
  Before the first token exists:
@@ -735,7 +736,7 @@ kxm session brief --status --dry-run
735
736
  ```
736
737
 
737
738
  ```text
738
- kxm hub:on · idle · dirty
739
+ kxm · dirty
739
740
  dry run: would write ~/.config/kxm/session.token
740
741
  dry run: would write /work/proj/.kxm/state/session-brief.json
741
742
  ```
@@ -952,6 +953,34 @@ kxm harness list --json
952
953
  {"schema":"kxm.cli-result.v1","ok":true,"command":"harness list","defaultHarness":"pi","harnesses":[{"id":"pi","label":"Pi","default":true,"mode":"headless","detected":false,"authenticated":false,"dispatch":{"status":"no","supported":false,"reason":"not_detected"},"canUpdate":{"self":true,"extensions":true,"models":true},"issues":[]},...]}
953
954
  ```
954
955
 
956
+ ## `kxm plugin`
957
+
958
+ ### `kxm plugin install`
959
+
960
+ ```text
961
+ kxm plugin install [--all | --pi | --omp | --claude] [--status-band]
962
+ ```
963
+
964
+ Installs the KXM extension into every discovered supported harness, or only the explicitly selected harnesses. `--status-band` is an explicit OMP-only opt-in: after installing the extension, it switches OMP to a focused custom status layout with model, mode, branch, pull request, subagent, active-subscription usage, metered cost, and context signals. It uses OMP's native background usage fetch and does not call `omp usage`. To support safe rollback, KXM parses OMP's global config file and retains only the three existing `statusLine` entries for the duration of the command; it does not use credential values.
965
+
966
+ | Option | Argument | Default | Description |
967
+ |---|---|---|---|
968
+ | `--all` | none | on when no harness flag is present | Install into every discovered supported harness |
969
+ | `--pi` | none | off | Install into Pi |
970
+ | `--omp` | none | off | Install into OMP |
971
+ | `--claude` | none | off | Install into Claude Code |
972
+ | `--status-band` | none | off | Replace OMP's status layout with the focused subscription layout |
973
+
974
+ - Mutates the selected harness installations. `--status-band` asks OMP for its global config directory, snapshots the three global status-line entries from `config.yml` or `config.yaml`, writes through `omp config set`, and verifies the effective values in the current working directory. On failure it restores prior values and resets entries that were previously absent or `null`. Restart OMP afterward.
975
+ - `--dry-run` reports the install and status-band intent without invoking a harness command.
976
+ - `--status-band` fails when OMP is not selected or detected. A failed or locally shadowed OMP configuration is reported as a failed OMP result rather than a successful install; verification covers the directory where the command runs, not every other project's OMP overrides.
977
+
978
+ ```bash
979
+ kxm plugin install --omp --status-band
980
+ ```
981
+
982
+ Not run in this reference: installs a plugin and changes OMP user configuration.
983
+
955
984
  ## `kxm auth`
956
985
 
957
986
  ### `kxm auth token`
@@ -323,11 +323,11 @@ Proposes a change to one authoritative state key. Despite its name, it only prop
323
323
 
324
324
  Returns `{ "proposalId" }`. Blocked by the `read-only` preset; under an attempt token it needs an explicit grant.
325
325
 
326
- ## Pi extension commands
326
+ ## Pi and OMP extension commands
327
327
 
328
- The Pi extension connects the session to the hub at start, registers the 19 tools, and adds two slash commands. It also keeps a `kxm` status line and `kxm-work` and `kxm-progress` widgets, refreshed after every turn.
328
+ The shared Pi-compatible extension connects the session to the hub at start, registers the 19 tools, and adds two slash commands. It also keeps a concise `kxm` status line and `kxm-work` and `kxm-progress` widgets, refreshed after every turn.
329
329
 
330
- In Pi:
330
+ In Pi or OMP:
331
331
 
332
332
  ```text
333
333
  /kxm
@@ -344,7 +344,9 @@ In Pi:
344
344
  | `/kxm memory` | Shows the project memory brief by running `kxm memory brief` (or `$KXM_BIN`) |
345
345
  | `/kxm help` | Lists the subcommands. Any unknown subcommand shows the same help |
346
346
 
347
- The task picker, `Continue KXM work?`, lists recent tasks and plans and puts the chosen prompt in the editor. It also appears when a Pi TUI session starts, begins a new session or forks, unless `KXM_SESSION_BRIEF=off`.
347
+ The task picker, `Continue KXM work?`, lists recent tasks and plans and puts the chosen prompt in the editor. It also appears when a Pi or OMP TUI session starts, begins a new session or forks, unless `KXM_SESSION_BRIEF=off`.
348
+
349
+ OMP can also show the active OAuth subscription's quota windows in its native status band. Install the extension and opt into KXM's focused layout with `kxm plugin install --omp --status-band`, then restart OMP. The layout keeps model, mode, branch, pull request, subagent, subscription usage, metered cost, and context signals; it does not add OMP's inline `status` segment because OMP already renders the KXM hook status on its own line. If `statusLine.showHookStatus` is disabled, the native usage and cost segments remain but the separate KXM line stays hidden.
348
350
 
349
351
  Inbound requests arrive as a displayed message that starts a model turn: `steer` at the next decision boundary, `followUp` (and `nextTurn`, which an unattended worker cannot wait on) after the current work. The final response is returned as the reply. If the model provider fails, the request stays `delivered` so a supervised worker can recover it. The extension also registers model providers; see [Harness routing](harness-routing.md) and [Nous providers](../guides/nous-providers.md).
350
352
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextmind/kxm",
3
- "version": "0.7.178",
3
+ "version": "0.7.179",
4
4
  "description": "KXM local-first multi-agent orchestration and operator dashboard",
5
5
  "type": "module",
6
6
  "author": "KontextMind",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "kxm",
4
4
  "displayName": "KXM",
5
- "version": "0.7.178",
5
+ "version": "0.7.179",
6
6
  "description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
7
7
  "author": {
8
8
  "name": "KontextMind",
@@ -886,12 +886,12 @@ import { spawnSync } from "node:child_process";
886
886
  import { randomUUID } from "node:crypto";
887
887
  import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
888
888
  import { join as join4 } from "node:path";
889
- function hubPrefix(hub) {
889
+ function hubStatusPart(hub) {
890
890
  const suffix = hub?.scope === "remote" ? "/remote" : "";
891
- if (hub?.state === "on" || hub?.state === void 0 && hub?.online === true) return `kxm hub:on${suffix}`;
892
- if (hub?.state === "off" || hub?.state === void 0 && hub?.online === false) return `kxm hub:off${suffix}`;
893
- if (hub?.state === "unknown") return `kxm hub:unknown${suffix}`;
894
- return "kxm";
891
+ if (hub?.state === "off" || hub?.state === void 0 && hub?.online === false) return `hub:off${suffix}`;
892
+ if (hub?.state === "unknown") return `hub:unknown${suffix}`;
893
+ if (hub?.scope === "remote") return "hub:remote";
894
+ return void 0;
895
895
  }
896
896
  function truncate(value, width) {
897
897
  const text = value.replace(/\s+/g, " ").trim();
@@ -969,17 +969,17 @@ function readGitShip(cwd) {
969
969
  }
970
970
  function formatCostLine(input) {
971
971
  if (!input) return void 0;
972
- if (input.sessionCostUsd === void 0 && input.runCostUsd === void 0) return "unknown";
972
+ if (input.sessionCostUsd === void 0 && input.runCostUsd === void 0) return void 0;
973
973
  const sess = input.sessionCostUsd !== void 0 ? `$${input.sessionCostUsd.toFixed(2)} sess` : void 0;
974
974
  const run = input.runCostUsd !== void 0 ? `$${input.runCostUsd.toFixed(2)} run` : void 0;
975
975
  const route = input.harness && input.model ? `${input.harness}/${input.model}` : input.model ?? void 0;
976
976
  const parts = [sess, run, route].filter(Boolean);
977
- return parts.length > 0 ? parts.join(" \xB7 ") : "unknown";
977
+ return parts.length > 0 ? parts.join(" \xB7 ") : void 0;
978
978
  }
979
- function renderStatusLine(statsOrBrief, current, hub, ship, updateLatest, cost) {
979
+ function renderStatusLine(statsOrBrief, current, hub, ship, updateLatest) {
980
980
  if ("schema" in statsOrBrief && statsOrBrief.schema === "kxm.session-brief.v1") {
981
981
  const brief = statsOrBrief;
982
- if (!current && !hub && !ship && !updateLatest && !cost) {
982
+ if (!current && !hub && !ship && !updateLatest) {
983
983
  return brief.statusLine;
984
984
  }
985
985
  return formatSessionStatusLine(
@@ -987,46 +987,39 @@ function renderStatusLine(statsOrBrief, current, hub, ship, updateLatest, cost)
987
987
  current,
988
988
  hub ?? brief.hub,
989
989
  ship,
990
- updateLatest,
991
- cost ?? brief.cost
990
+ updateLatest
992
991
  );
993
992
  }
994
- return formatSessionStatusLine(statsOrBrief, current, hub, ship, updateLatest, cost);
995
- }
996
- function formatSessionStatusLine(stats, current, hub, ship, updateLatest, cost) {
997
- const head = hubPrefix(hub);
998
- if (!current && stats.activeTasks === 0 && stats.planCount === 0 && stats.inbox === 0) {
999
- const idle = hub?.online === void 0 && hub?.state === void 0 ? "kxm idle" : `${head} \xB7 idle`;
1000
- const withShip = ship?.dirty ? `${idle} \xB7 dirty` : ship && ship.ahead > 0 ? `${idle} \xB7 ${ship.ahead} local` : idle;
1001
- const withCost = cost ? `${withShip} \xB7 ${cost}` : withShip;
1002
- const finalLine = updateLatest ? `${withCost} \xB7 upd ${updateLatest}` : withCost;
1003
- return finalLine.length <= 80 ? finalLine : `${finalLine.slice(0, 79)}\u2026`;
1004
- }
1005
- const parts = [];
1006
- if (current?.kind === "task") parts.push(`${head} ${current.detail}`);
1007
- else if (current?.kind === "plan") parts.push(`${head} plan ${truncate(current.detail, 36)}`);
1008
- else parts.push(head);
1009
- parts.push(`${stats.activeTasks} task${stats.activeTasks === 1 ? "" : "s"}`);
993
+ return formatSessionStatusLine(statsOrBrief, current, hub, ship, updateLatest);
994
+ }
995
+ function formatSessionStatusLine(stats, current, hub, ship, updateLatest) {
996
+ const parts = ["kxm"];
997
+ const hubPart = hubStatusPart(hub);
998
+ if (hubPart) parts.push(hubPart);
999
+ if (current?.kind === "task") parts.push(current.detail);
1000
+ else if (current?.kind === "plan") parts.push(`plan ${truncate(current.detail, 36)}`);
1001
+ if (stats.activeTasks > 0) parts.push(`${stats.activeTasks} task${stats.activeTasks === 1 ? "" : "s"}`);
1010
1002
  if (stats.waitingTasks > 0) parts.push(`${stats.waitingTasks} waiting`);
1011
- parts.push(`${stats.planCount} plan${stats.planCount === 1 ? "" : "s"}`);
1003
+ if (stats.planCount > 0) parts.push(`${stats.planCount} plan${stats.planCount === 1 ? "" : "s"}`);
1012
1004
  if (stats.inbox > 0) parts.push(`inbox ${stats.inbox}`);
1013
1005
  if (ship?.dirty) parts.push("dirty");
1014
1006
  else if (ship && ship.ahead > 0) parts.push(`${ship.ahead} local`);
1015
- if (cost) parts.push(cost);
1016
1007
  if (updateLatest) parts.push(`upd ${updateLatest}`);
1017
- const line = parts.join(" \xB7 ");
1018
- return line.length <= 80 ? line : `${line.slice(0, 79)}\u2026`;
1008
+ return truncate(parts.join(" \xB7 "), 80);
1019
1009
  }
1020
1010
  function formatSessionWidget(stats, current, hub, ship, updateLatest, cost) {
1021
- const hubMark = hub?.state === "on" || hub?.online === true ? "hub:on " : hub?.state === "off" || hub?.online === false ? "hub:off " : hub?.state === "unknown" ? "hub:unknown " : "";
1022
- const lines = [
1023
- `KXM ${hubMark}${stats.activeTasks} tasks ${stats.waitingTasks} waiting ${stats.planCount} plans inbox ${stats.inbox}`
1024
- ];
1011
+ const suffix = hub?.scope === "remote" ? "/remote" : "";
1012
+ const hubMark = hub?.state === "on" || hub?.state === void 0 && hub?.online === true ? `hub:on${suffix}` : hub?.state === "off" || hub?.state === void 0 && hub?.online === false ? `hub:off${suffix}` : hub?.state === "unknown" ? `hub:unknown${suffix}` : void 0;
1013
+ const summary = ["KXM", hubMark];
1014
+ if (stats.activeTasks > 0) summary.push(`${stats.activeTasks} task${stats.activeTasks === 1 ? "" : "s"}`);
1015
+ if (stats.waitingTasks > 0) summary.push(`${stats.waitingTasks} waiting`);
1016
+ if (stats.planCount > 0) summary.push(`${stats.planCount} plan${stats.planCount === 1 ? "" : "s"}`);
1017
+ if (stats.inbox > 0) summary.push(`inbox ${stats.inbox}`);
1018
+ const lines = [summary.filter(Boolean).join(" \xB7 ")];
1025
1019
  if (current) lines.push(`now ${current.kind} ${truncate(current.detail, 56)}`);
1026
- else if (stats.latestPlan) lines.push(`plan ${truncate(stats.latestPlan, 60)}`);
1027
- else lines.push("now no selected work");
1028
- lines.push(formatShipLine(ship));
1029
- if (cost) lines.push(`cost ${cost}`);
1020
+ else if (stats.latestPlan) lines.push(`plan ${truncate(stats.latestPlan, 60)}`);
1021
+ if (ship?.dirty || ship && ship.ahead > 0) lines.push(formatShipLine(ship));
1022
+ if (cost && cost !== "unknown") lines.push(`cost ${cost}`);
1030
1023
  if (updateLatest) lines.push(`update ${updateLatest} available \xB7 kxm update --kxm`);
1031
1024
  return lines;
1032
1025
  }
@@ -1046,7 +1039,7 @@ function buildSessionBrief(snapshot, current, hub, ship, updateLatest, cost, ses
1046
1039
  const tasks = uniqueLabels(recentTasks(snapshot.runs).map(taskItem));
1047
1040
  const plans = uniqueLabels(snapshot.plans.slice(0, MAX_SESSION_BRIEF_PLANS).map(planItem));
1048
1041
  const resolvedHub = hub ?? { state: "off", evidence: "unconfigured", online: false };
1049
- const statusLine = formatSessionStatusLine(stats, current, resolvedHub, ship, updateLatest, cost);
1042
+ const statusLine = formatSessionStatusLine(stats, current, resolvedHub, ship, updateLatest);
1050
1043
  const widgetLines = formatSessionWidget(stats, current, resolvedHub, ship, updateLatest, cost);
1051
1044
  return {
1052
1045
  schema: SESSION_BRIEF_SCHEMA,
@@ -1110,7 +1103,7 @@ function estimateSessionCost(stateDir) {
1110
1103
  latestModel = r.effectiveModel ?? r.requestedModel ?? latestModel;
1111
1104
  latestHarness = r.harness ?? latestHarness;
1112
1105
  }
1113
- if (!hasMetered) return "unknown";
1106
+ if (!hasMetered) return void 0;
1114
1107
  const route = latestHarness && latestModel ? `${latestHarness}/${latestModel}` : latestModel;
1115
1108
  return `$${totalCost.toFixed(2)} sess${route ? ` \xB7 ${route}` : ""}`;
1116
1109
  } catch {
@@ -1147,8 +1140,7 @@ function loadSessionBrief(cwd, env = process.env, current, hub, options = {}) {
1147
1140
  current,
1148
1141
  effectiveHub,
1149
1142
  options.ship,
1150
- options.updateLatest,
1151
- effectiveCost
1143
+ options.updateLatest
1152
1144
  );
1153
1145
  const widgetLines = formatSessionWidget(
1154
1146
  cached.stats,
@@ -1213,8 +1205,7 @@ async function loadSessionBriefAsync(cwd, env = process.env, current, hub, optio
1213
1205
  current,
1214
1206
  effectiveHub,
1215
1207
  options.ship,
1216
- void 0,
1217
- effectiveCost
1208
+ void 0
1218
1209
  );
1219
1210
  const widgetLines = formatSessionWidget(
1220
1211
  cached.stats,