codex-multi-auth 2.1.4 → 2.1.5

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.
@@ -1,730 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmdirSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { createLogger } from "./logger.js";
6
- import { getCodexCacheDir } from "./runtime-paths.js";
7
- const log = createLogger("update-checker");
8
- const PACKAGE_NAME = "codex-multi-auth";
9
- const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
10
- const CACHE_DIR = getCodexCacheDir();
11
- const CACHE_FILE = join(CACHE_DIR, "update-check-cache.json");
12
- const AUTO_UPDATE_LOCK_DIR = join(CACHE_DIR, "auto-update.lock");
13
- const AUTO_UPDATE_LOCK_OWNER_FILE = join(AUTO_UPDATE_LOCK_DIR, "owner.json");
14
- const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
15
- const UPDATE_CHECK_TIMEOUT_MS = 5_000;
16
- const AUTO_UPDATE_TIMEOUT_MS = 2 * 60 * 1000;
17
- const AUTO_UPDATE_LOCK_STALE_MS = 10 * 60 * 1000;
18
- const TASKKILL_TIMEOUT_MS = 5_000;
19
- const AUTO_UPDATE_ENV_NAME = "CODEX_MULTI_AUTH_AUTO_UPDATE";
20
- const TRUE_VALUES = new Set(["1", "true", "yes"]);
21
- const FALSE_VALUES = new Set(["0", "false", "no"]);
22
- const SAFE_SUBPROCESS_ENV_KEYS = new Set([
23
- "APPDATA",
24
- "COMSPEC",
25
- "HOME",
26
- "LANG",
27
- "LC_ALL",
28
- "LC_CTYPE",
29
- "LOCALAPPDATA",
30
- "NUMBER_OF_PROCESSORS",
31
- "OS",
32
- "PATH",
33
- "PATHEXT",
34
- "PROCESSOR_ARCHITECTURE",
35
- "PROGRAMFILES",
36
- "PROGRAMFILES(X86)",
37
- "PROGRAMW6432",
38
- "SYSTEMDRIVE",
39
- "SYSTEMROOT",
40
- "TEMP",
41
- "TMP",
42
- "USERPROFILE",
43
- "WINDIR",
44
- ]);
45
- const SENSITIVE_SUBPROCESS_ENV_KEY_PATTERN = /(?:AUTH|COOKIE|CREDENTIAL|OPENAI|CHATGPT|PASSWORD|SECRET|SESSION|TOKEN)/i;
46
- const CI_ENV_KEYS = [
47
- "CI",
48
- "GITHUB_ACTIONS",
49
- "GITLAB_CI",
50
- "CIRCLECI",
51
- "BUILDKITE",
52
- "TF_BUILD",
53
- "TEAMCITY_VERSION",
54
- "JENKINS_URL",
55
- "TRAVIS",
56
- "APPVEYOR",
57
- "BITBUCKET_BUILD_NUMBER",
58
- "VITEST",
59
- ];
60
- const RETRYABLE_WRITE_ERRORS = new Set(["EBUSY", "EPERM", "ENOTEMPTY"]);
61
- let updateCacheWriteQueue = Promise.resolve();
62
- let cachedPackageRoot;
63
- function enqueueUpdateCacheWrite(writeTask) {
64
- const queued = updateCacheWriteQueue.catch(() => undefined).then(writeTask);
65
- updateCacheWriteQueue = queued.then(() => undefined, () => undefined);
66
- return queued;
67
- }
68
- function writeCacheContents(serialized) {
69
- let tempPath = null;
70
- let wroteTemp = false;
71
- try {
72
- if (!existsSync(CACHE_DIR)) {
73
- mkdirSync(CACHE_DIR, { recursive: true });
74
- }
75
- tempPath = `${CACHE_FILE}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
76
- let lastError = null;
77
- for (let attempt = 0; attempt < 4; attempt++) {
78
- try {
79
- writeFileSync(tempPath, serialized, "utf8");
80
- renameSync(tempPath, CACHE_FILE);
81
- wroteTemp = false;
82
- return;
83
- }
84
- catch (error) {
85
- const code = error.code ?? "";
86
- lastError = error;
87
- wroteTemp = true;
88
- if (!RETRYABLE_WRITE_ERRORS.has(code) || attempt >= 3) {
89
- throw error;
90
- }
91
- sleepSync(15 * (2 ** attempt));
92
- }
93
- }
94
- if (lastError)
95
- throw lastError;
96
- }
97
- finally {
98
- if (wroteTemp && tempPath) {
99
- try {
100
- unlinkSync(tempPath);
101
- }
102
- catch {
103
- // Best effort temp cleanup.
104
- }
105
- }
106
- }
107
- }
108
- function sleepSync(ms) {
109
- const delay = Math.max(0, Math.floor(ms));
110
- if (delay === 0)
111
- return;
112
- const lock = new Int32Array(new SharedArrayBuffer(4));
113
- Atomics.wait(lock, 0, 0, delay);
114
- }
115
- function getCurrentVersion() {
116
- try {
117
- const packageJsonPath = join(getPackageRoot(), "package.json");
118
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
119
- return packageJson.version;
120
- }
121
- catch (error) {
122
- log.debug("Failed to read current package version", {
123
- error: error instanceof Error ? error.message : String(error),
124
- });
125
- return "0.0.0";
126
- }
127
- }
128
- function loadCache() {
129
- try {
130
- if (!existsSync(CACHE_FILE))
131
- return null;
132
- const content = readFileSync(CACHE_FILE, "utf8");
133
- return JSON.parse(content);
134
- }
135
- catch (error) {
136
- log.debug("Failed to load update cache", {
137
- error: error instanceof Error ? error.message : String(error),
138
- });
139
- return null;
140
- }
141
- }
142
- async function saveCache(cache) {
143
- await enqueueUpdateCacheWrite(() => {
144
- try {
145
- writeCacheContents(JSON.stringify(cache, null, 2));
146
- }
147
- catch (error) {
148
- log.warn("Failed to save update cache", { error: error.message });
149
- }
150
- });
151
- }
152
- function parseSemver(version) {
153
- const normalized = version.trim().replace(/^v/i, "");
154
- const [withoutBuild] = normalized.split("+");
155
- const [corePart = "0.0.0", prereleasePart] = (withoutBuild ?? "0.0.0").split("-", 2);
156
- const [majorRaw = "0", minorRaw = "0", patchRaw = "0"] = corePart.split(".");
157
- const toSafeInt = (value) => {
158
- if (!/^\d+$/.test(value))
159
- return 0;
160
- const parsed = Number.parseInt(value, 10);
161
- return Number.isFinite(parsed) ? parsed : 0;
162
- };
163
- return {
164
- core: [toSafeInt(majorRaw), toSafeInt(minorRaw), toSafeInt(patchRaw)],
165
- prerelease: prereleasePart && prereleasePart.trim().length > 0
166
- ? prereleasePart.split(".").filter((segment) => segment.length > 0)
167
- : [],
168
- };
169
- }
170
- function comparePrerelease(current, latest) {
171
- const maxLen = Math.max(current.length, latest.length);
172
- for (let i = 0; i < maxLen; i++) {
173
- const currentPart = current[i];
174
- const latestPart = latest[i];
175
- if (currentPart === undefined && latestPart === undefined)
176
- return 0;
177
- if (currentPart === undefined)
178
- return 1;
179
- if (latestPart === undefined)
180
- return -1;
181
- if (currentPart === latestPart)
182
- continue;
183
- const currentIsNumeric = /^\d+$/.test(currentPart);
184
- const latestIsNumeric = /^\d+$/.test(latestPart);
185
- if (currentIsNumeric && latestIsNumeric) {
186
- const currentNum = Number.parseInt(currentPart, 10);
187
- const latestNum = Number.parseInt(latestPart, 10);
188
- if (latestNum > currentNum)
189
- return 1;
190
- if (latestNum < currentNum)
191
- return -1;
192
- continue;
193
- }
194
- if (currentIsNumeric && !latestIsNumeric)
195
- return 1;
196
- if (!currentIsNumeric && latestIsNumeric)
197
- return -1;
198
- const lexical = latestPart.localeCompare(currentPart, "en", { sensitivity: "case" });
199
- if (lexical > 0)
200
- return 1;
201
- if (lexical < 0)
202
- return -1;
203
- }
204
- return 0;
205
- }
206
- function compareVersions(current, latest) {
207
- const parsedCurrent = parseSemver(current);
208
- const parsedLatest = parseSemver(latest);
209
- for (let i = 0; i < parsedCurrent.core.length; i++) {
210
- const currentPart = parsedCurrent.core[i] ?? 0;
211
- const latestPart = parsedLatest.core[i] ?? 0;
212
- if (latestPart > currentPart)
213
- return 1;
214
- if (latestPart < currentPart)
215
- return -1;
216
- }
217
- const currentHasPrerelease = parsedCurrent.prerelease.length > 0;
218
- const latestHasPrerelease = parsedLatest.prerelease.length > 0;
219
- if (!currentHasPrerelease && latestHasPrerelease) {
220
- return -1;
221
- }
222
- if (currentHasPrerelease && !latestHasPrerelease) {
223
- return 1;
224
- }
225
- return comparePrerelease(parsedCurrent.prerelease, parsedLatest.prerelease);
226
- }
227
- async function fetchLatestVersion(timeoutMs = UPDATE_CHECK_TIMEOUT_MS) {
228
- try {
229
- const controller = new AbortController();
230
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
231
- const response = await fetch(NPM_REGISTRY_URL, {
232
- signal: controller.signal,
233
- headers: { Accept: "application/json" },
234
- });
235
- clearTimeout(timeout);
236
- if (!response.ok) {
237
- log.debug("Failed to fetch npm registry", { status: response.status });
238
- return null;
239
- }
240
- const data = (await response.json());
241
- return data.version ?? null;
242
- }
243
- catch (error) {
244
- log.debug("Failed to check for updates", { error: error.message });
245
- return null;
246
- }
247
- }
248
- function readOptionalBoolean(value) {
249
- if (value === undefined || value.trim().length === 0)
250
- return null;
251
- const normalized = value.trim().toLowerCase();
252
- if (TRUE_VALUES.has(normalized))
253
- return true;
254
- if (FALSE_VALUES.has(normalized))
255
- return false;
256
- return null;
257
- }
258
- function isCiOrTestEnvironment(env) {
259
- return CI_ENV_KEYS.some((key) => {
260
- const value = env[key];
261
- if (value === undefined || value.trim().length === 0)
262
- return false;
263
- const parsed = readOptionalBoolean(value);
264
- return parsed !== false;
265
- });
266
- }
267
- export function isAutoUpdateEnabled(env = process.env) {
268
- const override = readOptionalBoolean(env[AUTO_UPDATE_ENV_NAME]);
269
- if (override !== null)
270
- return override;
271
- return !isCiOrTestEnvironment(env);
272
- }
273
- function getModuleDir() {
274
- const moduleDir = typeof import.meta.dirname === "string"
275
- ? import.meta.dirname
276
- : dirname(fileURLToPath(import.meta.url));
277
- return moduleDir;
278
- }
279
- export function resolvePackageRootFromModuleDir(moduleDir) {
280
- let current = moduleDir;
281
- for (let depth = 0; depth < 8; depth++) {
282
- const packageJsonPath = join(current, "package.json");
283
- try {
284
- if (existsSync(packageJsonPath)) {
285
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
286
- if (packageJson.name === PACKAGE_NAME)
287
- return current;
288
- }
289
- }
290
- catch {
291
- // Keep walking; malformed or unreadable package metadata should not break startup.
292
- }
293
- const parent = dirname(current);
294
- if (parent === current)
295
- break;
296
- current = parent;
297
- }
298
- return join(moduleDir, "..");
299
- }
300
- function getPackageRoot() {
301
- cachedPackageRoot ??= resolvePackageRootFromModuleDir(getModuleDir());
302
- return cachedPackageRoot;
303
- }
304
- export function isUpdateablePackageInstall(packageRoot = getPackageRoot()) {
305
- const normalized = packageRoot.replace(/\\/g, "/").toLowerCase();
306
- return normalized.endsWith("/node_modules/codex-multi-auth");
307
- }
308
- function resolveNpmCommand(platform) {
309
- return platform === "win32" ? "npm.cmd" : "npm";
310
- }
311
- function quoteCmdArg(value) {
312
- if (!/[\s&|<>^"]/.test(value))
313
- return value;
314
- return `"${value.replace(/"/g, '""')}"`;
315
- }
316
- function isSensitiveSubprocessEnvKey(key) {
317
- return SENSITIVE_SUBPROCESS_ENV_KEY_PATTERN.test(key);
318
- }
319
- function isSafeSubprocessEnvKey(key) {
320
- const normalized = key.toUpperCase();
321
- if (SAFE_SUBPROCESS_ENV_KEYS.has(normalized))
322
- return true;
323
- return normalized.startsWith("NPM_CONFIG_");
324
- }
325
- function buildAutoUpdateSubprocessEnv(env) {
326
- const mergedEnv = { ...process.env, ...env };
327
- const subprocessEnv = {};
328
- for (const [key, value] of Object.entries(mergedEnv)) {
329
- if (value === undefined)
330
- continue;
331
- if (isSensitiveSubprocessEnvKey(key))
332
- continue;
333
- if (!isSafeSubprocessEnvKey(key))
334
- continue;
335
- subprocessEnv[key] = value;
336
- }
337
- subprocessEnv[AUTO_UPDATE_ENV_NAME] = "0";
338
- return subprocessEnv;
339
- }
340
- function resolveUpdateSpawn(options) {
341
- const args = ["update", "-g", PACKAGE_NAME];
342
- if (options.platform !== "win32") {
343
- return { command: options.command, args };
344
- }
345
- return {
346
- command: process.env.ComSpec || "cmd.exe",
347
- args: [
348
- "/d",
349
- "/s",
350
- "/c",
351
- [options.command, ...args].map(quoteCmdArg).join(" "),
352
- ],
353
- };
354
- }
355
- async function runUpdateCommand(options) {
356
- return new Promise((resolve) => {
357
- let settled = false;
358
- let child = null;
359
- const updateSpawn = resolveUpdateSpawn({
360
- command: options.command,
361
- platform: options.platform,
362
- });
363
- function finish(result) {
364
- if (settled)
365
- return;
366
- settled = true;
367
- clearTimeout(timeout);
368
- resolve(result);
369
- }
370
- let timeoutStarted = false;
371
- const timeout = setTimeout(() => {
372
- timeoutStarted = true;
373
- void killUpdateProcessTree(child, options.platform)
374
- .catch(() => undefined)
375
- .finally(() => {
376
- finish({
377
- ok: false,
378
- exitCode: null,
379
- error: `Auto-update timed out after ${options.timeoutMs}ms`,
380
- });
381
- });
382
- }, options.timeoutMs);
383
- timeout.unref?.();
384
- try {
385
- child = spawn(updateSpawn.command, updateSpawn.args, {
386
- env: buildAutoUpdateSubprocessEnv(options.env),
387
- stdio: "ignore",
388
- windowsHide: options.platform === "win32",
389
- });
390
- child.unref?.();
391
- }
392
- catch (error) {
393
- finish({
394
- ok: false,
395
- exitCode: null,
396
- error: error instanceof Error ? error.message : String(error),
397
- });
398
- return;
399
- }
400
- child.once("error", (error) => {
401
- finish({
402
- ok: false,
403
- exitCode: null,
404
- error: error instanceof Error ? error.message : String(error),
405
- });
406
- });
407
- child.once("exit", (code, signal) => {
408
- if (timeoutStarted)
409
- return;
410
- finish({
411
- ok: code === 0,
412
- exitCode: code,
413
- error: code === 0
414
- ? null
415
- : `npm update exited with ${code ?? `signal ${signal ?? "unknown"}`}`,
416
- });
417
- });
418
- });
419
- }
420
- async function killUpdateProcessTree(child, platform) {
421
- if (!child)
422
- return;
423
- if (platform === "win32" && child.pid) {
424
- const killed = await taskkillProcessTree(child.pid);
425
- if (!killed) {
426
- child.kill();
427
- }
428
- return;
429
- }
430
- child.kill();
431
- }
432
- function taskkillProcessTree(pid) {
433
- return new Promise((resolve) => {
434
- let settled = false;
435
- function finish(killed) {
436
- if (settled)
437
- return;
438
- settled = true;
439
- clearTimeout(timeout);
440
- resolve(killed);
441
- }
442
- const timeout = setTimeout(() => finish(false), TASKKILL_TIMEOUT_MS);
443
- timeout.unref?.();
444
- try {
445
- const killer = spawn("cmd.exe", [
446
- "/d",
447
- "/s",
448
- "/c",
449
- `taskkill /PID ${pid} /T /F`,
450
- ], {
451
- stdio: "ignore",
452
- windowsHide: true,
453
- });
454
- killer.once("error", () => finish(false));
455
- killer.once("exit", (code) => finish(code === 0));
456
- }
457
- catch {
458
- finish(false);
459
- return;
460
- }
461
- });
462
- }
463
- function removeAutoUpdateLockDirectory() {
464
- try {
465
- unlinkSync(AUTO_UPDATE_LOCK_OWNER_FILE);
466
- }
467
- catch (error) {
468
- const code = error.code ?? "";
469
- if (code !== "ENOENT") {
470
- log.debug("Failed to remove auto-update lock owner", {
471
- error: error instanceof Error ? error.message : String(error),
472
- });
473
- }
474
- }
475
- let lastError = null;
476
- for (let attempt = 0; attempt < 4; attempt++) {
477
- try {
478
- rmdirSync(AUTO_UPDATE_LOCK_DIR);
479
- return;
480
- }
481
- catch (error) {
482
- const code = error.code ?? "";
483
- lastError = error;
484
- if (!RETRYABLE_WRITE_ERRORS.has(code) || attempt >= 3) {
485
- break;
486
- }
487
- sleepSync(15 * (2 ** attempt));
488
- }
489
- }
490
- if (lastError) {
491
- log.debug("Failed to remove auto-update lock", { error: lastError.message });
492
- }
493
- }
494
- function isAutoUpdateLockStale(now = Date.now()) {
495
- try {
496
- const stats = statSync(AUTO_UPDATE_LOCK_DIR);
497
- const ownerPid = readAutoUpdateLockOwnerPid();
498
- if (ownerPid !== null) {
499
- return !isProcessAlive(ownerPid);
500
- }
501
- return now - stats.mtimeMs > AUTO_UPDATE_LOCK_STALE_MS;
502
- }
503
- catch {
504
- return true;
505
- }
506
- }
507
- function readAutoUpdateLockOwnerPid() {
508
- try {
509
- const parsed = JSON.parse(readFileSync(AUTO_UPDATE_LOCK_OWNER_FILE, "utf8"));
510
- if (!parsed || typeof parsed !== "object" || !("pid" in parsed)) {
511
- return null;
512
- }
513
- const pid = parsed.pid;
514
- return typeof pid === "number" && Number.isInteger(pid) && pid > 0
515
- ? pid
516
- : null;
517
- }
518
- catch {
519
- return null;
520
- }
521
- }
522
- function isProcessAlive(pid) {
523
- try {
524
- process.kill(pid, 0);
525
- return true;
526
- }
527
- catch (error) {
528
- const code = error && typeof error === "object" && "code" in error ? error.code : null;
529
- return code === "EPERM";
530
- }
531
- }
532
- function writeAutoUpdateLockOwner() {
533
- writeFileSync(AUTO_UPDATE_LOCK_OWNER_FILE, `${JSON.stringify({
534
- pid: process.pid,
535
- startedAt: new Date().toISOString(),
536
- })}\n`, { encoding: "utf8", mode: 0o600 });
537
- try {
538
- chmodSync(AUTO_UPDATE_LOCK_OWNER_FILE, 0o600);
539
- }
540
- catch {
541
- // Best-effort only; permissions vary by platform and filesystem.
542
- }
543
- }
544
- function acquireAutoUpdateLock() {
545
- try {
546
- if (!existsSync(CACHE_DIR)) {
547
- mkdirSync(CACHE_DIR, { recursive: true });
548
- }
549
- }
550
- catch (error) {
551
- log.debug("Failed to prepare auto-update lock directory", {
552
- error: error instanceof Error ? error.message : String(error),
553
- });
554
- return null;
555
- }
556
- for (let attempt = 0; attempt < 2; attempt++) {
557
- try {
558
- mkdirSync(AUTO_UPDATE_LOCK_DIR);
559
- }
560
- catch (error) {
561
- const code = error.code ?? "";
562
- if (code === "EEXIST" && isAutoUpdateLockStale()) {
563
- removeAutoUpdateLockDirectory();
564
- continue;
565
- }
566
- if (code !== "EEXIST") {
567
- log.debug("Failed to acquire auto-update lock", {
568
- error: error instanceof Error ? error.message : String(error),
569
- });
570
- }
571
- return null;
572
- }
573
- try {
574
- writeAutoUpdateLockOwner();
575
- return removeAutoUpdateLockDirectory;
576
- }
577
- catch (error) {
578
- removeAutoUpdateLockDirectory();
579
- log.debug("Failed to write auto-update lock owner", {
580
- error: error instanceof Error ? error.message : String(error),
581
- });
582
- return null;
583
- }
584
- }
585
- return null;
586
- }
587
- function notifyUpdateStart(callback, result) {
588
- if (!callback)
589
- return;
590
- try {
591
- callback(result);
592
- }
593
- catch (error) {
594
- log.debug("Auto-update start callback failed", {
595
- error: error instanceof Error ? error.message : String(error),
596
- });
597
- }
598
- }
599
- export async function checkForUpdates(force = false, fetchTimeoutMs = UPDATE_CHECK_TIMEOUT_MS) {
600
- const currentVersion = getCurrentVersion();
601
- const cache = loadCache();
602
- const now = Date.now();
603
- if (!force && cache && now - cache.lastCheck < CHECK_INTERVAL_MS) {
604
- const hasUpdate = cache.latestVersion ? compareVersions(currentVersion, cache.latestVersion) > 0 : false;
605
- return {
606
- hasUpdate,
607
- currentVersion,
608
- latestVersion: cache.latestVersion,
609
- updateCommand: `npm update -g ${PACKAGE_NAME}`,
610
- };
611
- }
612
- const latestVersion = await fetchLatestVersion(fetchTimeoutMs);
613
- await saveCache({
614
- lastCheck: now,
615
- latestVersion,
616
- currentVersion,
617
- });
618
- const hasUpdate = latestVersion ? compareVersions(currentVersion, latestVersion) > 0 : false;
619
- return {
620
- hasUpdate,
621
- currentVersion,
622
- latestVersion,
623
- updateCommand: `npm update -g ${PACKAGE_NAME}`,
624
- };
625
- }
626
- export async function autoUpdateIfAvailable(options = {}) {
627
- const env = options.env ?? process.env;
628
- const currentVersion = getCurrentVersion();
629
- const npmCommand = options.npmCommand ?? resolveNpmCommand(options.platform ?? process.platform);
630
- const skipped = (reason) => ({
631
- checked: false,
632
- updated: false,
633
- reason,
634
- exitCode: null,
635
- error: null,
636
- hasUpdate: false,
637
- currentVersion,
638
- latestVersion: null,
639
- updateCommand: `npm update -g ${PACKAGE_NAME}`,
640
- });
641
- if (!isAutoUpdateEnabled(env)) {
642
- return skipped("disabled");
643
- }
644
- if (!options.forceInstall &&
645
- !isUpdateablePackageInstall(options.packageRoot ?? getPackageRoot())) {
646
- return skipped("not-updateable-install");
647
- }
648
- const result = await checkForUpdates(options.forceCheck ?? false, options.fetchTimeoutMs);
649
- if (!result.hasUpdate || !result.latestVersion) {
650
- return {
651
- ...result,
652
- checked: true,
653
- updated: false,
654
- reason: "current",
655
- exitCode: null,
656
- error: null,
657
- };
658
- }
659
- const releaseLock = acquireAutoUpdateLock();
660
- if (!releaseLock) {
661
- return {
662
- ...result,
663
- checked: true,
664
- updated: false,
665
- reason: "already-running",
666
- exitCode: null,
667
- error: null,
668
- };
669
- }
670
- try {
671
- notifyUpdateStart(options.onUpdateStart, result);
672
- const updateResult = await runUpdateCommand({
673
- command: npmCommand,
674
- env,
675
- platform: options.platform ?? process.platform,
676
- timeoutMs: options.timeoutMs ?? AUTO_UPDATE_TIMEOUT_MS,
677
- });
678
- if (!updateResult.ok) {
679
- log.warn("Auto-update failed", { error: updateResult.error });
680
- return {
681
- ...result,
682
- checked: true,
683
- updated: false,
684
- reason: "update-failed",
685
- exitCode: updateResult.exitCode,
686
- error: updateResult.error,
687
- };
688
- }
689
- log.info(`Auto-updated ${PACKAGE_NAME} to v${result.latestVersion}`);
690
- return {
691
- ...result,
692
- checked: true,
693
- updated: true,
694
- reason: "updated",
695
- exitCode: updateResult.exitCode,
696
- error: null,
697
- };
698
- }
699
- finally {
700
- releaseLock();
701
- }
702
- }
703
- export async function checkAndNotify(showToast) {
704
- try {
705
- const result = await checkForUpdates();
706
- if (result.hasUpdate && result.latestVersion) {
707
- const message = `Update available: ${PACKAGE_NAME} v${result.latestVersion} (current: v${result.currentVersion})`;
708
- log.info(message);
709
- if (showToast) {
710
- await showToast(`Plugin update available: v${result.latestVersion}. Run: ${result.updateCommand}`, "info");
711
- }
712
- }
713
- }
714
- catch (error) {
715
- log.debug("Update check failed", { error: error.message });
716
- }
717
- }
718
- export function clearUpdateCache() {
719
- void enqueueUpdateCacheWrite(() => {
720
- try {
721
- if (existsSync(CACHE_FILE)) {
722
- writeCacheContents("{}");
723
- }
724
- }
725
- catch {
726
- // Ignore errors
727
- }
728
- });
729
- }
730
- //# sourceMappingURL=auto-update-checker.js.map