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
|
@@ -17,7 +17,33 @@
|
|
|
17
17
|
*/
|
|
18
18
|
export interface Credentials {
|
|
19
19
|
claudeOauthToken?: string;
|
|
20
|
+
claudeTokenCapturedAt?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ClaudeTokenStatus {
|
|
23
|
+
/** ISO string of when the token was saved. */
|
|
24
|
+
readonly capturedAt: string;
|
|
25
|
+
/** ISO string of the computed expiry (capturedAt + lifetimeDays). */
|
|
26
|
+
readonly expiresAt: string;
|
|
27
|
+
/** Whole days remaining until expiry (floor). 0 when expiring today, negative when expired. */
|
|
28
|
+
readonly daysLeft: number;
|
|
29
|
+
/** True when daysLeft <= 0. */
|
|
30
|
+
readonly expired: boolean;
|
|
31
|
+
/** True when 0 < daysLeft <= warnWithinDays. */
|
|
32
|
+
readonly nearExpiry: boolean;
|
|
20
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Compute token lifetime status from a stored ISO capture timestamp.
|
|
36
|
+
*
|
|
37
|
+
* Pure — no I/O, no Date.now() inside. Pass `nowMs` for deterministic testing.
|
|
38
|
+
* Never throws.
|
|
39
|
+
*
|
|
40
|
+
* @param capturedAtIso - ISO string stored at save time, or undefined/null.
|
|
41
|
+
* @param nowMs - Current epoch-ms (e.g. Date.now() from the caller).
|
|
42
|
+
* @param lifetimeDays - Total token lifetime in days (default 365).
|
|
43
|
+
* @param warnWithinDays - Warn when this many days or fewer remain (default 14).
|
|
44
|
+
* @returns Status object, or null when capturedAtIso is missing or unparseable.
|
|
45
|
+
*/
|
|
46
|
+
export declare function claudeTokenStatus(capturedAtIso: string | undefined, nowMs: number, lifetimeDays?: number, warnWithinDays?: number): ClaudeTokenStatus | null;
|
|
21
47
|
/**
|
|
22
48
|
* Load stored credentials. Never throws — missing or corrupt files return `{}`.
|
|
23
49
|
*/
|
|
@@ -51,8 +77,17 @@ export declare function claudeEnv(baseEnv: NodeJS.ProcessEnv, token: string | nu
|
|
|
51
77
|
/**
|
|
52
78
|
* Persist the Claude OAuth token atomically to
|
|
53
79
|
* `~/.myshell-tools/credentials.json` with restrictive permissions (0o600).
|
|
80
|
+
*
|
|
81
|
+
* Records `claudeTokenCapturedAt` (ISO timestamp) so the token's age can be
|
|
82
|
+
* tracked for expiry warnings.
|
|
54
83
|
*/
|
|
55
84
|
export declare function saveClaudeToken(token: string, homeDir?: string): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Load the ISO timestamp recorded when the Claude OAuth token was last saved.
|
|
87
|
+
* Returns `undefined` when no token has been saved, or when the stored value
|
|
88
|
+
* is missing from an older credential file. Never throws.
|
|
89
|
+
*/
|
|
90
|
+
export declare function loadClaudeTokenCapturedAt(homeDir?: string): Promise<string | undefined>;
|
|
56
91
|
/**
|
|
57
92
|
* Remove the stored Claude OAuth token. Writes the file back without the
|
|
58
93
|
* token key so any future credential fields are preserved.
|
|
@@ -19,6 +19,40 @@ import { mkdir, readFile, chmod } from 'node:fs/promises';
|
|
|
19
19
|
import { homedir } from 'node:os';
|
|
20
20
|
import { join } from 'node:path';
|
|
21
21
|
import { atomicWrite } from './atomic.js';
|
|
22
|
+
/**
|
|
23
|
+
* Compute token lifetime status from a stored ISO capture timestamp.
|
|
24
|
+
*
|
|
25
|
+
* Pure — no I/O, no Date.now() inside. Pass `nowMs` for deterministic testing.
|
|
26
|
+
* Never throws.
|
|
27
|
+
*
|
|
28
|
+
* @param capturedAtIso - ISO string stored at save time, or undefined/null.
|
|
29
|
+
* @param nowMs - Current epoch-ms (e.g. Date.now() from the caller).
|
|
30
|
+
* @param lifetimeDays - Total token lifetime in days (default 365).
|
|
31
|
+
* @param warnWithinDays - Warn when this many days or fewer remain (default 14).
|
|
32
|
+
* @returns Status object, or null when capturedAtIso is missing or unparseable.
|
|
33
|
+
*/
|
|
34
|
+
export function claudeTokenStatus(capturedAtIso, nowMs, lifetimeDays = 365, warnWithinDays = 14) {
|
|
35
|
+
try {
|
|
36
|
+
if (capturedAtIso === undefined || capturedAtIso === null || capturedAtIso.length === 0) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
const capturedMs = new Date(capturedAtIso).getTime();
|
|
40
|
+
if (!Number.isFinite(capturedMs)) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const lifetimeMs = lifetimeDays * 24 * 60 * 60 * 1000;
|
|
44
|
+
const expiresMs = capturedMs + lifetimeMs;
|
|
45
|
+
const expiresAt = new Date(expiresMs).toISOString();
|
|
46
|
+
const msLeft = expiresMs - nowMs;
|
|
47
|
+
const daysLeft = Math.floor(msLeft / (24 * 60 * 60 * 1000));
|
|
48
|
+
const expired = daysLeft <= 0;
|
|
49
|
+
const nearExpiry = !expired && daysLeft <= warnWithinDays;
|
|
50
|
+
return { capturedAt: capturedAtIso, expiresAt, daysLeft, expired, nearExpiry };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
22
56
|
// ---------------------------------------------------------------------------
|
|
23
57
|
// Path helpers (pure)
|
|
24
58
|
// ---------------------------------------------------------------------------
|
|
@@ -46,6 +80,9 @@ function parseCredentials(raw) {
|
|
|
46
80
|
if (typeof obj['claudeOauthToken'] === 'string' && obj['claudeOauthToken'].length > 0) {
|
|
47
81
|
result.claudeOauthToken = obj['claudeOauthToken'];
|
|
48
82
|
}
|
|
83
|
+
if (typeof obj['claudeTokenCapturedAt'] === 'string' && obj['claudeTokenCapturedAt'].length > 0) {
|
|
84
|
+
result.claudeTokenCapturedAt = obj['claudeTokenCapturedAt'];
|
|
85
|
+
}
|
|
49
86
|
return result;
|
|
50
87
|
}
|
|
51
88
|
catch {
|
|
@@ -114,6 +151,9 @@ export function claudeEnv(baseEnv, token) {
|
|
|
114
151
|
/**
|
|
115
152
|
* Persist the Claude OAuth token atomically to
|
|
116
153
|
* `~/.myshell-tools/credentials.json` with restrictive permissions (0o600).
|
|
154
|
+
*
|
|
155
|
+
* Records `claudeTokenCapturedAt` (ISO timestamp) so the token's age can be
|
|
156
|
+
* tracked for expiry warnings.
|
|
117
157
|
*/
|
|
118
158
|
export async function saveClaudeToken(token, homeDir) {
|
|
119
159
|
const home = homeDir ?? homedir();
|
|
@@ -124,7 +164,11 @@ export async function saveClaudeToken(token, homeDir) {
|
|
|
124
164
|
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
125
165
|
// Load existing credentials so we only replace the token key, preserving others.
|
|
126
166
|
const existing = await loadCredentials(homeDir);
|
|
127
|
-
const updated = {
|
|
167
|
+
const updated = {
|
|
168
|
+
...existing,
|
|
169
|
+
claudeOauthToken: token,
|
|
170
|
+
claudeTokenCapturedAt: new Date().toISOString(),
|
|
171
|
+
};
|
|
128
172
|
// atomicWrite with mode 0o600 guarantees the temp file is never more permissive
|
|
129
173
|
// than the final destination — no world-readable window before the rename.
|
|
130
174
|
await atomicWrite(path, JSON.stringify(updated, null, 2), 0o600);
|
|
@@ -137,6 +181,20 @@ export async function saveClaudeToken(token, homeDir) {
|
|
|
137
181
|
// Cross-platform best-effort only — never throws
|
|
138
182
|
}
|
|
139
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* Load the ISO timestamp recorded when the Claude OAuth token was last saved.
|
|
186
|
+
* Returns `undefined` when no token has been saved, or when the stored value
|
|
187
|
+
* is missing from an older credential file. Never throws.
|
|
188
|
+
*/
|
|
189
|
+
export async function loadClaudeTokenCapturedAt(homeDir) {
|
|
190
|
+
try {
|
|
191
|
+
const creds = await loadCredentials(homeDir);
|
|
192
|
+
return creds.claudeTokenCapturedAt;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
140
198
|
/**
|
|
141
199
|
* Remove the stored Claude OAuth token. Writes the file back without the
|
|
142
200
|
* token key so any future credential fields are preserved.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/infra/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/infra/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/infra/health.ts — Self-health evaluation for myshell-tools.
|
|
3
|
+
*
|
|
4
|
+
* The product goal is "it just works": the user should never run a diagnostic
|
|
5
|
+
* command. Instead the control panel evaluates its own environment health at
|
|
6
|
+
* startup and surfaces a short, actionable warning ONLY when something is
|
|
7
|
+
* actually wrong. No problems → nothing shown (silence == healthy).
|
|
8
|
+
*
|
|
9
|
+
* This module covers the diagnostics that are NOT already visible elsewhere in
|
|
10
|
+
* the UI: Node version, state-directory writability, and pricing-table
|
|
11
|
+
* staleness. Provider install/auth status and Claude-token expiry are already
|
|
12
|
+
* rendered in the header, so they are intentionally not duplicated here.
|
|
13
|
+
*
|
|
14
|
+
* `evaluateHealth` is PURE (no I/O) so it is trivially testable. The one piece
|
|
15
|
+
* that needs I/O — probing whether the state directory is writable — is a
|
|
16
|
+
* separate function the caller runs once at startup and feeds in.
|
|
17
|
+
*/
|
|
18
|
+
type HealthSeverity = 'warn' | 'error';
|
|
19
|
+
export interface HealthIssue {
|
|
20
|
+
/** Stable identifier for the issue (useful for tests and de-duplication). */
|
|
21
|
+
readonly id: string;
|
|
22
|
+
readonly severity: HealthSeverity;
|
|
23
|
+
/** One-line, human-readable message that already includes the fix. */
|
|
24
|
+
readonly message: string;
|
|
25
|
+
}
|
|
26
|
+
export interface HealthInputs {
|
|
27
|
+
/** process.version, e.g. "v20.20.0". */
|
|
28
|
+
readonly nodeVersion: string;
|
|
29
|
+
/** Whether the .myshell-tools state directory could be written to. */
|
|
30
|
+
readonly stateWritable: boolean;
|
|
31
|
+
/** Whether the bundled pricing seed is past its staleness window. */
|
|
32
|
+
readonly pricingStale: boolean;
|
|
33
|
+
/** Minimum supported Node major version (defaults to 20). */
|
|
34
|
+
readonly minNodeMajor?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parse the major version from a Node version string ("v20.20.0" → 20).
|
|
38
|
+
* Returns null when the string can't be parsed (so callers can skip the check
|
|
39
|
+
* rather than emit a bogus warning). Pure; never throws.
|
|
40
|
+
*/
|
|
41
|
+
export declare function nodeMajor(version: string): number | null;
|
|
42
|
+
/**
|
|
43
|
+
* Evaluate environment health and return the issues worth surfacing.
|
|
44
|
+
*
|
|
45
|
+
* Pure — takes a snapshot of inputs and returns zero or more issues, most
|
|
46
|
+
* severe first (errors before warnings). An empty array means "all healthy,
|
|
47
|
+
* show nothing".
|
|
48
|
+
*/
|
|
49
|
+
export declare function evaluateHealth(inputs: HealthInputs): HealthIssue[];
|
|
50
|
+
/**
|
|
51
|
+
* Probe whether the .myshell-tools state directory under `cwd` is writable.
|
|
52
|
+
*
|
|
53
|
+
* Creates the directory if needed, writes and removes a temp file. Returns true
|
|
54
|
+
* on success, false on any I/O error. Never throws.
|
|
55
|
+
*/
|
|
56
|
+
export declare function probeStateWritable(cwd: string): Promise<boolean>;
|
|
57
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/infra/health.ts — Self-health evaluation for myshell-tools.
|
|
3
|
+
*
|
|
4
|
+
* The product goal is "it just works": the user should never run a diagnostic
|
|
5
|
+
* command. Instead the control panel evaluates its own environment health at
|
|
6
|
+
* startup and surfaces a short, actionable warning ONLY when something is
|
|
7
|
+
* actually wrong. No problems → nothing shown (silence == healthy).
|
|
8
|
+
*
|
|
9
|
+
* This module covers the diagnostics that are NOT already visible elsewhere in
|
|
10
|
+
* the UI: Node version, state-directory writability, and pricing-table
|
|
11
|
+
* staleness. Provider install/auth status and Claude-token expiry are already
|
|
12
|
+
* rendered in the header, so they are intentionally not duplicated here.
|
|
13
|
+
*
|
|
14
|
+
* `evaluateHealth` is PURE (no I/O) so it is trivially testable. The one piece
|
|
15
|
+
* that needs I/O — probing whether the state directory is writable — is a
|
|
16
|
+
* separate function the caller runs once at startup and feeds in.
|
|
17
|
+
*/
|
|
18
|
+
import { mkdir, writeFile, rm, access } from 'node:fs/promises';
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Pure helpers
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
/**
|
|
24
|
+
* Parse the major version from a Node version string ("v20.20.0" → 20).
|
|
25
|
+
* Returns null when the string can't be parsed (so callers can skip the check
|
|
26
|
+
* rather than emit a bogus warning). Pure; never throws.
|
|
27
|
+
*/
|
|
28
|
+
export function nodeMajor(version) {
|
|
29
|
+
const m = /^v?(\d+)\./.exec(version.trim());
|
|
30
|
+
if (m === null)
|
|
31
|
+
return null;
|
|
32
|
+
const n = parseInt(m[1] ?? '', 10);
|
|
33
|
+
return Number.isFinite(n) ? n : null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Evaluate environment health and return the issues worth surfacing.
|
|
37
|
+
*
|
|
38
|
+
* Pure — takes a snapshot of inputs and returns zero or more issues, most
|
|
39
|
+
* severe first (errors before warnings). An empty array means "all healthy,
|
|
40
|
+
* show nothing".
|
|
41
|
+
*/
|
|
42
|
+
export function evaluateHealth(inputs) {
|
|
43
|
+
const minMajor = inputs.minNodeMajor ?? 20;
|
|
44
|
+
const issues = [];
|
|
45
|
+
// State directory not writable — the most serious: nothing persists.
|
|
46
|
+
if (!inputs.stateWritable) {
|
|
47
|
+
issues.push({
|
|
48
|
+
id: 'state-not-writable',
|
|
49
|
+
severity: 'error',
|
|
50
|
+
message: "Can't write to the .myshell-tools state directory — conversations and " +
|
|
51
|
+
'cost tracking will not be saved. Check the directory permissions.',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Node below the supported floor — the compiled CLI targets Node >= minMajor.
|
|
55
|
+
const major = nodeMajor(inputs.nodeVersion);
|
|
56
|
+
if (major !== null && major < minMajor) {
|
|
57
|
+
issues.push({
|
|
58
|
+
id: 'node-too-old',
|
|
59
|
+
severity: 'warn',
|
|
60
|
+
message: `Node ${inputs.nodeVersion} is below the supported v${minMajor} — upgrade Node if you hit errors.`,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
// Stale pricing seed — cost estimates may drift; updating refreshes them.
|
|
64
|
+
if (inputs.pricingStale) {
|
|
65
|
+
issues.push({
|
|
66
|
+
id: 'pricing-stale',
|
|
67
|
+
severity: 'warn',
|
|
68
|
+
message: 'Cost estimates may be out of date — update to refresh them: npm install -g myshell-tools@latest',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return issues;
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// I/O probe (run once at startup; result fed into evaluateHealth)
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
/**
|
|
77
|
+
* Probe whether the .myshell-tools state directory under `cwd` is writable.
|
|
78
|
+
*
|
|
79
|
+
* Creates the directory if needed, writes and removes a temp file. Returns true
|
|
80
|
+
* on success, false on any I/O error. Never throws.
|
|
81
|
+
*/
|
|
82
|
+
export async function probeStateWritable(cwd) {
|
|
83
|
+
const stateDir = join(cwd, '.myshell-tools');
|
|
84
|
+
const probe = join(stateDir, '.health-probe');
|
|
85
|
+
try {
|
|
86
|
+
await mkdir(stateDir, { recursive: true });
|
|
87
|
+
await writeFile(probe, '');
|
|
88
|
+
await rm(probe, { force: true });
|
|
89
|
+
await access(stateDir);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/infra/health.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA2BjC,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC;IAC3C,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,qEAAqE;IACrE,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,oBAAoB;YACxB,QAAQ,EAAE,OAAO;YACjB,OAAO,EACL,wEAAwE;gBACxE,mEAAmE;SACtE,CAAC,CAAC;IACL,CAAC;IAED,8EAA8E;IAC9E,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,cAAc;YAClB,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,QAAQ,MAAM,CAAC,WAAW,4BAA4B,QAAQ,oCAAoC;SAC5G,CAAC,CAAC;IACL,CAAC;IAED,0EAA0E;IAC1E,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,eAAe;YACnB,QAAQ,EAAE,MAAM;YAChB,OAAO,EACL,iGAAiG;SACpG,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,kEAAkE;AAClE,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAW;IAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3B,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/dist/infra/insights.d.ts
CHANGED
|
@@ -18,6 +18,11 @@ export interface SpendSummary {
|
|
|
18
18
|
readonly totalUsd: number;
|
|
19
19
|
/** Total number of ledger entries (calls). */
|
|
20
20
|
readonly calls: number;
|
|
21
|
+
/** Real tokens (input + output) used today (UTC). The transparent primary
|
|
22
|
+
* signal — measured, not an estimate, unlike the USD figures. */
|
|
23
|
+
readonly todayTokens: number;
|
|
24
|
+
/** Real tokens (input + output) used across all time. */
|
|
25
|
+
readonly totalTokens: number;
|
|
21
26
|
/** Per-provider breakdown keyed by ProviderId string. */
|
|
22
27
|
readonly byProvider: Record<string, {
|
|
23
28
|
readonly usd: number;
|
|
@@ -64,3 +69,12 @@ export declare function providerHealth(entries: LedgerEntry[]): ProviderHealth[]
|
|
|
64
69
|
* @param n - Amount in US dollars (may be 0).
|
|
65
70
|
*/
|
|
66
71
|
export declare function formatUsd(n: number): string;
|
|
72
|
+
/**
|
|
73
|
+
* Format a token count compactly: 942 → "942", 12_400 → "12.4k", 3_000_000 → "3M".
|
|
74
|
+
*
|
|
75
|
+
* Tokens are REAL measured values (unlike the USD estimates), so this is the
|
|
76
|
+
* primary live signal. Pure; never throws. Negative/NaN inputs clamp to "0".
|
|
77
|
+
*
|
|
78
|
+
* @param n - Token count.
|
|
79
|
+
*/
|
|
80
|
+
export declare function formatTokens(n: number): string;
|
package/dist/infra/insights.js
CHANGED
|
@@ -22,11 +22,16 @@ export function summarizeSpend(entries, nowIso) {
|
|
|
22
22
|
const todayDate = nowIso.slice(0, 10); // 'YYYY-MM-DD'
|
|
23
23
|
let todayUsd = 0;
|
|
24
24
|
let totalUsd = 0;
|
|
25
|
+
let todayTokens = 0;
|
|
26
|
+
let totalTokens = 0;
|
|
25
27
|
const byProvider = {};
|
|
26
28
|
for (const entry of entries) {
|
|
27
29
|
totalUsd += entry.usd;
|
|
30
|
+
const entryTokens = entry.inputTokens + entry.outputTokens;
|
|
31
|
+
totalTokens += entryTokens;
|
|
28
32
|
if (entry.timestamp.slice(0, 10) === todayDate) {
|
|
29
33
|
todayUsd += entry.usd;
|
|
34
|
+
todayTokens += entryTokens;
|
|
30
35
|
}
|
|
31
36
|
const existing = byProvider[entry.provider];
|
|
32
37
|
if (existing !== undefined) {
|
|
@@ -41,6 +46,8 @@ export function summarizeSpend(entries, nowIso) {
|
|
|
41
46
|
todayUsd,
|
|
42
47
|
totalUsd,
|
|
43
48
|
calls: entries.length,
|
|
49
|
+
todayTokens,
|
|
50
|
+
totalTokens,
|
|
44
51
|
byProvider,
|
|
45
52
|
};
|
|
46
53
|
}
|
|
@@ -102,4 +109,28 @@ export function providerHealth(entries) {
|
|
|
102
109
|
export function formatUsd(n) {
|
|
103
110
|
return '$' + n.toFixed(4);
|
|
104
111
|
}
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// formatTokens
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
/**
|
|
116
|
+
* Format a token count compactly: 942 → "942", 12_400 → "12.4k", 3_000_000 → "3M".
|
|
117
|
+
*
|
|
118
|
+
* Tokens are REAL measured values (unlike the USD estimates), so this is the
|
|
119
|
+
* primary live signal. Pure; never throws. Negative/NaN inputs clamp to "0".
|
|
120
|
+
*
|
|
121
|
+
* @param n - Token count.
|
|
122
|
+
*/
|
|
123
|
+
export function formatTokens(n) {
|
|
124
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
125
|
+
return '0';
|
|
126
|
+
if (n < 1000)
|
|
127
|
+
return String(Math.round(n));
|
|
128
|
+
if (n < 1_000_000) {
|
|
129
|
+
const k = n / 1000;
|
|
130
|
+
// One decimal, but drop a trailing ".0" (12000 → "12k", 12400 → "12.4k").
|
|
131
|
+
return (Number.isInteger(k) ? String(k) : k.toFixed(1)) + 'k';
|
|
132
|
+
}
|
|
133
|
+
const m = n / 1_000_000;
|
|
134
|
+
return (Number.isInteger(m) ? String(m) : m.toFixed(1)) + 'M';
|
|
135
|
+
}
|
|
105
136
|
//# sourceMappingURL=insights.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/infra/insights.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"insights.js","sourceRoot":"","sources":["../../src/infra/insights.ts"],"names":[],"mappings":"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"}
|
package/dist/interface/menu.d.ts
CHANGED
|
@@ -24,6 +24,9 @@ import type { Provider, ProviderId, SandboxLevel } from '../providers/port.js';
|
|
|
24
24
|
import type { OutputSink } from './render.js';
|
|
25
25
|
import type { LoginMethod } from '../commands/login.js';
|
|
26
26
|
import type { UpdateCheckResult } from '../infra/update-check.js';
|
|
27
|
+
import type { ClaudeTokenStatus } from '../infra/credentials.js';
|
|
28
|
+
import { claudeTokenStatus } from '../infra/credentials.js';
|
|
29
|
+
import type { HealthIssue } from '../infra/health.js';
|
|
27
30
|
export interface MenuContext {
|
|
28
31
|
readonly version: string;
|
|
29
32
|
readonly clock: Clock;
|
|
@@ -92,6 +95,30 @@ export interface MenuContext {
|
|
|
92
95
|
* Used only for the opt-in auto-update path.
|
|
93
96
|
*/
|
|
94
97
|
readonly relaunch?: () => Promise<number>;
|
|
98
|
+
/**
|
|
99
|
+
* Optional pre-computed Claude token lifetime status for testing. When provided,
|
|
100
|
+
* `startMenu` uses this instead of loading from disk, allowing tests to drive
|
|
101
|
+
* the token-expiry header warning without touching the filesystem.
|
|
102
|
+
*
|
|
103
|
+
* Pass `null` explicitly to suppress any token warning; omit (undefined) to
|
|
104
|
+
* trigger the real disk read via `loadClaudeTokenCapturedAt`.
|
|
105
|
+
*/
|
|
106
|
+
readonly claudeTokenInfo?: ClaudeTokenStatus | null;
|
|
107
|
+
/**
|
|
108
|
+
* Optional override for npx-context detection (testing). When provided,
|
|
109
|
+
* `startMenu` uses this instead of inspecting `process.argv[1]`, so tests can
|
|
110
|
+
* drive the "running under npx" warning + auto-update suppression without a
|
|
111
|
+
* real npx cache path. Omit (undefined) to trigger the real detection.
|
|
112
|
+
*/
|
|
113
|
+
readonly runningUnderNpx?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Pre-computed environment health issues (Node version, state-dir writable,
|
|
116
|
+
* pricing staleness) surfaced automatically below the header — only when a
|
|
117
|
+
* problem exists. Computed once at startup by cli.ts (the diagnostics don't
|
|
118
|
+
* change in-session) so the user never has to run a separate health command.
|
|
119
|
+
* Omit/empty → nothing is shown.
|
|
120
|
+
*/
|
|
121
|
+
readonly healthIssues?: readonly HealthIssue[];
|
|
95
122
|
}
|
|
96
123
|
/**
|
|
97
124
|
* Parse a yes/no answer from a raw input line, with a configurable default.
|
|
@@ -150,6 +177,35 @@ export declare function defaultAliasHint(shell: string | undefined, platform: st
|
|
|
150
177
|
* All arithmetic is pure — no Date, no Math.random.
|
|
151
178
|
*/
|
|
152
179
|
export declare function relativeTime(thenMs: number, nowMs: number): string;
|
|
180
|
+
/**
|
|
181
|
+
* Build the short version-status suffix shown next to the version number in the
|
|
182
|
+
* header title — so the user always knows, at a glance, whether they are current.
|
|
183
|
+
*
|
|
184
|
+
* Pure — no I/O. Returns a leading-space string ready to append to the title:
|
|
185
|
+
* - update available + known latest → ` → 3.1.0 available`
|
|
186
|
+
* - up to date (latest known, no update) → ` (latest)`
|
|
187
|
+
* - check failed / offline (latest unknown) → `` (claim nothing)
|
|
188
|
+
*
|
|
189
|
+
* @param updateInfo - Result of the update check, or undefined when not run.
|
|
190
|
+
*/
|
|
191
|
+
export declare function versionStatusLabel(updateInfo?: UpdateCheckResult): string;
|
|
192
|
+
/**
|
|
193
|
+
* Detect whether myshell-tools is running via `npx` rather than a global install.
|
|
194
|
+
*
|
|
195
|
+
* Pure — takes the running script path (process.argv[1]) and the environment.
|
|
196
|
+
* npx executes packages from a cache directory containing a `_npx` segment
|
|
197
|
+
* (e.g. ~/.npm/_npx/<hash>/node_modules/myshell-tools/dist/cli.js), so the
|
|
198
|
+
* presence of that segment in the script path is the reliable signal. Handles
|
|
199
|
+
* both POSIX and Windows separators. Never throws.
|
|
200
|
+
*
|
|
201
|
+
* Why it matters: self-update runs `npm install -g`, which an npx invocation
|
|
202
|
+
* will ignore on the next run (npx re-serves its own cache). So under npx we
|
|
203
|
+
* skip silent auto-update and instead tell the user to install globally.
|
|
204
|
+
*
|
|
205
|
+
* @param scriptPath - The running script path (typically process.argv[1]).
|
|
206
|
+
* @param env - Environment to read npm_* hints from.
|
|
207
|
+
*/
|
|
208
|
+
export declare function isRunningUnderNpx(scriptPath: string | undefined, env: NodeJS.ProcessEnv): boolean;
|
|
153
209
|
/**
|
|
154
210
|
* Build the header box lines (provider status) from real EnvironmentStatus.
|
|
155
211
|
* Returns string[] safe to pass as the `lines` arg to box().
|
|
@@ -159,14 +215,23 @@ export declare function relativeTime(thenMs: number, nowMs: number): string;
|
|
|
159
215
|
* ⚠️ when ps.installed && !ps.authenticated (append " not signed in")
|
|
160
216
|
* ❌ when !ps.installed (append install command)
|
|
161
217
|
* Plan label appended when ps.plan is non-null (e.g. " (Max x5)").
|
|
218
|
+
*
|
|
219
|
+
* @param claudeToken - Optional pre-computed token lifetime status. When the token
|
|
220
|
+
* is near expiry or expired, ONE concise warning line is appended. Computed by
|
|
221
|
+
* the caller (startMenu) so this function stays pure and I/O-free.
|
|
162
222
|
*/
|
|
163
|
-
export declare function renderHeaderLines(env: EnvironmentStatus, _version: string): string[];
|
|
223
|
+
export declare function renderHeaderLines(env: EnvironmentStatus, _version: string, claudeToken?: ReturnType<typeof claudeTokenStatus>): string[];
|
|
164
224
|
/**
|
|
165
|
-
* Render the
|
|
225
|
+
* Render the activity status line shown beneath the provider header.
|
|
226
|
+
*
|
|
227
|
+
* This is a SUBSCRIPTION tool, not an API-key tool — per-token dollar figures
|
|
228
|
+
* don't map to flat subscription billing and read as misleading bloat, so the
|
|
229
|
+
* always-on line shows REAL, measured signals only: task count and tokens. The
|
|
230
|
+
* estimated-dollar view lives on-demand in `myshell-tools cost`, clearly
|
|
231
|
+
* captioned there as an API-equivalent (not your actual bill).
|
|
166
232
|
*
|
|
167
|
-
* Uses real numbers only — all values come from the SpendSummary
|
|
168
|
-
*
|
|
169
|
-
* shows dollar amounts only.
|
|
233
|
+
* Uses real numbers only — all values come from the SpendSummary derived from
|
|
234
|
+
* `readLedger`. No digit-% literals appear here.
|
|
170
235
|
*
|
|
171
236
|
* @param spend - Output of summarizeSpend() over real ledger entries.
|
|
172
237
|
* @param color - When false, no ANSI escape codes are emitted.
|