exodus-cli 1.1.0 → 1.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/dist/index.js +192 -54
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32203,7 +32203,7 @@ function useColor() {
|
|
|
32203
32203
|
// node_modules/commander/index.js
|
|
32204
32204
|
var program = new Command;
|
|
32205
32205
|
// package.json
|
|
32206
|
-
var version = "1.
|
|
32206
|
+
var version = "1.2.0";
|
|
32207
32207
|
|
|
32208
32208
|
// src/lib/open-app.ts
|
|
32209
32209
|
import { join } from "path";
|
|
@@ -41605,6 +41605,133 @@ async function listInstalledSkills(skillsDir) {
|
|
|
41605
41605
|
return Object.entries(lock.skills).map(([slug, info]) => ({ slug, ...info }));
|
|
41606
41606
|
}
|
|
41607
41607
|
|
|
41608
|
+
// src/lib/update-notifier.ts
|
|
41609
|
+
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
41610
|
+
import { dirname, join as join5 } from "path";
|
|
41611
|
+
|
|
41612
|
+
// src/lib/dist-channel.ts
|
|
41613
|
+
var DIST_CHANNEL = "npm";
|
|
41614
|
+
|
|
41615
|
+
// src/lib/updater.ts
|
|
41616
|
+
var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
41617
|
+
var DEFAULT_GITHUB_API = "https://api.github.com/repos/exodus-ai-org/exodus-cli";
|
|
41618
|
+
function getCurrentVersion() {
|
|
41619
|
+
return version;
|
|
41620
|
+
}
|
|
41621
|
+
function isNewerVersion(current, latest) {
|
|
41622
|
+
const c = current.split(".").map(Number);
|
|
41623
|
+
const l = latest.split(".").map(Number);
|
|
41624
|
+
for (let i = 0;i < 3; i++) {
|
|
41625
|
+
const cv = c[i] ?? 0;
|
|
41626
|
+
const lv = l[i] ?? 0;
|
|
41627
|
+
if (lv > cv)
|
|
41628
|
+
return true;
|
|
41629
|
+
if (lv < cv)
|
|
41630
|
+
return false;
|
|
41631
|
+
}
|
|
41632
|
+
return false;
|
|
41633
|
+
}
|
|
41634
|
+
async function getLatestNpmVersion(baseUrl = DEFAULT_NPM_REGISTRY) {
|
|
41635
|
+
const res = await fetch(`${baseUrl}/exodus-cli/latest`);
|
|
41636
|
+
if (!res.ok)
|
|
41637
|
+
throw new Error(`npm registry lookup failed: ${res.status}`);
|
|
41638
|
+
const body = await res.json();
|
|
41639
|
+
return body.version;
|
|
41640
|
+
}
|
|
41641
|
+
async function getLatestRelease(baseUrl = DEFAULT_GITHUB_API) {
|
|
41642
|
+
const res = await fetch(`${baseUrl}/releases/latest`);
|
|
41643
|
+
if (!res.ok)
|
|
41644
|
+
throw new Error(`GitHub releases lookup failed: ${res.status}`);
|
|
41645
|
+
return await res.json();
|
|
41646
|
+
}
|
|
41647
|
+
async function getLatestVersion() {
|
|
41648
|
+
return DIST_CHANNEL === "npm" ? await getLatestNpmVersion() : (await getLatestRelease()).tag_name.replace(/^v/, "");
|
|
41649
|
+
}
|
|
41650
|
+
async function checkForUpdate() {
|
|
41651
|
+
const current = getCurrentVersion();
|
|
41652
|
+
const latest = await getLatestVersion();
|
|
41653
|
+
if (!isNewerVersion(current, latest)) {
|
|
41654
|
+
return { updateAvailable: false, current };
|
|
41655
|
+
}
|
|
41656
|
+
return { updateAvailable: true, current, latest };
|
|
41657
|
+
}
|
|
41658
|
+
|
|
41659
|
+
// src/lib/update-notifier.ts
|
|
41660
|
+
var CACHE_FILE = "update-check.json";
|
|
41661
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
41662
|
+
var UPDATE_CHECK_ARG = "__update-check";
|
|
41663
|
+
function getUpdateCachePath(exodusHome = getExodusHome()) {
|
|
41664
|
+
return join5(exodusHome, CACHE_FILE);
|
|
41665
|
+
}
|
|
41666
|
+
async function readUpdateCache(exodusHome = getExodusHome()) {
|
|
41667
|
+
try {
|
|
41668
|
+
const parsed = JSON.parse(await readFile2(getUpdateCachePath(exodusHome), "utf-8"));
|
|
41669
|
+
if (typeof parsed?.checkedAt !== "number" || typeof parsed?.latest !== "string")
|
|
41670
|
+
return null;
|
|
41671
|
+
return { checkedAt: parsed.checkedAt, latest: parsed.latest };
|
|
41672
|
+
} catch {
|
|
41673
|
+
return null;
|
|
41674
|
+
}
|
|
41675
|
+
}
|
|
41676
|
+
async function writeUpdateCache(cache3, exodusHome = getExodusHome()) {
|
|
41677
|
+
const path2 = getUpdateCachePath(exodusHome);
|
|
41678
|
+
await mkdir2(dirname(path2), { recursive: true });
|
|
41679
|
+
await writeFile2(path2, JSON.stringify(cache3));
|
|
41680
|
+
}
|
|
41681
|
+
function isCacheStale(cache3, now2 = Date.now()) {
|
|
41682
|
+
if (!cache3)
|
|
41683
|
+
return true;
|
|
41684
|
+
const age = now2 - cache3.checkedAt;
|
|
41685
|
+
return age < 0 || age >= CHECK_INTERVAL_MS;
|
|
41686
|
+
}
|
|
41687
|
+
function getUpdateNotice(current, cache3) {
|
|
41688
|
+
if (!cache3 || !isNewerVersion(current, cache3.latest))
|
|
41689
|
+
return null;
|
|
41690
|
+
return `Update available: ${current} \u2192 ${cache3.latest}. Run: exodus update`;
|
|
41691
|
+
}
|
|
41692
|
+
function formatUpdateBadge(current, cache3) {
|
|
41693
|
+
if (!cache3 || !isNewerVersion(current, cache3.latest))
|
|
41694
|
+
return null;
|
|
41695
|
+
return `Update available: ${cache3.latest}`;
|
|
41696
|
+
}
|
|
41697
|
+
async function getUpdateBadge(exodusHome = getExodusHome(), current = getCurrentVersion()) {
|
|
41698
|
+
return formatUpdateBadge(current, await readUpdateCache(exodusHome));
|
|
41699
|
+
}
|
|
41700
|
+
function buildRefreshCommand(argv = process.argv, execPath = process.execPath) {
|
|
41701
|
+
const entry = argv[1];
|
|
41702
|
+
if (!entry || entry === execPath)
|
|
41703
|
+
return [execPath, UPDATE_CHECK_ARG];
|
|
41704
|
+
return [execPath, entry, UPDATE_CHECK_ARG];
|
|
41705
|
+
}
|
|
41706
|
+
async function refreshUpdateCache(exodusHome = getExodusHome(), fetchLatest = getLatestVersion, now2 = Date.now) {
|
|
41707
|
+
try {
|
|
41708
|
+
const latest = await fetchLatest();
|
|
41709
|
+
await writeUpdateCache({ checkedAt: now2(), latest }, exodusHome);
|
|
41710
|
+
} catch {}
|
|
41711
|
+
}
|
|
41712
|
+
function spawnBackgroundRefresh() {
|
|
41713
|
+
const child = Bun.spawn({
|
|
41714
|
+
cmd: buildRefreshCommand(),
|
|
41715
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
41716
|
+
});
|
|
41717
|
+
child.unref();
|
|
41718
|
+
}
|
|
41719
|
+
async function prepareUpdateNotice(opts = {}) {
|
|
41720
|
+
const {
|
|
41721
|
+
exodusHome = getExodusHome(),
|
|
41722
|
+
current = getCurrentVersion(),
|
|
41723
|
+
now: now2 = Date.now(),
|
|
41724
|
+
spawnRefresh = spawnBackgroundRefresh
|
|
41725
|
+
} = opts;
|
|
41726
|
+
const cache3 = await readUpdateCache(exodusHome);
|
|
41727
|
+
if (isCacheStale(cache3, now2)) {
|
|
41728
|
+
try {
|
|
41729
|
+
spawnRefresh();
|
|
41730
|
+
} catch {}
|
|
41731
|
+
}
|
|
41732
|
+
return getUpdateNotice(current, cache3);
|
|
41733
|
+
}
|
|
41734
|
+
|
|
41608
41735
|
// src/tui/app.tsx
|
|
41609
41736
|
var import_react41 = __toESM(require_react(), 1);
|
|
41610
41737
|
|
|
@@ -42368,7 +42495,10 @@ function InstalledScreen({ skillsDir = getSkillsDir() }) {
|
|
|
42368
42495
|
|
|
42369
42496
|
// src/tui/app.tsx
|
|
42370
42497
|
var jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
|
|
42371
|
-
function App2({
|
|
42498
|
+
function App2({
|
|
42499
|
+
skillsDir = getSkillsDir(),
|
|
42500
|
+
updateNotice = null
|
|
42501
|
+
}) {
|
|
42372
42502
|
const [tab2, setTab] = import_react41.useState("discover");
|
|
42373
42503
|
const [selected, setSelected] = import_react41.useState(null);
|
|
42374
42504
|
const { exit } = use_app_default();
|
|
@@ -42401,11 +42531,29 @@ function App2({ skillsDir = getSkillsDir() }) {
|
|
|
42401
42531
|
}, undefined, false, undefined, this)
|
|
42402
42532
|
]
|
|
42403
42533
|
}, undefined, true, undefined, this),
|
|
42404
|
-
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(
|
|
42405
|
-
|
|
42406
|
-
|
|
42407
|
-
|
|
42408
|
-
|
|
42534
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
42535
|
+
children: [
|
|
42536
|
+
updateNotice ? /* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
42537
|
+
marginRight: 1,
|
|
42538
|
+
children: [
|
|
42539
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
42540
|
+
color: "yellow",
|
|
42541
|
+
wrap: "truncate-end",
|
|
42542
|
+
children: updateNotice
|
|
42543
|
+
}, undefined, false, undefined, this),
|
|
42544
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
42545
|
+
dimColor: true,
|
|
42546
|
+
children: " \xB7"
|
|
42547
|
+
}, undefined, false, undefined, this)
|
|
42548
|
+
]
|
|
42549
|
+
}, undefined, true, undefined, this) : null,
|
|
42550
|
+
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Text, {
|
|
42551
|
+
dimColor: true,
|
|
42552
|
+
italic: true,
|
|
42553
|
+
children: "Tab to switch"
|
|
42554
|
+
}, undefined, false, undefined, this)
|
|
42555
|
+
]
|
|
42556
|
+
}, undefined, true, undefined, this)
|
|
42409
42557
|
]
|
|
42410
42558
|
}, undefined, true, undefined, this),
|
|
42411
42559
|
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Rule, {}, undefined, false, undefined, this),
|
|
@@ -42505,8 +42653,11 @@ async function runSkillsUninstall(slug, opts = {}) {
|
|
|
42505
42653
|
}
|
|
42506
42654
|
}
|
|
42507
42655
|
function registerSkillsCommand(program2) {
|
|
42508
|
-
const skills = program2.command("skills").description("Browse and manage skills.sh skills").action(() => {
|
|
42509
|
-
|
|
42656
|
+
const skills = program2.command("skills").description("Browse and manage skills.sh skills").action(async () => {
|
|
42657
|
+
const updateNotice = await getUpdateBadge();
|
|
42658
|
+
render_default(/* @__PURE__ */ jsx_dev_runtime9.jsxDEV(App2, {
|
|
42659
|
+
updateNotice
|
|
42660
|
+
}, undefined, false, undefined, this), { alternateScreen: true });
|
|
42510
42661
|
});
|
|
42511
42662
|
skills.command("search <query>").description("Search skills.sh").option("--json", "output JSON instead of a formatted list").action(async (query, opts) => {
|
|
42512
42663
|
await runSkillsSearch(query, opts);
|
|
@@ -42523,50 +42674,6 @@ function registerSkillsCommand(program2) {
|
|
|
42523
42674
|
return skills;
|
|
42524
42675
|
}
|
|
42525
42676
|
|
|
42526
|
-
// src/lib/dist-channel.ts
|
|
42527
|
-
var DIST_CHANNEL = "npm";
|
|
42528
|
-
|
|
42529
|
-
// src/lib/updater.ts
|
|
42530
|
-
var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
42531
|
-
var DEFAULT_GITHUB_API = "https://api.github.com/repos/exodus-ai-org/exodus-cli";
|
|
42532
|
-
function getCurrentVersion() {
|
|
42533
|
-
return version;
|
|
42534
|
-
}
|
|
42535
|
-
function isNewerVersion(current, latest) {
|
|
42536
|
-
const c = current.split(".").map(Number);
|
|
42537
|
-
const l = latest.split(".").map(Number);
|
|
42538
|
-
for (let i = 0;i < 3; i++) {
|
|
42539
|
-
const cv = c[i] ?? 0;
|
|
42540
|
-
const lv = l[i] ?? 0;
|
|
42541
|
-
if (lv > cv)
|
|
42542
|
-
return true;
|
|
42543
|
-
if (lv < cv)
|
|
42544
|
-
return false;
|
|
42545
|
-
}
|
|
42546
|
-
return false;
|
|
42547
|
-
}
|
|
42548
|
-
async function getLatestNpmVersion(baseUrl = DEFAULT_NPM_REGISTRY) {
|
|
42549
|
-
const res = await fetch(`${baseUrl}/exodus-cli/latest`);
|
|
42550
|
-
if (!res.ok)
|
|
42551
|
-
throw new Error(`npm registry lookup failed: ${res.status}`);
|
|
42552
|
-
const body = await res.json();
|
|
42553
|
-
return body.version;
|
|
42554
|
-
}
|
|
42555
|
-
async function getLatestRelease(baseUrl = DEFAULT_GITHUB_API) {
|
|
42556
|
-
const res = await fetch(`${baseUrl}/releases/latest`);
|
|
42557
|
-
if (!res.ok)
|
|
42558
|
-
throw new Error(`GitHub releases lookup failed: ${res.status}`);
|
|
42559
|
-
return await res.json();
|
|
42560
|
-
}
|
|
42561
|
-
async function checkForUpdate() {
|
|
42562
|
-
const current = getCurrentVersion();
|
|
42563
|
-
const latest = DIST_CHANNEL === "npm" ? await getLatestNpmVersion() : (await getLatestRelease()).tag_name.replace(/^v/, "");
|
|
42564
|
-
if (!isNewerVersion(current, latest)) {
|
|
42565
|
-
return { updateAvailable: false, current };
|
|
42566
|
-
}
|
|
42567
|
-
return { updateAvailable: true, current, latest };
|
|
42568
|
-
}
|
|
42569
|
-
|
|
42570
42677
|
// src/commands/update.ts
|
|
42571
42678
|
async function runUpdate(opts = {}) {
|
|
42572
42679
|
try {
|
|
@@ -42596,6 +42703,7 @@ function registerUpdateCommand(program2) {
|
|
|
42596
42703
|
}
|
|
42597
42704
|
|
|
42598
42705
|
// src/cli.ts
|
|
42706
|
+
var REFRESH_TIMEOUT_MS = 1e4;
|
|
42599
42707
|
function buildProgram() {
|
|
42600
42708
|
const program2 = new Command;
|
|
42601
42709
|
program2.name("exodus").description("exodus-cli \u2014 launch Exodus, manage skills, and self-update").version(version);
|
|
@@ -42604,10 +42712,40 @@ function buildProgram() {
|
|
|
42604
42712
|
registerSkillsCommand(program2);
|
|
42605
42713
|
return program2;
|
|
42606
42714
|
}
|
|
42715
|
+
function wantsUpdateNotice(argv) {
|
|
42716
|
+
if (argv.includes(UPDATE_CHECK_ARG))
|
|
42717
|
+
return false;
|
|
42718
|
+
return argv[2] !== "update";
|
|
42719
|
+
}
|
|
42720
|
+
async function runCli(argv = process.argv, runtime = {}) {
|
|
42721
|
+
const {
|
|
42722
|
+
parse = (a) => buildProgram().parseAsync(a),
|
|
42723
|
+
prepareNotice = prepareUpdateNotice,
|
|
42724
|
+
refreshCache = refreshUpdateCache,
|
|
42725
|
+
writeNotice = (message) => console.error(message),
|
|
42726
|
+
exit = () => process.exit(0),
|
|
42727
|
+
timeoutMs = REFRESH_TIMEOUT_MS
|
|
42728
|
+
} = runtime;
|
|
42729
|
+
if (argv.includes(UPDATE_CHECK_ARG)) {
|
|
42730
|
+
const deadline = new Promise((resolve2) => {
|
|
42731
|
+
setTimeout(resolve2, timeoutMs).unref();
|
|
42732
|
+
});
|
|
42733
|
+
await Promise.race([refreshCache(), deadline.then(exit)]);
|
|
42734
|
+
return;
|
|
42735
|
+
}
|
|
42736
|
+
const pending = wantsUpdateNotice(argv) ? prepareNotice().catch(() => null) : Promise.resolve(null);
|
|
42737
|
+
try {
|
|
42738
|
+
await parse(argv);
|
|
42739
|
+
} finally {
|
|
42740
|
+
const message = await pending;
|
|
42741
|
+
if (message)
|
|
42742
|
+
writeNotice(message);
|
|
42743
|
+
}
|
|
42744
|
+
}
|
|
42607
42745
|
|
|
42608
42746
|
// index.ts
|
|
42609
42747
|
try {
|
|
42610
|
-
await
|
|
42748
|
+
await runCli(process.argv);
|
|
42611
42749
|
} catch (err) {
|
|
42612
42750
|
console.error(err instanceof Error ? err.message : String(err));
|
|
42613
42751
|
process.exitCode = 1;
|