myshell-tools 3.0.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -1
- package/README.md +32 -21
- package/dist/cli.js +22 -6
- package/dist/cli.js.map +1 -1
- package/dist/commands/cost.js +44 -25
- package/dist/commands/cost.js.map +1 -1
- package/dist/commands/doctor.d.ts +17 -4
- package/dist/commands/doctor.js +56 -34
- package/dist/commands/doctor.js.map +1 -1
- package/dist/core/native-session.d.ts +57 -0
- package/dist/core/native-session.js +68 -0
- package/dist/core/native-session.js.map +1 -0
- package/dist/core/orchestrate.js +25 -4
- package/dist/core/orchestrate.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/infra/config.d.ts +8 -0
- package/dist/infra/config.js.map +1 -1
- package/dist/infra/credentials.d.ts +35 -0
- package/dist/infra/credentials.js +59 -1
- package/dist/infra/credentials.js.map +1 -1
- package/dist/infra/health.d.ts +57 -0
- package/dist/infra/health.js +96 -0
- package/dist/infra/health.js.map +1 -0
- package/dist/infra/insights.d.ts +14 -0
- package/dist/infra/insights.js +31 -0
- package/dist/infra/insights.js.map +1 -1
- package/dist/interface/menu.d.ts +70 -5
- package/dist/interface/menu.js +195 -26
- package/dist/interface/menu.js.map +1 -1
- package/dist/interface/render.js +11 -8
- package/dist/interface/render.js.map +1 -1
- package/dist/providers/claude.d.ts +24 -8
- package/dist/providers/claude.js +65 -15
- package/dist/providers/claude.js.map +1 -1
- package/dist/providers/codex-parse.js +14 -2
- package/dist/providers/codex-parse.js.map +1 -1
- package/dist/providers/codex.d.ts +13 -1
- package/dist/providers/codex.js +19 -8
- package/dist/providers/codex.js.map +1 -1
- package/dist/providers/port.d.ts +15 -0
- package/dist/ui/help.d.ts +17 -0
- package/dist/ui/help.js +106 -0
- package/dist/ui/help.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,7 +9,58 @@ and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.
|
|
|
9
9
|
### Pending
|
|
10
10
|
- Live cross-vendor review demonstration (requires an authenticated Codex CLI).
|
|
11
11
|
- Cross-OS CI execution (requires a public remote).
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
## [3.2.0]
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **Tokens, not dollars, on the everyday UI.** myshell-tools drives your *subscription* CLIs (flat fee), so per-task dollar figures were misleading — they don't map to subscription billing and read as bloat. The control-panel status line and the live per-task output now show **real, measured token counts**; the always-on money meter ("Today: $… · session so far: $…") is gone. The `tier-done` and final-summary lines show tokens; the control-panel line shows tasks + tokens.
|
|
17
|
+
- **`cost` reframed as "usage & efficiency".** It now leads with real tokens (overall + per model) and a **billing-agnostic routing-efficiency ratio** ("routing picked cheaper-tier models — ~N× less than always-flagship"), which is honest under a subscription. The dollar estimate is demoted to a clearly-captioned section: **"Estimated cost — API-equivalent (list price), not your subscription bill"** — and both the routed and always-flagship figures use the **same basis** (list price × tokens), so they're apples-to-apples and internally consistent (routed never exceeds flagship). The previous mix of a provider-reported total against a list-price counterfactual could read as a contradiction; that's resolved. New pure `formatTokens` helper; `SpendSummary` gained `todayTokens`/`totalTokens`; the `tier-done` event carries real `inputTokens`/`outputTokens`.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- **Version status in the header** — the control-panel title now always tells you where you stand: `myshell-tools v3.2.0 (latest)` when current, or `myshell-tools v3.2.0 → 3.3.0 available` when a newer release exists. No more guessing whether you're up to date. (`versionStatusLabel`, pure + tested.)
|
|
21
|
+
- **npx-awareness** — when run via `npx myshell-tools`, the tool now detects it (`isRunningUnderNpx`) and is honest about updates: instead of silently running a global install that the next `npx` invocation would ignore (npx re-serves its own cache), it shows `Install globally to stay current: npm install -g myshell-tools@latest`. Silent auto-update and the `[u]` key are suppressed under npx because they cannot persist there.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- The update banner and `[u]` Update-now action appear **only when a newer version is genuinely available** (unchanged), and are now also gated on the update being able to persist (not under npx).
|
|
25
|
+
|
|
26
|
+
### Performance
|
|
27
|
+
- **Control-panel menu no longer re-parses the ledger on every keystroke.** The spend summary is computed once and cached, and only refreshed after a task actually runs (the only time the ledger changes). Previously each keypress re-read and re-parsed the unbounded `ledger.jsonl`; on an active ledger that was tens-to-hundreds of ms of avoidable latency per keystroke. The menu hot path is now O(1) in ledger size.
|
|
28
|
+
|
|
29
|
+
### Added (experimental, opt-in)
|
|
30
|
+
- **Native session continuity for Claude and Codex (`nativeSessions`, default OFF).** The default path replays a compacted history block into every turn's prompt so stateless `-p`/`exec` calls have context — correct and provider-portable, but it re-sends prior context each turn. When enabled, a conversation that stays on one provider reuses that provider's *native* session and the replayed history is skipped — better context fidelity and less re-sent context (matters most for subscription rate-limit headroom; it isn't a dollar saving on a flat plan). Two id models, handled transparently:
|
|
31
|
+
- **Claude** — we choose the id (the conversation id): `--session-id` to establish, `--resume` to continue.
|
|
32
|
+
- **Codex** — Codex generates its own thread id; myshell-tools captures it from the `thread.started` event, persists it on the turn in the conversation log, and resumes via `codex exec resume <thread-id>` on the next Codex turn.
|
|
33
|
+
|
|
34
|
+
If a turn routes to a provider with no active native session, it transparently falls back to history replay — so switching providers never loses context. Enable via Settings → `[4] Native sessions` or `"nativeSessions": true`.
|
|
35
|
+
- **Verification:** the planning logic, the Claude/Codex CLI-arg construction, the Codex thread-id capture (contract test against the recorded transcript), and the persist-on-the-turn behavior are all unit/contract-tested. The one thing only a live CLI can prove — that resuming actually carries context — is a **gated integration test** you run with your own authenticated CLIs: `MYSHELL_NATIVE_SESSION_E2E=1 npm run test:integration` (covers both Claude and Codex). Off until you opt in; the feature defaults off until you've confirmed it on your setup. opencode has no documented resume flag yet, so it stays on history replay.
|
|
36
|
+
- **Per-command help.** `myshell-tools <command> --help` now shows focused, command-specific help (e.g. `login --help` explains `--code`/`--browser` and the container flow; `cost --help` is honest about subscription-vs-API billing) instead of the generic command list. Bare `--help` still shows the global list. Pure `commandHelpText`, unit-tested.
|
|
37
|
+
- **Self-health, surfaced automatically — no command to run.** The control panel now evaluates its own environment at startup (Node version, state-directory writability, pricing-table staleness) and shows a short, actionable warning **only when something is actually wrong**. No problems → nothing shown. Pure `evaluateHealth` (fully unit-tested) + a one-shot `probeStateWritable`. The diagnostics that were already visible in the header (provider install/auth, Claude-token expiry) are not duplicated.
|
|
38
|
+
- **`doctor --fix` offers to refresh an expiring Claude token.** When Claude is signed in and the stored `sk-ant-oat…` token is expired or inside the 14-day warning window, the fix pass offers a one-keypress re-login — closing the gap where the expiry was *reported* but never *actionable*.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- **Retired the `doctor` name from the user-facing surface.** "Doctor" was borrowed jargon, and *requiring* a diagnostic command is itself friction — health now surfaces on its own (see above). The command still exists as a hidden, scriptable health check for support/CI, reachable as `status`, `check`, or `doctor` (the old name still works for muscle-memory and existing scripts); it's just no longer advertised in `--help`. Its report header now reads "environment health" rather than "doctor".
|
|
42
|
+
|
|
43
|
+
### Why
|
|
44
|
+
- Users running the convenience `npx` path were landing on a stale cached version (e.g. 2.8.0) and could not understand why "auto-update" never advanced them — npx ignores the global install our updater performs. The tool now names that situation and points to the durable fix instead of failing silently.
|
|
45
|
+
|
|
46
|
+
## [3.1.0]
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
- **Claude token lifetime awareness** — `claude setup-token` mints an `sk-ant-oat…` token valid ~1 year; the tool now records when it was captured and surfaces the remaining lifetime. `doctor` shows `token: expires ~YYYY-MM-DD (NNN days left)`, and the control-panel header shows a concise warning only when the token is near expiry or already expired (`claudeTokenStatus`, pure + tested). No nagging when the token is healthy.
|
|
50
|
+
|
|
51
|
+
## [3.0.0]
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
- **opencode contract test** — parser pinned to a recorded real `opencode run --format json` transcript.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
- **Wizard polish** — first-run prompts are simple `(y/n)` / `(Y/n)` instead of requiring the user to type `yes`.
|
|
58
|
+
- **Chat feels like a chat** — the conversation prompt is a bare `> ` (not `myshell-tools>`).
|
|
59
|
+
- **Claude token env-scoping** — the stored OAuth token is injected only into the provider child process env (and only when not already present), never globally exported.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
- **Browser→code login retry** — when the browser/localhost OAuth flow can't work (containers/SSH), the login offers an interactive `--code` retry.
|
|
63
|
+
- **Auth-aware routing** — `route()` prefers authenticated + available providers; auth errors short-circuit (no wasted failover/escalation).
|
|
13
64
|
|
|
14
65
|
## [2.17.0]
|
|
15
66
|
|
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
**Hierarchical, multi-provider AI orchestration for your shell — over the CLIs you already use.**
|
|
4
4
|
|
|
5
|
-
`myshell-tools` routes each task to the *cheapest* model likely to succeed, runs it on your real codebase, optionally has a **different vendor** review the result, and shows you exactly what it did and
|
|
5
|
+
`myshell-tools` routes each task to the *cheapest* model likely to succeed, runs it on your real codebase, optionally has a **different vendor** review the result, and shows you exactly what it did and how many real tokens it used — with **no fabricated data, ever**.
|
|
6
6
|
|
|
7
|
-
> **Status: `3.
|
|
7
|
+
> **Status: `3.2.0` — honest, tested, and real.** Claude, Codex, and opencode (experimental) all work, provider auth is detected for real, and the header always shows whether you're on the latest version (`(latest)` or `→ x.y.z available`).
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -38,13 +38,14 @@ myshell-tools
|
|
|
38
38
|
|
|
39
39
|
Using one frontier model for everything is wasteful (renaming a variable doesn't need Opus) and single‑model output has blind spots. `myshell-tools` addresses both, honestly:
|
|
40
40
|
|
|
41
|
-
- **Cost‑aware routing** — trivial work goes to the cheap tier (Haiku / GPT‑5 mini), real implementation to the mid tier, hard calls to the flagship.
|
|
41
|
+
- **Cost‑aware routing** — trivial work goes to the cheap tier (Haiku / GPT‑5 mini), real implementation to the mid tier, hard calls to the flagship. The efficiency shows up as a billing‑agnostic ratio (how many flagship tokens you avoided), not a dollar figure — because you're on a subscription, not metered API billing.
|
|
42
42
|
- **Efficiency modes** — three policy presets control the cost/quality trade-off:
|
|
43
43
|
- `cost-saver` — routes to the cheapest capable model for each tier; only runs the cross-vendor review pass on *critical*-risk tasks (not every IC call). An optional `maxCostUsd` cap halts further escalation/review once spend reaches the limit.
|
|
44
44
|
- `balanced` — the default; routes intelligently and reviews high-risk work.
|
|
45
45
|
- `quality-first` — always reviews IC output for high/critical tasks, regardless of cost.
|
|
46
46
|
- **Cross‑vendor adversarial review** — a *different vendor* checks the first model's output (Codex reviewing Claude, or vice‑versa). Different families, different blind spots. Review gating depends on mode; see Efficiency modes above.
|
|
47
47
|
- **Multi-turn context continuity** — follow-up messages carry real context. Prior conversation turns are compacted into a bounded history block (~6 k chars, most recent 12 turns) and replayed to the model, so it actually knows what was said earlier. Confidence envelopes are stripped before replay to save tokens.
|
|
48
|
+
- **Native session continuity** *(experimental, opt-in, default off)* — when enabled, a conversation that stays on one provider reuses that provider's *native* session instead of replaying the history block, for better fidelity and less re-sent context. **Claude** uses a session id we choose (the conversation id); **Codex** has its generated thread id captured (from `thread.started`), persisted on the turn, and resumed via `codex exec resume`. Falls back to history replay automatically when a turn routes to a provider without an active session. Because the live behavior depends on your CLI, it ships off with a gated verification test covering both providers — `MYSHELL_NATIVE_SESSION_E2E=1 npm run test:integration` — and you enable it (Settings → Native sessions) only after it passes on your setup.
|
|
48
49
|
- **Container / SSH sign-in** — `myshell-tools login` auto-detects headless and cloud-IDE environments (Replit, Codespaces, Gitpod, SSH sessions) and switches to a no-localhost sign-in flow automatically. Force either flow with `--code` or `--browser`. For Claude, the tool prompts you to paste the `sk-ant-oat…` OAuth token printed by `claude setup-token`, stores it locally (mode 0600), and injects it at startup — no manual env-var wiring needed. For Codex, a device-code flow is used.
|
|
49
50
|
- **opencode provider (experimental)** — auto-detected; works instantly with free hosted models (no keys). `[o]` is always visible in the Auth section: it installs `opencode-ai` (with consent) if missing, then runs `opencode auth login`. Route to it explicitly or let the policy fall back to it automatically.
|
|
50
51
|
- **Routing prefers advertised models** — detection passes each provider's actual model list to `route()`, which picks the cheapest model the CLI *actually has*, not just the cheapest in the pricing table. Falls back gracefully if the advertised list doesn't match any pricing entry.
|
|
@@ -75,7 +76,7 @@ You need **one** to start; install **both** claude and codex to unlock cross‑v
|
|
|
75
76
|
|
|
76
77
|
### `npx` vs. `npm install -g` — which to choose?
|
|
77
78
|
|
|
78
|
-
`npx myshell-tools` is convenient for a one-off run but **caches the downloaded version** — subsequent invocations reuse the cache and **will not pick up new releases** automatically.
|
|
79
|
+
`npx myshell-tools` is convenient for a one-off run but **caches the downloaded version** — subsequent invocations reuse the cache and **will not pick up new releases** automatically. The tool detects when it's running under npx and, if a newer version exists, tells you exactly that instead of pretending to self-update (a global install run from an npx process is ignored by the next `npx` invocation). If you're stuck on an old version via npx, clear the cache (`rm -rf ~/.npm/_npx`) or — better — install globally:
|
|
79
80
|
|
|
80
81
|
For day-to-day use, a global install is recommended:
|
|
81
82
|
|
|
@@ -130,7 +131,6 @@ Commands:
|
|
|
130
131
|
run <task...> Run a one-shot task and exit
|
|
131
132
|
repl Plain line REPL (no menu)
|
|
132
133
|
login [prov] Sign in to a provider (claude or codex) via its own OAuth
|
|
133
|
-
doctor Check providers, auth, environment
|
|
134
134
|
cost Show real spend + the cost-routing counterfactual
|
|
135
135
|
|
|
136
136
|
Options:
|
|
@@ -144,19 +144,26 @@ These are **actual, unedited** outputs (your costs/timings will differ):
|
|
|
144
144
|
|
|
145
145
|
```text
|
|
146
146
|
$ myshell-tools run "what is 2 plus 2"
|
|
147
|
-
Classified: worker tier, low risk — tier: worker keyword 'what is'; risk: defaulting to low
|
|
148
147
|
▶ WORKER (claude/claude-haiku-4-5) attempt 1
|
|
149
148
|
2 plus 2 equals 4.
|
|
150
|
-
✓ tier done — confidence: 100%,
|
|
151
|
-
Success — tier: worker,
|
|
149
|
+
✓ tier done — confidence: 100%, 312 tokens, duration: 5648ms
|
|
150
|
+
Success — tier: worker, 312 tokens, attempts: 1, session: 0dbfe2e3-…
|
|
152
151
|
```
|
|
153
152
|
|
|
154
|
-
The confidence (`100%`) is **parsed from the model's own structured reply**, not invented. The
|
|
153
|
+
The confidence (`100%`) is **parsed from the model's own structured reply**, not invented. The token count is the **CLI's own reported usage** — real and measured. Because myshell-tools drives your *subscription* CLIs (not metered API keys), the hot path shows tokens, not dollars; a per-task dollar figure wouldn't map to flat subscription billing. If you want a rough API-equivalent cost estimate, it lives in `myshell-tools cost`.
|
|
155
154
|
|
|
156
|
-
### Health
|
|
155
|
+
### Health — automatic, no command needed
|
|
156
|
+
|
|
157
|
+
The control panel checks its own environment on every launch (Node version, whether the state directory is writable, pricing freshness) and shows a short, actionable warning **only when something is actually wrong**. When everything is fine, it stays quiet — you never run a "doctor" command.
|
|
158
|
+
|
|
159
|
+
If you want the full report explicitly (handy for support threads or CI), it's still there as a hidden, scriptable command — `status`, `check`, or `doctor`:
|
|
157
160
|
|
|
158
161
|
```text
|
|
159
|
-
$ myshell-tools
|
|
162
|
+
$ myshell-tools status
|
|
163
|
+
myshell-tools — environment health
|
|
164
|
+
Platform: linux
|
|
165
|
+
Node: v22.19.0
|
|
166
|
+
...
|
|
160
167
|
Providers
|
|
161
168
|
✓ claude — installed, version: 2.1.157 (Claude Code)
|
|
162
169
|
auth: signed in (pro)
|
|
@@ -165,21 +172,25 @@ Providers
|
|
|
165
172
|
Ready — at least one provider is available.
|
|
166
173
|
```
|
|
167
174
|
|
|
168
|
-
###
|
|
175
|
+
### Usage & efficiency (`cost`)
|
|
176
|
+
|
|
177
|
+
This is a *subscription* tool, so the everyday UI shows **real, measured tokens** — never per-task dollars, which wouldn't map to flat subscription billing. The on-demand `cost` view leads with tokens and a **billing-agnostic routing-efficiency ratio**, then offers a clearly-captioned API-equivalent dollar estimate for anyone who wants the magnitude:
|
|
169
178
|
|
|
170
179
|
```text
|
|
171
180
|
$ myshell-tools cost
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
181
|
+
myshell-tools — usage & efficiency
|
|
182
|
+
Tasks run: 3
|
|
183
|
+
Tokens used: 12.4k (real, measured)
|
|
184
|
+
Per-model usage
|
|
185
|
+
claude-haiku-4-5: 2 tasks, 4.1k tokens
|
|
186
|
+
claude-sonnet-4-6: 1 task, 8.3k tokens
|
|
187
|
+
Routing efficiency
|
|
188
|
+
Routing picked cheaper-tier models where it could — ~6.3× less than sending every task to the flagship (claude-opus-4-7).
|
|
189
|
+
Estimated cost — API-equivalent (list price), not your subscription bill
|
|
190
|
+
Routed: ~$0.0020 · always-flagship: ~$0.0126
|
|
180
191
|
```
|
|
181
192
|
|
|
182
|
-
The
|
|
193
|
+
The **efficiency ratio is honest under a subscription** (it compares flagship tokens you avoided, not dollars you were charged). The dollar figures are explicitly labeled an *API-equivalent estimate* — not your actual bill — and both use the **same basis** (list price × tokens), so "routed vs always-flagship" is apples-to-apples and internally consistent.
|
|
183
194
|
|
|
184
195
|
---
|
|
185
196
|
|
package/dist/cli.js
CHANGED
|
@@ -19,11 +19,14 @@ import { detectEnvironment } from './providers/detect.js';
|
|
|
19
19
|
import { createFileConversationStore } from './infra/conversations.js';
|
|
20
20
|
import { loadConfig } from './infra/config.js';
|
|
21
21
|
import { checkForUpdate } from './infra/update-check.js';
|
|
22
|
+
import { evaluateHealth, probeStateWritable } from './infra/health.js';
|
|
23
|
+
import { isPricingStale } from './infra/pricing.js';
|
|
22
24
|
import { runDoctor } from './commands/doctor.js';
|
|
23
25
|
import { runCost } from './commands/cost.js';
|
|
24
26
|
import { runLogin } from './commands/login.js';
|
|
25
27
|
import { runInstall } from './commands/install.js';
|
|
26
28
|
import { banner } from './ui/banner.js';
|
|
29
|
+
import { commandHelpText } from './ui/help.js';
|
|
27
30
|
import { createSpinner } from './ui/spinner.js';
|
|
28
31
|
import { dim } from './ui/theme.js';
|
|
29
32
|
const require = createRequire(import.meta.url);
|
|
@@ -46,9 +49,6 @@ Commands:
|
|
|
46
49
|
Add --code to use the no-localhost flow (paste a code for
|
|
47
50
|
claude, device code for codex) — best inside containers /
|
|
48
51
|
over SSH. Add --browser to force the localhost flow.
|
|
49
|
-
doctor [--fix] Check provider installation, auth, and environment health.
|
|
50
|
-
Add --fix to interactively install missing providers and
|
|
51
|
-
sign in to unauthenticated ones.
|
|
52
52
|
cost Show real spend from the ledger with a per-model breakdown
|
|
53
53
|
install Write a guarded startup hook to your shell rc file so new
|
|
54
54
|
interactive shells launch myshell-tools automatically
|
|
@@ -112,7 +112,10 @@ function welcome(deps, color) {
|
|
|
112
112
|
async function main() {
|
|
113
113
|
const args = process.argv.slice(2);
|
|
114
114
|
if (args.includes('--help') || args.includes('-h')) {
|
|
115
|
-
|
|
115
|
+
// Focused per-command help (e.g. `login --help`) when the first arg is a
|
|
116
|
+
// known command; otherwise the global command list.
|
|
117
|
+
const cmdHelp = args[0] !== undefined ? commandHelpText(args[0]) : null;
|
|
118
|
+
process.stdout.write(cmdHelp ?? HELP);
|
|
116
119
|
process.exit(0);
|
|
117
120
|
}
|
|
118
121
|
if (args.includes('--version') || args.includes('-v')) {
|
|
@@ -140,7 +143,11 @@ async function main() {
|
|
|
140
143
|
const provider = rest.find((a) => !a.startsWith('-'));
|
|
141
144
|
process.exit(await runLogin(out, provider, method !== undefined ? { method } : undefined));
|
|
142
145
|
}
|
|
143
|
-
|
|
146
|
+
// Health check — surfaced automatically in the control panel, so this is no
|
|
147
|
+
// longer an advertised command. Kept as a hidden, scriptable entry point for
|
|
148
|
+
// support/CI; `status` and `check` are friendlier aliases for the old
|
|
149
|
+
// `doctor` name (which still works for muscle-memory / existing scripts).
|
|
150
|
+
if (args[0] === 'doctor' || args[0] === 'status' || args[0] === 'check') {
|
|
144
151
|
const fix = args.includes('--fix');
|
|
145
152
|
process.exit(await runDoctor(out, fix ? { fix: true } : undefined));
|
|
146
153
|
}
|
|
@@ -170,12 +177,20 @@ async function main() {
|
|
|
170
177
|
if (args.length === 0) {
|
|
171
178
|
const spinner = createSpinner(out);
|
|
172
179
|
spinner.start('Detecting providers…');
|
|
173
|
-
const [env, config] = await Promise.all([
|
|
180
|
+
const [env, config, stateWritable] = await Promise.all([
|
|
174
181
|
detectEnvironment(),
|
|
175
182
|
loadConfig(),
|
|
183
|
+
probeStateWritable(cwd),
|
|
176
184
|
]);
|
|
177
185
|
const providers = buildProviders(cwd, env);
|
|
178
186
|
spinner.stop();
|
|
187
|
+
// Evaluate non-provider environment health once at startup. Surfaced in the
|
|
188
|
+
// menu only when a problem exists — the user never runs a health command.
|
|
189
|
+
const healthIssues = evaluateHealth({
|
|
190
|
+
nodeVersion: process.version,
|
|
191
|
+
stateWritable,
|
|
192
|
+
pricingStale: isPricingStale(),
|
|
193
|
+
});
|
|
179
194
|
const store = createFileConversationStore({ clock: systemClock });
|
|
180
195
|
const ledger = createLedger({ cwd });
|
|
181
196
|
const menuCtx = {
|
|
@@ -189,6 +204,7 @@ async function main() {
|
|
|
189
204
|
cwd,
|
|
190
205
|
sandbox: 'workspace-write',
|
|
191
206
|
timeoutMs: 120000,
|
|
207
|
+
healthIssues,
|
|
192
208
|
checkForUpdate: () => checkForUpdate({ currentVersion: version, now: Date.now() }),
|
|
193
209
|
updateSelf: async (updateOut) => {
|
|
194
210
|
try {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AACvC,MAAM,OAAO,GAAW,GAAG,CAAC,OAAiB,CAAC;AAE9C,MAAM,IAAI,GAAG;iBACI,OAAO
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/cost.js
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* fabricated. If the ledger is empty the command says so and returns 0.
|
|
20
20
|
*/
|
|
21
21
|
import { readLedger, summarizeLedger } from '../infra/ledger.js';
|
|
22
|
+
import { formatTokens } from '../infra/insights.js';
|
|
22
23
|
import { getCheapestForTier, calculateCost, getModelPricing } from '../infra/pricing.js';
|
|
23
24
|
import { bold, dim, cyan, divider, label } from '../ui/theme.js';
|
|
24
25
|
// ---------------------------------------------------------------------------
|
|
@@ -32,7 +33,7 @@ import { bold, dim, cyan, divider, label } from '../ui/theme.js';
|
|
|
32
33
|
*/
|
|
33
34
|
export function formatCostReport(entries, color = false) {
|
|
34
35
|
if (entries.length === 0) {
|
|
35
|
-
return ['No usage recorded yet
|
|
36
|
+
return ['No usage recorded yet. Run a task first, e.g. myshell-tools run "summarize this repo"'];
|
|
36
37
|
}
|
|
37
38
|
const summary = summarizeLedger(entries);
|
|
38
39
|
// Counterfactual uses the flagship from paid providers only (claude/codex).
|
|
@@ -42,9 +43,15 @@ export function formatCostReport(entries, color = false) {
|
|
|
42
43
|
// Apples-to-apples: price BOTH the models actually used AND the flagship on the
|
|
43
44
|
// SAME basis (list price × tokens). We do NOT compare the billed total (which
|
|
44
45
|
// includes caching/discounts) against a list-price flagship estimate.
|
|
46
|
+
// Also accumulate REAL token totals (overall + per model) — the honest signal.
|
|
45
47
|
let routedListUsd = 0;
|
|
46
48
|
let flagshipListUsd = 0;
|
|
49
|
+
let totalTokens = 0;
|
|
50
|
+
const tokensByModel = {};
|
|
47
51
|
for (const entry of entries) {
|
|
52
|
+
const entryTokens = entry.inputTokens + entry.outputTokens;
|
|
53
|
+
totalTokens += entryTokens;
|
|
54
|
+
tokensByModel[entry.model] = (tokensByModel[entry.model] ?? 0) + entryTokens;
|
|
48
55
|
const entryPricing = getModelPricing(entry.provider, entry.model);
|
|
49
56
|
if (entryPricing) {
|
|
50
57
|
routedListUsd += calculateCost(entry.inputTokens, entry.outputTokens, entryPricing);
|
|
@@ -52,41 +59,53 @@ export function formatCostReport(entries, color = false) {
|
|
|
52
59
|
flagshipListUsd += calculateCost(entry.inputTokens, entry.outputTokens, flagship);
|
|
53
60
|
}
|
|
54
61
|
const lines = [];
|
|
55
|
-
lines.push(bold('myshell-tools
|
|
62
|
+
lines.push(bold('myshell-tools — usage & efficiency', color));
|
|
56
63
|
lines.push(divider(color));
|
|
57
|
-
// ----
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// is "as billed" — it may include estimates.
|
|
62
|
-
lines.push(`${label('Total cost', color)}: $${summary.totalUsd.toFixed(4)} ` +
|
|
63
|
-
`${dim('(provider-reported where available, otherwise estimated from list prices)', color)}`);
|
|
64
|
-
lines.push(`${label('Total calls', color)}: ${summary.calls}`);
|
|
64
|
+
// ---- Usage (REAL, measured) -----------------------------------------------
|
|
65
|
+
// Tokens are measured, not estimated — the trustworthy primary figure.
|
|
66
|
+
lines.push(`${label('Tasks run', color)}: ${summary.calls}`);
|
|
67
|
+
lines.push(`${label('Tokens used', color)}: ${formatTokens(totalTokens)} ${dim('(real, measured)', color)}`);
|
|
65
68
|
lines.push(divider(color));
|
|
66
|
-
|
|
67
|
-
lines.push(bold('Per-model breakdown', color));
|
|
69
|
+
lines.push(bold('Per-model usage', color));
|
|
68
70
|
for (const [model, ms] of Object.entries(summary.byModel)) {
|
|
69
|
-
const callStr = ms.calls === 1 ? '1
|
|
70
|
-
lines.push(` ${cyan(model, color)}: ${callStr},
|
|
71
|
+
const callStr = ms.calls === 1 ? '1 task' : `${ms.calls} tasks`;
|
|
72
|
+
lines.push(` ${cyan(model, color)}: ${callStr}, ${formatTokens(tokensByModel[model] ?? 0)} tokens`);
|
|
71
73
|
}
|
|
72
74
|
lines.push(divider(color));
|
|
73
|
-
// ----
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
lines.push(`${label('Routed (models used)', color)}: $${routedListUsd.toFixed(4)}`);
|
|
79
|
-
lines.push(`${label('Always-flagship', color)}: $${flagshipListUsd.toFixed(4)}`);
|
|
75
|
+
// ---- Routing efficiency (billing-agnostic ratio) --------------------------
|
|
76
|
+
// The savings RATIO is honest regardless of billing model: it compares how
|
|
77
|
+
// many flagship tokens you avoided by routing to cheaper tiers. This is the
|
|
78
|
+
// value-prop number, and it holds true on a subscription too.
|
|
79
|
+
lines.push(bold('Routing efficiency', color));
|
|
80
80
|
if (routedListUsd > 0 && flagshipListUsd > routedListUsd) {
|
|
81
81
|
const multiplier = flagshipListUsd / routedListUsd;
|
|
82
|
-
lines.push(`Routing
|
|
83
|
-
|
|
82
|
+
lines.push(`Routing picked cheaper-tier models where it could — ` +
|
|
83
|
+
`${cyan(`~${multiplier.toFixed(1)}× less`, color)} than sending every task to ` +
|
|
84
|
+
`the flagship (${flagship.model}).`);
|
|
84
85
|
}
|
|
85
86
|
else if (routedListUsd > 0) {
|
|
86
|
-
lines.push('Every
|
|
87
|
+
lines.push(dim('Every task already used a flagship-tier (or pricier) model — no routing savings to show.', color));
|
|
87
88
|
}
|
|
88
89
|
else {
|
|
89
|
-
lines.push(dim('No priced models in the ledger — cannot compute a
|
|
90
|
+
lines.push(dim('No priced models in the ledger — cannot compute a routing comparison.', color));
|
|
91
|
+
}
|
|
92
|
+
// ---- Estimated cost (API-equivalent, NOT your subscription bill) ----------
|
|
93
|
+
// myshell-tools drives your SUBSCRIPTION CLIs — you pay a flat fee, not per
|
|
94
|
+
// token. This is a rough "if this were metered API usage" estimate, shown for
|
|
95
|
+
// devs who want the magnitude; it is not what you are billed. Both figures use
|
|
96
|
+
// the SAME basis (list price × tokens) so "routed vs always-flagship" is
|
|
97
|
+
// apples-to-apples and internally consistent (routed never exceeds flagship).
|
|
98
|
+
lines.push(divider(color));
|
|
99
|
+
lines.push(bold('Estimated cost', color) + dim(' — API-equivalent (list price), not your subscription bill', color));
|
|
100
|
+
if (routedListUsd > 0) {
|
|
101
|
+
let line = `${label('Routed', color)}: ~$${routedListUsd.toFixed(4)}`;
|
|
102
|
+
if (flagshipListUsd > routedListUsd) {
|
|
103
|
+
line += ` · ${dim(`always-flagship: ~$${flagshipListUsd.toFixed(4)}`, color)}`;
|
|
104
|
+
}
|
|
105
|
+
lines.push(line);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
lines.push(dim('No priced models in the ledger — no estimate available.', color));
|
|
90
109
|
}
|
|
91
110
|
return lines;
|
|
92
111
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/commands/cost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEjE,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAsB,EAAE,KAAK,GAAG,KAAK;IACpE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/commands/cost.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { OutputSink } from '../interface/render.js';
|
|
18
18
|
import type { EnvironmentStatus } from '../providers/detect.js';
|
|
19
|
+
import type { ClaudeTokenStatus } from '../infra/credentials.js';
|
|
19
20
|
export interface DoctorExtras {
|
|
20
21
|
readonly nodeVersion: string;
|
|
21
22
|
readonly stateWritable: boolean;
|
|
@@ -28,11 +29,12 @@ export interface DoctorExtras {
|
|
|
28
29
|
* Used by runDoctor after it collects the real data, and by unit tests with
|
|
29
30
|
* hand-built inputs.
|
|
30
31
|
*
|
|
31
|
-
* @param env
|
|
32
|
-
* @param extras
|
|
33
|
-
* @param color
|
|
32
|
+
* @param env - Full environment status (from detectEnvironment or a fake).
|
|
33
|
+
* @param extras - Supplemental runtime info (node version, write probe, etc.).
|
|
34
|
+
* @param color - Whether to emit ANSI colour codes.
|
|
35
|
+
* @param claudeTokenInfo - Optional pre-computed token lifetime status (from claudeTokenStatus()).
|
|
34
36
|
*/
|
|
35
|
-
export declare function buildDoctorReport(env: EnvironmentStatus, extras: DoctorExtras, color: boolean): string[];
|
|
37
|
+
export declare function buildDoctorReport(env: EnvironmentStatus, extras: DoctorExtras, color: boolean, claudeTokenInfo?: ClaudeTokenStatus | null): string[];
|
|
36
38
|
export interface DoctorFixOpts {
|
|
37
39
|
/** When true, run an interactive fix pass after the report. */
|
|
38
40
|
readonly fix?: boolean;
|
|
@@ -56,6 +58,17 @@ export interface DoctorFixOpts {
|
|
|
56
58
|
* Defaults to the real detectEnvironment from providers/detect.ts.
|
|
57
59
|
*/
|
|
58
60
|
readonly detectEnvironment?: () => Promise<EnvironmentStatus>;
|
|
61
|
+
/**
|
|
62
|
+
* Load the Claude token capture timestamp (ISO 8601). Injected in tests to
|
|
63
|
+
* drive the token-expiry refresh prompt hermetically (no disk read).
|
|
64
|
+
* Defaults to the real loadClaudeTokenCapturedAt from infra/credentials.ts.
|
|
65
|
+
*/
|
|
66
|
+
readonly loadClaudeTokenCapturedAt?: () => Promise<string | undefined>;
|
|
67
|
+
/**
|
|
68
|
+
* Current epoch-ms, used for deterministic token-expiry computation in tests.
|
|
69
|
+
* Defaults to Date.now().
|
|
70
|
+
*/
|
|
71
|
+
readonly now?: () => number;
|
|
59
72
|
}
|
|
60
73
|
/**
|
|
61
74
|
* Detect the environment, probe I/O, build the report, and write it to `out`.
|