@imdeadpool/codex-account-switcher 0.1.8 → 0.1.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 +8 -0
- package/dist/commands/list.d.ts +1 -0
- package/dist/commands/list.js +33 -0
- package/dist/commands/self-update.d.ts +8 -0
- package/dist/commands/self-update.js +40 -0
- package/dist/hooks/init/update-notifier.d.ts +3 -0
- package/dist/hooks/init/update-notifier.js +20 -0
- package/dist/lib/accounts/account-service.d.ts +1 -0
- package/dist/lib/accounts/account-service.js +23 -5
- package/dist/lib/update-check.d.ts +5 -0
- package/dist/lib/update-check.js +84 -0
- package/dist/tests/save-account-safety.test.js +32 -3
- package/dist/tests/update-check.test.d.ts +1 -0
- package/dist/tests/update-check.test.js +29 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -60,6 +60,12 @@ codex-auth list --details
|
|
|
60
60
|
# show current account name
|
|
61
61
|
codex-auth current
|
|
62
62
|
|
|
63
|
+
# check for a newer release and update globally
|
|
64
|
+
codex-auth self-update
|
|
65
|
+
|
|
66
|
+
# check only (no install)
|
|
67
|
+
codex-auth self-update --check
|
|
68
|
+
|
|
63
69
|
# remove accounts (interactive multi-select)
|
|
64
70
|
codex-auth remove
|
|
65
71
|
|
|
@@ -96,6 +102,7 @@ codex-auth remove-login-hook
|
|
|
96
102
|
- `codex-auth use [name]` – Accepts a name or launches an interactive selector with the current account pre-selected, writes `~/.codex/auth.json` as a regular file from the chosen snapshot, and records the active name.
|
|
97
103
|
- `codex-auth list [--details]` – Lists all saved snapshots alphabetically and marks the active one with `*`. `--details` adds per-snapshot mapping metadata (email, account id, user id, and usage metadata) for easier session/account troubleshooting.
|
|
98
104
|
- `codex-auth current` – Prints the active account name, or a friendly message if none is active.
|
|
105
|
+
- `codex-auth self-update [--check]` – Checks npm for a newer release. Without flags, it installs the latest version globally when one is available.
|
|
99
106
|
- `codex-auth remove [query|--all]` – Removes snapshots interactively or by selector. If the active account is removed, the best remaining account is activated automatically.
|
|
100
107
|
- `codex-auth status` – Prints auto-switch state, managed service status, active thresholds, and usage mode.
|
|
101
108
|
- `codex-auth config auto ...` – Enables/disables managed auto-switch and updates threshold percentages.
|
|
@@ -131,3 +138,4 @@ Notes:
|
|
|
131
138
|
|
|
132
139
|
- Works on macOS/Linux/Windows (regular-file auth snapshot activation).
|
|
133
140
|
- Requires Node 18+.
|
|
141
|
+
- Running bare `codex-auth` shows the help screen and also displays an update notice when a newer npm release is available.
|
package/dist/commands/list.d.ts
CHANGED
package/dist/commands/list.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const core_1 = require("@oclif/core");
|
|
7
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
4
8
|
const base_command_1 = require("../lib/base-command");
|
|
9
|
+
const update_check_1 = require("../lib/update-check");
|
|
5
10
|
class ListCommand extends base_command_1.BaseCommand {
|
|
6
11
|
async run() {
|
|
7
12
|
await this.runSafe(async () => {
|
|
8
13
|
var _a, _b, _c, _d, _e, _f;
|
|
9
14
|
const { flags } = await this.parse(ListCommand);
|
|
10
15
|
const detailed = Boolean(flags.details);
|
|
16
|
+
await this.maybeOfferGlobalUpdate();
|
|
11
17
|
if (!detailed) {
|
|
12
18
|
const accounts = await this.accounts.listAccountNames();
|
|
13
19
|
const current = await this.accounts.getCurrentAccountName();
|
|
@@ -34,6 +40,33 @@ class ListCommand extends base_command_1.BaseCommand {
|
|
|
34
40
|
}
|
|
35
41
|
});
|
|
36
42
|
}
|
|
43
|
+
async maybeOfferGlobalUpdate() {
|
|
44
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
45
|
+
return;
|
|
46
|
+
const currentVersion = this.config.version;
|
|
47
|
+
if (!currentVersion || typeof currentVersion !== "string")
|
|
48
|
+
return;
|
|
49
|
+
const latestVersion = await (0, update_check_1.fetchLatestNpmVersion)(update_check_1.PACKAGE_NAME);
|
|
50
|
+
if (!latestVersion || !(0, update_check_1.isVersionNewer)(currentVersion, latestVersion))
|
|
51
|
+
return;
|
|
52
|
+
this.log(`Update available for codex-auth: ${currentVersion} -> ${latestVersion}`);
|
|
53
|
+
const prompt = await (0, prompts_1.default)({
|
|
54
|
+
type: "confirm",
|
|
55
|
+
name: "install",
|
|
56
|
+
message: "Press Enter to update globally now",
|
|
57
|
+
initial: true,
|
|
58
|
+
});
|
|
59
|
+
if (!prompt.install) {
|
|
60
|
+
this.log(`Skipped update. Run manually: npm i -g ${update_check_1.PACKAGE_NAME}@latest`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const installExitCode = await (0, update_check_1.runGlobalNpmInstall)(update_check_1.PACKAGE_NAME);
|
|
64
|
+
if (installExitCode === 0) {
|
|
65
|
+
this.log("Global update completed.");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.warn(`Global update failed (exit code ${installExitCode}). Try: npm i -g ${update_check_1.PACKAGE_NAME}@latest`);
|
|
69
|
+
}
|
|
37
70
|
}
|
|
38
71
|
ListCommand.description = "List accounts managed under ~/.codex";
|
|
39
72
|
ListCommand.flags = {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseCommand } from "../lib/base-command";
|
|
2
|
+
export default class SelfUpdateCommand extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
readonly check: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
6
|
+
};
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../lib/base-command");
|
|
5
|
+
const update_check_1 = require("../lib/update-check");
|
|
6
|
+
class SelfUpdateCommand extends base_command_1.BaseCommand {
|
|
7
|
+
async run() {
|
|
8
|
+
await this.runSafe(async () => {
|
|
9
|
+
const { flags } = await this.parse(SelfUpdateCommand);
|
|
10
|
+
const currentVersion = this.config.version;
|
|
11
|
+
const latestVersion = await (0, update_check_1.fetchLatestNpmVersion)(update_check_1.PACKAGE_NAME);
|
|
12
|
+
if (!latestVersion) {
|
|
13
|
+
this.warn("Could not check npm for the latest release right now.");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (!(0, update_check_1.isVersionNewer)(currentVersion, latestVersion)) {
|
|
17
|
+
this.log(`codex-auth is up to date (${currentVersion}).`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
this.log(`Update available: ${currentVersion} -> ${latestVersion}`);
|
|
21
|
+
if (flags.check) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const exitCode = await (0, update_check_1.runGlobalNpmInstall)(update_check_1.PACKAGE_NAME);
|
|
25
|
+
if (exitCode === 0) {
|
|
26
|
+
this.log("Global update completed.");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.warn(`Global update failed (exit code ${exitCode}). Run: npm i -g ${update_check_1.PACKAGE_NAME}@latest`);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
SelfUpdateCommand.description = "Check for updates and upgrade codex-auth globally";
|
|
34
|
+
SelfUpdateCommand.flags = {
|
|
35
|
+
check: core_1.Flags.boolean({
|
|
36
|
+
description: "Only check whether an update is available",
|
|
37
|
+
default: false,
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
exports.default = SelfUpdateCommand;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const update_check_1 = require("../../lib/update-check");
|
|
4
|
+
const hook = async function (options) {
|
|
5
|
+
if (options.id)
|
|
6
|
+
return;
|
|
7
|
+
if (options.argv.length > 0)
|
|
8
|
+
return;
|
|
9
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
10
|
+
return;
|
|
11
|
+
const currentVersion = options.config.version;
|
|
12
|
+
if (!currentVersion)
|
|
13
|
+
return;
|
|
14
|
+
const latestVersion = await (0, update_check_1.fetchLatestNpmVersion)(update_check_1.PACKAGE_NAME);
|
|
15
|
+
if (!latestVersion || !(0, update_check_1.isVersionNewer)(currentVersion, latestVersion))
|
|
16
|
+
return;
|
|
17
|
+
this.log(`Update available for codex-auth: ${currentVersion} -> ${latestVersion}`);
|
|
18
|
+
this.log("Run `codex-auth self-update` to install the latest version.");
|
|
19
|
+
};
|
|
20
|
+
exports.default = hook;
|
|
@@ -31,16 +31,26 @@ class AccountService {
|
|
|
31
31
|
autoSwitchDisabled: false,
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
const resolvedName = await this.resolveLoginAccountNameFromCurrentAuth();
|
|
34
35
|
const activeName = await this.getCurrentAccountName();
|
|
35
36
|
if (activeName) {
|
|
36
37
|
const activeSnapshotPath = this.accountFilePath(activeName);
|
|
37
38
|
if (await this.pathExists(activeSnapshotPath)) {
|
|
38
39
|
const activeSnapshot = await (0, auth_parser_1.parseAuthSnapshotFile)(activeSnapshotPath);
|
|
39
40
|
if (this.snapshotsShareIdentity(activeSnapshot, incomingSnapshot)) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
if (activeName === resolvedName.name) {
|
|
42
|
+
return {
|
|
43
|
+
synchronized: false,
|
|
44
|
+
autoSwitchDisabled: false,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const authMatchesActiveSnapshot = await this.filesMatch(authPath, activeSnapshotPath);
|
|
48
|
+
if (authMatchesActiveSnapshot) {
|
|
49
|
+
return {
|
|
50
|
+
synchronized: false,
|
|
51
|
+
autoSwitchDisabled: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
56
|
}
|
|
@@ -49,7 +59,6 @@ class AccountService {
|
|
|
49
59
|
if (autoSwitchDisabled) {
|
|
50
60
|
await this.setAutoSwitchEnabled(false);
|
|
51
61
|
}
|
|
52
|
-
const resolvedName = await this.resolveLoginAccountNameFromCurrentAuth();
|
|
53
62
|
const savedName = await this.saveAccount(resolvedName.name);
|
|
54
63
|
return {
|
|
55
64
|
synchronized: true,
|
|
@@ -550,6 +559,15 @@ class AccountService {
|
|
|
550
559
|
return false;
|
|
551
560
|
}
|
|
552
561
|
}
|
|
562
|
+
async filesMatch(firstPath, secondPath) {
|
|
563
|
+
try {
|
|
564
|
+
const [first, second] = await Promise.all([promises_1.default.readFile(firstPath), promises_1.default.readFile(secondPath)]);
|
|
565
|
+
return first.equals(second);
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
553
571
|
async hydrateSnapshotMetadata(registry, accountName) {
|
|
554
572
|
var _a;
|
|
555
573
|
const parsed = await (0, auth_parser_1.parseAuthSnapshotFile)(this.accountFilePath(accountName));
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const PACKAGE_NAME = "@imdeadpool/codex-account-switcher";
|
|
2
|
+
export declare function parseVersionTriplet(version: string): [number, number, number] | null;
|
|
3
|
+
export declare function isVersionNewer(currentVersion: string, latestVersion: string): boolean;
|
|
4
|
+
export declare function fetchLatestNpmVersion(packageName: string, timeoutMs?: number): Promise<string | null>;
|
|
5
|
+
export declare function runGlobalNpmInstall(packageName: string, version?: "latest" | string): Promise<number>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PACKAGE_NAME = void 0;
|
|
4
|
+
exports.parseVersionTriplet = parseVersionTriplet;
|
|
5
|
+
exports.isVersionNewer = isVersionNewer;
|
|
6
|
+
exports.fetchLatestNpmVersion = fetchLatestNpmVersion;
|
|
7
|
+
exports.runGlobalNpmInstall = runGlobalNpmInstall;
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
const SEMVER_TRIPLET = /^v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/;
|
|
10
|
+
exports.PACKAGE_NAME = "@imdeadpool/codex-account-switcher";
|
|
11
|
+
function parseVersionTriplet(version) {
|
|
12
|
+
const match = version.trim().match(SEMVER_TRIPLET);
|
|
13
|
+
if (!match)
|
|
14
|
+
return null;
|
|
15
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
16
|
+
}
|
|
17
|
+
function isVersionNewer(currentVersion, latestVersion) {
|
|
18
|
+
const current = parseVersionTriplet(currentVersion);
|
|
19
|
+
const latest = parseVersionTriplet(latestVersion);
|
|
20
|
+
if (!current || !latest)
|
|
21
|
+
return false;
|
|
22
|
+
for (let i = 0; i < 3; i += 1) {
|
|
23
|
+
if (latest[i] > current[i])
|
|
24
|
+
return true;
|
|
25
|
+
if (latest[i] < current[i])
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
async function fetchLatestNpmVersion(packageName, timeoutMs = 2500) {
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
const child = (0, node_child_process_1.spawn)("npm", ["view", packageName, "version", "--json"], {
|
|
33
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
34
|
+
});
|
|
35
|
+
let output = "";
|
|
36
|
+
const timeout = setTimeout(() => {
|
|
37
|
+
child.kill("SIGTERM");
|
|
38
|
+
resolve(null);
|
|
39
|
+
}, timeoutMs);
|
|
40
|
+
child.stdout.on("data", (chunk) => {
|
|
41
|
+
output += chunk.toString();
|
|
42
|
+
});
|
|
43
|
+
child.on("error", () => {
|
|
44
|
+
clearTimeout(timeout);
|
|
45
|
+
resolve(null);
|
|
46
|
+
});
|
|
47
|
+
child.on("exit", (code) => {
|
|
48
|
+
clearTimeout(timeout);
|
|
49
|
+
if (code !== 0) {
|
|
50
|
+
resolve(null);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const trimmed = output.trim();
|
|
54
|
+
if (!trimmed) {
|
|
55
|
+
resolve(null);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(trimmed);
|
|
60
|
+
if (typeof parsed === "string" && parsed.trim().length > 0) {
|
|
61
|
+
resolve(parsed.trim());
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// fall through
|
|
67
|
+
}
|
|
68
|
+
resolve(trimmed.replace(/^"+|"+$/g, ""));
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function runGlobalNpmInstall(packageName, version = "latest") {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
const child = (0, node_child_process_1.spawn)("npm", ["i", "-g", `${packageName}@${version}`], {
|
|
75
|
+
stdio: "inherit",
|
|
76
|
+
});
|
|
77
|
+
child.on("error", () => {
|
|
78
|
+
resolve(1);
|
|
79
|
+
});
|
|
80
|
+
child.on("exit", (code) => {
|
|
81
|
+
resolve(typeof code === "number" ? code : 1);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -19,9 +19,10 @@ function encodeBase64Url(input) {
|
|
|
19
19
|
.replace(/=+$/g, "");
|
|
20
20
|
}
|
|
21
21
|
function buildAuthPayload(email, options) {
|
|
22
|
-
var _a, _b;
|
|
22
|
+
var _a, _b, _c;
|
|
23
23
|
const accountId = (_a = options === null || options === void 0 ? void 0 : options.accountId) !== null && _a !== void 0 ? _a : "acct-1";
|
|
24
24
|
const userId = (_b = options === null || options === void 0 ? void 0 : options.userId) !== null && _b !== void 0 ? _b : "user-1";
|
|
25
|
+
const tokenSeed = (_c = options === null || options === void 0 ? void 0 : options.tokenSeed) !== null && _c !== void 0 ? _c : email;
|
|
25
26
|
const idTokenPayload = {
|
|
26
27
|
email,
|
|
27
28
|
"https://api.openai.com/auth": {
|
|
@@ -33,8 +34,8 @@ function buildAuthPayload(email, options) {
|
|
|
33
34
|
const idToken = `${encodeBase64Url(JSON.stringify({ alg: "none" }))}.${encodeBase64Url(JSON.stringify(idTokenPayload))}.sig`;
|
|
34
35
|
return JSON.stringify({
|
|
35
36
|
tokens: {
|
|
36
|
-
access_token: `token-${
|
|
37
|
-
refresh_token: `refresh-${
|
|
37
|
+
access_token: `token-${tokenSeed}`,
|
|
38
|
+
refresh_token: `refresh-${tokenSeed}`,
|
|
38
39
|
id_token: idToken,
|
|
39
40
|
account_id: accountId,
|
|
40
41
|
},
|
|
@@ -362,6 +363,34 @@ async function withIsolatedCodexDir(t, fn) {
|
|
|
362
363
|
strict_1.default.equal(registry.autoSwitch.enabled, false);
|
|
363
364
|
});
|
|
364
365
|
});
|
|
366
|
+
(0, node_test_1.default)("syncExternalAuthSnapshotIfNeeded re-keys active alias to inferred email name when external login identity matches", async (t) => {
|
|
367
|
+
await withIsolatedCodexDir(t, async ({ codexDir, accountsDir, authPath }) => {
|
|
368
|
+
const service = new account_service_1.AccountService();
|
|
369
|
+
const activeAlias = "team-primary";
|
|
370
|
+
const incomingEmail = "admin@kozpontihusbolt.hu";
|
|
371
|
+
const currentPath = node_path_1.default.join(codexDir, "current");
|
|
372
|
+
await promises_1.default.writeFile(node_path_1.default.join(accountsDir, `${activeAlias}.json`), buildAuthPayload(incomingEmail, {
|
|
373
|
+
accountId: "acct-team",
|
|
374
|
+
userId: "user-team",
|
|
375
|
+
tokenSeed: "pre-login",
|
|
376
|
+
}), "utf8");
|
|
377
|
+
await promises_1.default.writeFile(currentPath, `${activeAlias}\n`, "utf8");
|
|
378
|
+
await promises_1.default.writeFile(authPath, buildAuthPayload(incomingEmail, {
|
|
379
|
+
accountId: "acct-team",
|
|
380
|
+
userId: "user-team",
|
|
381
|
+
tokenSeed: "post-login",
|
|
382
|
+
}), "utf8");
|
|
383
|
+
const result = await service.syncExternalAuthSnapshotIfNeeded();
|
|
384
|
+
strict_1.default.deepEqual(result, {
|
|
385
|
+
synchronized: true,
|
|
386
|
+
savedName: incomingEmail,
|
|
387
|
+
autoSwitchDisabled: false,
|
|
388
|
+
});
|
|
389
|
+
strict_1.default.equal((await promises_1.default.readFile(currentPath, "utf8")).trim(), incomingEmail);
|
|
390
|
+
const inferredSnapshot = await (0, auth_parser_1.parseAuthSnapshotFile)(node_path_1.default.join(accountsDir, `${incomingEmail}.json`));
|
|
391
|
+
strict_1.default.equal(inferredSnapshot.email, incomingEmail);
|
|
392
|
+
});
|
|
393
|
+
});
|
|
365
394
|
(0, node_test_1.default)("syncExternalAuthSnapshotIfNeeded materializes auth symlink so external codex login can no longer overwrite snapshot files", async (t) => {
|
|
366
395
|
if (process.platform === "win32") {
|
|
367
396
|
t.skip("symlink conversion behavior is Unix-specific in this test");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const node_test_1 = __importDefault(require("node:test"));
|
|
7
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
8
|
+
const update_check_1 = require("../lib/update-check");
|
|
9
|
+
(0, node_test_1.default)("parseVersionTriplet parses standard semver triplets", () => {
|
|
10
|
+
strict_1.default.deepEqual((0, update_check_1.parseVersionTriplet)("0.1.9"), [0, 1, 9]);
|
|
11
|
+
strict_1.default.deepEqual((0, update_check_1.parseVersionTriplet)("v1.20.3"), [1, 20, 3]);
|
|
12
|
+
});
|
|
13
|
+
(0, node_test_1.default)("parseVersionTriplet supports pre-release/build suffixes", () => {
|
|
14
|
+
strict_1.default.deepEqual((0, update_check_1.parseVersionTriplet)("1.2.3-beta.1"), [1, 2, 3]);
|
|
15
|
+
strict_1.default.deepEqual((0, update_check_1.parseVersionTriplet)("1.2.3+build"), [1, 2, 3]);
|
|
16
|
+
});
|
|
17
|
+
(0, node_test_1.default)("parseVersionTriplet rejects non-triplet versions", () => {
|
|
18
|
+
strict_1.default.equal((0, update_check_1.parseVersionTriplet)("1.2"), null);
|
|
19
|
+
strict_1.default.equal((0, update_check_1.parseVersionTriplet)("latest"), null);
|
|
20
|
+
});
|
|
21
|
+
(0, node_test_1.default)("isVersionNewer compares semver triplets correctly", () => {
|
|
22
|
+
strict_1.default.equal((0, update_check_1.isVersionNewer)("0.1.8", "0.1.9"), true);
|
|
23
|
+
strict_1.default.equal((0, update_check_1.isVersionNewer)("0.1.9", "0.1.9"), false);
|
|
24
|
+
strict_1.default.equal((0, update_check_1.isVersionNewer)("0.2.0", "0.1.9"), false);
|
|
25
|
+
});
|
|
26
|
+
(0, node_test_1.default)("isVersionNewer returns false when either version is invalid", () => {
|
|
27
|
+
strict_1.default.equal((0, update_check_1.isVersionNewer)("latest", "0.1.9"), false);
|
|
28
|
+
strict_1.default.equal((0, update_check_1.isVersionNewer)("0.1.8", "nightly"), false);
|
|
29
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imdeadpool/codex-account-switcher",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "A command-line tool that lets you manage and switch between multiple Codex accounts instantly, no more constant logins and logouts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -52,6 +52,9 @@
|
|
|
52
52
|
},
|
|
53
53
|
"oclif": {
|
|
54
54
|
"bin": "codex-auth",
|
|
55
|
-
"commands": "./dist/commands"
|
|
55
|
+
"commands": "./dist/commands",
|
|
56
|
+
"hooks": {
|
|
57
|
+
"init": "./dist/hooks/init/update-notifier"
|
|
58
|
+
}
|
|
56
59
|
}
|
|
57
60
|
}
|