usagemax 0.3.8 → 0.3.9
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/README.md +12 -6
- package/package.json +1 -1
- package/src/cli.js +31 -11
- package/src/updates.js +37 -0
package/README.md
CHANGED
|
@@ -40,10 +40,12 @@ bunx usagemax sync --dry-run --explain
|
|
|
40
40
|
bunx usagemax sync
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
The CLI checks npm's `latest` dist-tag at most twice per day
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
The CLI checks npm's `latest` dist-tag at most twice per day. Run
|
|
44
|
+
`usagemax update` to update a global installation through the package manager
|
|
45
|
+
that launched it (Bun or npm). Add `--check` for a read-only check, or
|
|
46
|
+
`--json` for automation. A command suffix such as `usagemax update sync` hands
|
|
47
|
+
that command to the newest release without typing `@latest`. Set
|
|
48
|
+
`USAGEMAX_AUTO_UPDATE=1` for an explicit automatic handoff. Use `--no-update-check` or set
|
|
47
49
|
`USAGEMAX_DISABLE_UPDATE_CHECK=1` in offline environments. Interactive
|
|
48
50
|
terminals show a small stderr progress line; JSON,
|
|
49
51
|
quiet, CI, and scheduled runs remain machine-readable and quiet.
|
|
@@ -81,6 +83,9 @@ usagemax token status Diagnose a key piped on stdin
|
|
|
81
83
|
usagemax service install Opt into periodic OS checkpoints
|
|
82
84
|
usagemax service status|run|uninstall
|
|
83
85
|
usagemax unlink [--revoke] Remove local credentials
|
|
86
|
+
usagemax update Update the global CLI through Bun or npm
|
|
87
|
+
usagemax update --check Check without installing
|
|
88
|
+
usagemax update sync Run sync through the newest CLI release
|
|
84
89
|
```
|
|
85
90
|
|
|
86
91
|
Useful options:
|
|
@@ -93,7 +98,8 @@ bunx usagemax status --remote --json # remote check; secret is never printe
|
|
|
93
98
|
bunx usagemax doctor --deep --json # parse and audit retained history
|
|
94
99
|
bunx usagemax link UMX-… --no-sync # link without uploading yet
|
|
95
100
|
bunx usagemax --version --json # print CLI and ccusage versions
|
|
96
|
-
bunx usagemax update --json # machine-readable
|
|
101
|
+
bunx usagemax update --json # update and return machine-readable status
|
|
102
|
+
bunx usagemax update --check --json # check without installing
|
|
97
103
|
bunx usagemax unlink --json # safe automation result; no secret output
|
|
98
104
|
```
|
|
99
105
|
|
|
@@ -135,7 +141,7 @@ printf '%s' "$USAGEMAX_COLLECTOR_TOKEN" \
|
|
|
135
141
|
--json
|
|
136
142
|
```
|
|
137
143
|
|
|
138
|
-
The `token status` command is included in CLI `0.3.
|
|
144
|
+
The `token status` command is included in CLI `0.3.9`. If a fresh environment
|
|
139
145
|
still has an older npm tag, run `usagemax update token status` or
|
|
140
146
|
`node packages/cli/src/cli.js token status` from this repository until the new
|
|
141
147
|
package is published.
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -18,7 +18,7 @@ import { intervalMinutes, manageService, runScheduledSync } from "./service.js";
|
|
|
18
18
|
import { collectorStatusView, requestCollectorStatus, requestSnapshot } from "./transport.js";
|
|
19
19
|
import { resumeUpload, restartExpiredUpload, withConfigLock } from "./resume.js";
|
|
20
20
|
import { CCUSAGE_VERSION, ccusageEnvironment, ccusageHome, discoverProviderArchives, SOURCE_INVENTORY_VERSION, sourceInventory, SUPPORTED_SOURCES } from "./sources.js";
|
|
21
|
-
import { checkForUpdate, runLatest } from "./updates.js";
|
|
21
|
+
import { checkForUpdate, packageManagerFor, runLatest, updateGlobal } from "./updates.js";
|
|
22
22
|
|
|
23
23
|
// Make the short-lived collector recognizable in Activity Monitor and `ps`.
|
|
24
24
|
// Windows may still display the underlying node.exe image name in Task Manager.
|
|
@@ -26,7 +26,7 @@ process.title = "UsageMax";
|
|
|
26
26
|
|
|
27
27
|
const require = createRequire(import.meta.url);
|
|
28
28
|
const executeFile = promisify(execFile);
|
|
29
|
-
const VERSION = "0.3.
|
|
29
|
+
const VERSION = "0.3.9";
|
|
30
30
|
const PUBLIC_API_ORIGIN = "https://usagemax.com/api";
|
|
31
31
|
const DEFAULT_LINK_ENDPOINT = `${PUBLIC_API_ORIGIN}/v1/devices/link`;
|
|
32
32
|
const DEFAULT_STATUS_ENDPOINT = `${PUBLIC_API_ORIGIN}/v1/devices/status`;
|
|
@@ -132,8 +132,9 @@ function help() {
|
|
|
132
132
|
process.stdout.write(" usagemax service status|run|uninstall\n");
|
|
133
133
|
process.stdout.write(" usagemax doctor [--deep] [--json] [--quiet|--no-progress]\n");
|
|
134
134
|
process.stdout.write(" Check source coverage; --deep parses full history\n");
|
|
135
|
-
process.stdout.write(" usagemax update
|
|
136
|
-
process.stdout.write(" [--json]
|
|
135
|
+
process.stdout.write(" usagemax update Update the global CLI through Bun or npm\n");
|
|
136
|
+
process.stdout.write(" [--check] [--json] Check only or emit machine-readable status\n");
|
|
137
|
+
process.stdout.write(" usagemax update <command args> Run a command through the latest CLI\n");
|
|
137
138
|
process.stdout.write(" usagemax report [...args] Run a local ccusage report\n");
|
|
138
139
|
process.stdout.write(" usagemax unlink [--revoke] Remove locally; --revoke also disables uploads\n");
|
|
139
140
|
process.stdout.write(" [--json] Emit machine-readable unlink status\n");
|
|
@@ -622,6 +623,9 @@ async function report(args) {
|
|
|
622
623
|
|
|
623
624
|
async function update(args = []) {
|
|
624
625
|
const json = args.includes("--json");
|
|
626
|
+
const checkOnly = args.includes("--check") || args.includes("--no-install");
|
|
627
|
+
const commandArgs = args.filter((arg) => !["--check", "--no-install", "--json"].includes(arg));
|
|
628
|
+
const handoffArgs = commandArgs.length ? [...commandArgs, ...(json ? ["--json"] : [])] : [];
|
|
625
629
|
const check = await checkForUpdate(configDirectory(), VERSION, { force: true });
|
|
626
630
|
if (!check.latest) {
|
|
627
631
|
const result = { version: VERSION, latest: null, newer: false, status: "unavailable" };
|
|
@@ -633,15 +637,31 @@ async function update(args = []) {
|
|
|
633
637
|
process.stdout.write(json ? `${JSON.stringify(result)}\n` : `UsageMax CLI ${VERSION} is current.\n`);
|
|
634
638
|
return;
|
|
635
639
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
640
|
+
if (handoffArgs.length) {
|
|
641
|
+
const result = { version: VERSION, latest: check.latest, newer: true, status: "available", command: `usagemax update ${commandArgs.join(" ")}` };
|
|
642
|
+
process.stdout.write(json ? `${JSON.stringify(result)}\n` : `UsageMax CLI ${check.latest} is available (current ${VERSION}).\n`);
|
|
643
|
+
if (!json) process.stdout.write(`Launching UsageMax ${check.latest}…\n`);
|
|
644
|
+
return runLatest(handoffArgs);
|
|
645
|
+
}
|
|
646
|
+
const manager = packageManagerFor({ cliPath: process.argv[1], runtime: process.versions, env: process.env });
|
|
647
|
+
const installCommand = manager === "bun" ? "bun add --global usagemax@latest" : "npm install --global usagemax@latest";
|
|
648
|
+
const available = { version: VERSION, latest: check.latest, newer: true, status: "available", manager, installCommand };
|
|
649
|
+
if (checkOnly) {
|
|
650
|
+
process.stdout.write(json ? `${JSON.stringify(available)}\n` : `UsageMax CLI ${check.latest} is available (current ${VERSION}). Run \`${installCommand}\`.\n`);
|
|
641
651
|
return;
|
|
642
652
|
}
|
|
643
|
-
if (!json) process.stdout.write(`
|
|
644
|
-
|
|
653
|
+
if (!json) process.stdout.write(`Updating UsageMax ${VERSION} → ${check.latest} via ${manager}…\n`);
|
|
654
|
+
try {
|
|
655
|
+
await updateGlobal({ latest: check.latest, manager, quiet: json });
|
|
656
|
+
} catch (error) {
|
|
657
|
+
const result = { ...available, status: "failed", error: error instanceof Error ? error.message : String(error) };
|
|
658
|
+
if (json) process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
659
|
+
else process.stderr.write(`UsageMax update failed: ${result.error}\n`);
|
|
660
|
+
process.exitCode = 1;
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const result = { ...available, status: "updated", installedVersion: check.latest };
|
|
664
|
+
process.stdout.write(json ? `${JSON.stringify(result)}\n` : `UsageMax CLI is now ${check.latest}.\n`);
|
|
645
665
|
}
|
|
646
666
|
|
|
647
667
|
async function maybeUpdate(command, args) {
|
package/src/updates.js
CHANGED
|
@@ -83,6 +83,43 @@ function runner() {
|
|
|
83
83
|
return { command: "bunx", prefix: ["--bun"] };
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Pick the package manager that owns the current invocation. Bun's global and
|
|
88
|
+
* ephemeral package paths are explicit; npm remains the safe default for a
|
|
89
|
+
* normal Node installation. The override is useful for managed environments
|
|
90
|
+
* where the executable is wrapped by a fleet-specific package manager.
|
|
91
|
+
*/
|
|
92
|
+
export function packageManagerFor({ cliPath = process.argv[1], runtime = process.versions, env = process.env } = {}) {
|
|
93
|
+
const override = String(env.USAGEMAX_PACKAGE_MANAGER || "").trim().toLowerCase();
|
|
94
|
+
if (override === "bun" || override === "npm") return override;
|
|
95
|
+
const normalizedPath = String(cliPath || "").replaceAll("\\", "/");
|
|
96
|
+
if (normalizedPath.includes("/.bun/install/") || runtime?.bun) return "bun";
|
|
97
|
+
if (env.npm_execpath || String(env.npm_config_user_agent || "").startsWith("npm/")) return "npm";
|
|
98
|
+
return "npm";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Install the current public release into the user's global package scope. */
|
|
102
|
+
export async function updateGlobal({ latest = "latest", manager = packageManagerFor(), spawnImpl = spawn, env = process.env, quiet = false, platform = process.platform } = {}) {
|
|
103
|
+
if (manager !== "bun" && manager !== "npm") throw new Error(`Unsupported package manager: ${manager}`);
|
|
104
|
+
if (!/^\d+\.\d+\.\d+$/.test(String(latest)) && latest !== "latest") throw new Error("Invalid UsageMax release version.");
|
|
105
|
+
const command = manager === "bun" ? (platform === "win32" ? "bun.exe" : "bun") : (platform === "win32" ? "npm.cmd" : "npm");
|
|
106
|
+
const args = manager === "bun"
|
|
107
|
+
? ["add", "--global", `usagemax@${latest}`]
|
|
108
|
+
: ["install", "--global", `usagemax@${latest}`];
|
|
109
|
+
const child = spawnImpl(command, args, {
|
|
110
|
+
stdio: quiet ? ["ignore", "pipe", "pipe"] : "inherit",
|
|
111
|
+
env: { ...env, NPM_CONFIG_UPDATE_NOTIFIER: "false" },
|
|
112
|
+
});
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
child.once("error", reject);
|
|
115
|
+
child.once("exit", (status) => {
|
|
116
|
+
const code = status ?? 1;
|
|
117
|
+
if (code === 0) resolve({ manager, command, args });
|
|
118
|
+
else reject(Object.assign(new Error(`${command} ${args.join(" ")} exited with code ${code}.`), { code: "USAGEMAX_UPDATE_FAILED", exitCode: code }));
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
86
123
|
/** Re-run a command through the current npm dist-tag without requiring @latest. */
|
|
87
124
|
export async function runLatest(args, { spawnImpl = spawn } = {}) {
|
|
88
125
|
const selected = runner();
|