minara 0.2.6 → 0.2.7

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/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { createRequire } from 'node:module';
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
5
  import { setRawJson } from './formatters.js';
6
+ import { checkForUpdate } from './update-check.js';
6
7
  // Auth & Account
7
8
  import { loginCommand } from './commands/login.js';
8
9
  import { logoutCommand } from './commands/logout.js';
@@ -24,6 +25,8 @@ import { premiumCommand } from './commands/premium.js';
24
25
  import { configCommand } from './commands/config.js';
25
26
  const require = createRequire(import.meta.url);
26
27
  const { version } = require('../package.json');
28
+ // Fire update check early (non-blocking); result printed after command completes
29
+ const updateCheckPromise = checkForUpdate(version);
27
30
  const program = new Command();
28
31
  program
29
32
  .name('minara')
@@ -65,8 +68,14 @@ program.addCommand(configCommand);
65
68
  program.action(() => {
66
69
  program.outputHelp();
67
70
  });
68
- program.parseAsync(process.argv).catch((err) => {
71
+ program.parseAsync(process.argv)
72
+ .catch((err) => {
69
73
  const message = err instanceof Error ? err.message : String(err);
70
74
  console.error(chalk.red('Error:'), message);
71
75
  process.exit(1);
76
+ })
77
+ .finally(async () => {
78
+ const notice = await updateCheckPromise;
79
+ if (notice)
80
+ console.log(notice);
72
81
  });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Non-blocking update check. Returns a formatted notice string if a newer
3
+ * version is available on npm, or `null` if up-to-date / check skipped.
4
+ */
5
+ export declare function checkForUpdate(currentVersion: string): Promise<string | null>;
@@ -0,0 +1,77 @@
1
+ import { join } from 'node:path';
2
+ import { homedir } from 'node:os';
3
+ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
4
+ import chalk from 'chalk';
5
+ const PKG_NAME = 'minara';
6
+ const CHECK_INTERVAL_MS = 4 * 60 * 60 * 1000; // 4 hours
7
+ const CACHE_DIR = join(homedir(), '.minara');
8
+ const CACHE_FILE = join(CACHE_DIR, 'update-check.json');
9
+ const FETCH_TIMEOUT_MS = 3000;
10
+ function readCache() {
11
+ try {
12
+ return JSON.parse(readFileSync(CACHE_FILE, 'utf-8'));
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ function writeCache(data) {
19
+ try {
20
+ mkdirSync(CACHE_DIR, { recursive: true, mode: 0o700 });
21
+ writeFileSync(CACHE_FILE, JSON.stringify(data), { mode: 0o600 });
22
+ }
23
+ catch {
24
+ // best-effort
25
+ }
26
+ }
27
+ function isNewer(remote, local) {
28
+ const r = remote.split('.').map(Number);
29
+ const l = local.split('.').map(Number);
30
+ for (let i = 0; i < 3; i++) {
31
+ if ((r[i] ?? 0) > (l[i] ?? 0))
32
+ return true;
33
+ if ((r[i] ?? 0) < (l[i] ?? 0))
34
+ return false;
35
+ }
36
+ return false;
37
+ }
38
+ /**
39
+ * Non-blocking update check. Returns a formatted notice string if a newer
40
+ * version is available on npm, or `null` if up-to-date / check skipped.
41
+ */
42
+ export async function checkForUpdate(currentVersion) {
43
+ try {
44
+ // Use cache to avoid hitting npm on every invocation
45
+ const cached = readCache();
46
+ if (cached && Date.now() - cached.checkedAt < CHECK_INTERVAL_MS) {
47
+ return isNewer(cached.latest, currentVersion)
48
+ ? formatNotice(currentVersion, cached.latest)
49
+ : null;
50
+ }
51
+ const controller = new AbortController();
52
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
53
+ const res = await fetch(`https://registry.npmjs.org/${PKG_NAME}/latest`, {
54
+ signal: controller.signal,
55
+ headers: { Accept: 'application/json' },
56
+ });
57
+ clearTimeout(timer);
58
+ if (!res.ok)
59
+ return null;
60
+ const { version: latest } = (await res.json());
61
+ if (!latest)
62
+ return null;
63
+ writeCache({ latest, checkedAt: Date.now() });
64
+ return isNewer(latest, currentVersion)
65
+ ? formatNotice(currentVersion, latest)
66
+ : null;
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ function formatNotice(current, latest) {
73
+ const line = ` Update available: ${chalk.dim(current)} → ${chalk.green.bold(latest)}`;
74
+ const cmd = ` Run ${chalk.cyan('npm i -g minara')} to update`;
75
+ const border = chalk.yellow('─'.repeat(48));
76
+ return `\n${border}\n${line}\n${cmd}\n${border}`;
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "minara",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "CLI client for Minara.ai — login, trade, deposit/withdraw, chat and more from your terminal.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",