tokentracker-cli 0.87.3 → 0.87.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.
- package/dashboard/dist/assets/AchievementBadge-_BbqyV4s.js +1 -0
- package/dashboard/dist/assets/{AchievementsPage-SaivmNs0.js → AchievementsPage-DlXdQMuk.js} +2 -2
- package/dashboard/dist/assets/{AchievementsSection-DhS-6gDl.js → AchievementsSection-BAL23Qum.js} +1 -1
- package/dashboard/dist/assets/{BadgeDetailModal-BfCesQLf.js → BadgeDetailModal-D5VYBn1e.js} +1 -1
- package/dashboard/dist/assets/{Card-Cjxl-RbP.js → Card-BCAAH2Tv.js} +1 -1
- package/dashboard/dist/assets/{ClawdAnimated-CErdixw_.js → ClawdAnimated-BaeJ4goq.js} +1 -1
- package/dashboard/dist/assets/{CommandPalette-MpC6EdTx.js → CommandPalette-DaBo0N_t.js} +1 -1
- package/dashboard/dist/assets/{CommunityStatsModal-C27kiCWg.js → CommunityStatsModal-DtnbqllK.js} +1 -1
- package/dashboard/dist/assets/{ConfirmModal-BzHs6qGZ.js → ConfirmModal-BdIbatZd.js} +1 -1
- package/dashboard/dist/assets/{Controls-DJEylji5.js → Controls-CtlnwG2h.js} +1 -1
- package/dashboard/dist/assets/DashboardPage-B7YSxJXW.js +1 -0
- package/dashboard/dist/assets/{DevicePage-DS8_oq1n.js → DevicePage-Y1QufKqx.js} +1 -1
- package/dashboard/dist/assets/{DialogClose-6TytC4Cj.js → DialogClose-BA6Fr6X7.js} +1 -1
- package/dashboard/dist/assets/DialogDescription-JjVfYyrp.js +1 -0
- package/dashboard/dist/assets/DialogTitle-CQlYwz-I.js +1 -0
- package/dashboard/dist/assets/{FadeIn-BzTGgpq_.js → FadeIn-C7oxsfI-.js} +1 -1
- package/dashboard/dist/assets/{HeaderGithubStar-CKSGB-Lq.js → HeaderGithubStar-5eKhC60J.js} +1 -1
- package/dashboard/dist/assets/{HoverTooltip-Ds-FyYmY.js → HoverTooltip-Tf9XsZ6G.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-DCWqmmXM.js → IpCheckPage-DEK7d2P9.js} +1 -1
- package/dashboard/dist/assets/{LandingPage-B57cM3zn.js → LandingPage-Cev8vQ3V.js} +2 -2
- package/dashboard/dist/assets/{LeaderboardAvatar-CYi8ENUq.js → LeaderboardAvatar-BP8r8s_o.js} +1 -1
- package/dashboard/dist/assets/LeaderboardPage-CFinKL9O.js +2 -0
- package/dashboard/dist/assets/{LeaderboardProfileModal-BGc4myMi.js → LeaderboardProfileModal-DKSPH2_U.js} +4 -4
- package/dashboard/dist/assets/{LeaderboardProfilePage-BB5dtkaS.js → LeaderboardProfilePage-DNSIoOdU.js} +3 -3
- package/dashboard/dist/assets/{LimitsPage-DofmgnvS.js → LimitsPage-DDljQnW7.js} +4 -4
- package/dashboard/dist/assets/{LocalOnlyNotice-CsLVVopf.js → LocalOnlyNotice-BuNHRmPw.js} +1 -1
- package/dashboard/dist/assets/{LoginCard-vC7vbKwK.js → LoginCard-Dq5-__UO.js} +1 -1
- package/dashboard/dist/assets/{LoginModal-BDKHs5ZP.js → LoginModal-BWuDhVTL.js} +1 -1
- package/dashboard/dist/assets/{LoginPage-Bb9LKA69.js → LoginPage-Dwb39YqH.js} +1 -1
- package/dashboard/dist/assets/{PetPage-7LGU7zwk.js → PetPage-BcvAOVH2.js} +1 -1
- package/dashboard/dist/assets/PopoverPopup-CnywL4jN.js +1 -0
- package/dashboard/dist/assets/{ProviderIcon-CBhScwLZ.js → ProviderIcon-DAn58wfZ.js} +1 -1
- package/dashboard/dist/assets/{ResetPasswordPage-DRWSTsTW.js → ResetPasswordPage-B-iZ9m8Z.js} +1 -1
- package/dashboard/dist/assets/{SegmentedControl-DGeMH2p8.js → SegmentedControl-DUlvUP02.js} +1 -1
- package/dashboard/dist/assets/{Select-BQOi6gWt.js → Select-BbVO0yyC.js} +1 -1
- package/dashboard/dist/assets/SelectItemText-BCo4iRHj.js +1 -0
- package/dashboard/dist/assets/{ServiceStatusPage-CSwBKd-J.js → ServiceStatusPage-Bf65rMHS.js} +1 -1
- package/dashboard/dist/assets/{SessionsPage-DqtNnt6J.js → SessionsPage-D2QWuLy9.js} +2 -2
- package/dashboard/dist/assets/SettingsPage-BtlZ7v0t.js +1 -0
- package/dashboard/dist/assets/SkillsPage-D7CXkuxF.js +1 -0
- package/dashboard/dist/assets/{TokenGalaxy-DnUDoJJZ.js → TokenGalaxy-B1VqfzOB.js} +1 -1
- package/dashboard/dist/assets/ToolbarRootContext-DlRA_RFX.js +1 -0
- package/dashboard/dist/assets/{TrendMonitor-BFvROIwx.js → TrendMonitor-D945Vzv_.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-zHv1cbWR.js → WidgetsPage-CZLhBVQL.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-CRtyzIB9.js → WrappedPage-Gf15Ax3y.js} +1 -1
- package/dashboard/dist/assets/__vite-browser-external-CRYifSM4.css +1 -0
- package/dashboard/dist/assets/{__vite-browser-external-RQ7lZFvr.js → __vite-browser-external-_-wIz90P.js} +11 -4
- package/dashboard/dist/assets/{agent-logos-BNkfzMFo.js → agent-logos-Ccd-gCmY.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-Bk4cPgo2.js → arrow-up-right-DksoZ7Fm.js} +1 -1
- package/dashboard/dist/assets/{check-CliWbD81.js → check-CFyujViz.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-Cm3fepaG.js → chevron-right-D2Y9ycoK.js} +1 -1
- package/dashboard/dist/assets/{copy-C10Ij0y6.js → copy-CvzVu4Jv.js} +1 -1
- package/dashboard/dist/assets/{download-B33Otf6v.js → download-M9hdGe0X.js} +1 -1
- package/dashboard/dist/assets/{external-link-CIFlqTbQ.js → external-link-BrvgYr3H.js} +1 -1
- package/dashboard/dist/assets/{flame-D9HUvqS6.js → flame-CanCCWfM.js} +1 -1
- package/dashboard/dist/assets/{format-tokens-CHDafmHO.js → format-tokens-D-x5NM5s.js} +1 -1
- package/dashboard/dist/assets/{icons-DvNfSar6.js → icons-iDxUXUbD.js} +1 -1
- package/dashboard/dist/assets/{index-CA_EbNuG.js → index-BPe3pmGu.js} +1 -1
- package/dashboard/dist/assets/{index-Bc5ZBKpe.js → index-CDK-qlvv.js} +1 -1
- package/dashboard/dist/assets/index-DhgQVkQR.js +9 -0
- package/dashboard/dist/assets/{info-DPC10oQ_.js → info-CS19GYkG.js} +1 -1
- package/dashboard/dist/assets/{limits-providers-C0Pz6mbN.js → limits-providers-Cep8gK1J.js} +1 -1
- package/dashboard/dist/assets/{link-2-WzNaAMth.js → link-2-_GqbzcZy.js} +1 -1
- package/dashboard/dist/assets/{loader-circle-C6xlopLF.js → loader-circle-DQlJKeCp.js} +1 -1
- package/dashboard/dist/assets/{maximize-2-0KiBFLqc.js → maximize-2-AaA61WoH.js} +1 -1
- package/dashboard/dist/assets/modifiers.esm-DgAD_X3C.js +1 -0
- package/dashboard/dist/assets/module-Ci-Lrj0I.js +2 -0
- package/dashboard/dist/assets/monitor-smartphone-C-KIKlP-.js +1 -0
- package/dashboard/dist/assets/provider-display-BWK3HqpN.js +42 -0
- package/dashboard/dist/assets/react-BGB0fHad.js +1 -0
- package/dashboard/dist/assets/{search-DcIhgvPK.js → search-BhQx4B4T.js} +1 -1
- package/dashboard/dist/assets/skills-api-BtsImOWQ.js +1 -0
- package/dashboard/dist/assets/sortable.esm-ew4S8Y1L.js +5 -0
- package/dashboard/dist/assets/store-OBiS6gfr.js +1 -0
- package/dashboard/dist/assets/{terminal-BrKrjIwy.js → terminal-GvWRPCY9.js} +1 -1
- package/dashboard/dist/assets/{trash-2-D-Z1EH3A.js → trash-2-COv_kp05.js} +1 -1
- package/dashboard/dist/assets/{use-community-stats-BpeauqPm.js → use-community-stats-COxOg9PE.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-DgfcukGo.js → use-limits-display-prefs-wf8pf1cF.js} +1 -1
- package/dashboard/dist/assets/use-ordered-list-Dw-kLFB1.js +1 -0
- package/dashboard/dist/assets/use-reduced-motion-B3wPPJY8.js +1 -0
- package/dashboard/dist/assets/{use-session-efficiency-pref-BQIz2bb3.js → use-session-efficiency-pref-D9X2CzAz.js} +1 -1
- package/dashboard/dist/assets/{use-transform-0oOtot3w.js → use-transform-BgfBM2dC.js} +1 -1
- package/dashboard/dist/assets/{use-usage-limits-CIPhW6GX.js → use-usage-limits-CrHu9ZJi.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-D-HSApxR.js → useCurrency-CmI0tWeH.js} +1 -1
- package/dashboard/dist/assets/useScrollLock-BtUfInbu.js +1 -0
- package/dashboard/dist/assets/{useTokenFormat-DlmxtsxU.js → useTokenFormat-DAHyFBMr.js} +1 -1
- package/dashboard/dist/assets/zap-C9NzWrn0.js +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist/ip-check.html +2 -2
- package/dashboard/dist/leaderboard.html +2 -2
- package/dashboard/dist/share.html +2 -2
- package/package.json +1 -1
- package/src/lib/codex-token-refresh.js +35 -7
- package/src/lib/local-api.js +1 -1
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/skills-manager.js +170 -7
- package/src/lib/usage-limits.js +39 -28
- package/dashboard/dist/assets/AchievementBadge--BdQsk7Z.js +0 -1
- package/dashboard/dist/assets/DashboardPage-BmrvChmn.js +0 -1
- package/dashboard/dist/assets/DialogDescription-BoEv861o.js +0 -1
- package/dashboard/dist/assets/DialogTitle-DpOXGzsp.js +0 -1
- package/dashboard/dist/assets/LeaderboardPage-DfL1iYB4.js +0 -2
- package/dashboard/dist/assets/PopoverPopup-DRzlyb01.js +0 -1
- package/dashboard/dist/assets/SelectItemText-BXpgzRHS.js +0 -1
- package/dashboard/dist/assets/SettingsPage-C9Bz2SMu.js +0 -1
- package/dashboard/dist/assets/SkillsPage-DrZdvGMd.js +0 -1
- package/dashboard/dist/assets/ToolbarRootContext-D9L4QmqU.js +0 -1
- package/dashboard/dist/assets/__vite-browser-external-CzQk3FUc.css +0 -1
- package/dashboard/dist/assets/index-DjOuhnCT.js +0 -9
- package/dashboard/dist/assets/module-Bah3ijPg.js +0 -2
- package/dashboard/dist/assets/provider-display-BPM_UujC.js +0 -42
- package/dashboard/dist/assets/react-BvxvY3fZ.js +0 -1
- package/dashboard/dist/assets/skills-api-Nx7WQwKb.js +0 -1
- package/dashboard/dist/assets/store-uw9hVnuM.js +0 -1
- package/dashboard/dist/assets/use-ordered-list-CSJMavMY.js +0 -5
- package/dashboard/dist/assets/use-reduced-motion-BZLtq0n-.js +0 -1
- package/dashboard/dist/assets/useScrollLock-ydGaZTyX.js +0 -1
- package/dashboard/dist/assets/zap-CrW1Qm1b.js +0 -1
|
@@ -14,28 +14,63 @@ const DEFAULT_REPOS = [
|
|
|
14
14
|
|
|
15
15
|
const TARGETS = {
|
|
16
16
|
claude: { id: "claude", label: "Claude", dir: () => path.join(os.homedir(), ".claude", "skills") },
|
|
17
|
-
codex: { id: "codex", label: "Codex", dir: () => path.join(
|
|
17
|
+
codex: { id: "codex", label: "Codex", dir: () => path.join(resolveCodexHome(), "skills") },
|
|
18
18
|
grok: { id: "grok", label: "Grok", dir: () => path.join(resolveGrokHome(process.env), "skills") },
|
|
19
19
|
antigravity: { id: "antigravity", label: "Antigravity", dirs: () => resolveAntigravitySkillDirs(process.env) },
|
|
20
20
|
gemini: { id: "gemini", label: "Gemini", dir: () => path.join(os.homedir(), ".gemini", "skills") },
|
|
21
21
|
opencode: { id: "opencode", label: "OpenCode", dir: () => path.join(os.homedir(), ".config", "opencode", "skills") },
|
|
22
|
+
openclaw: { id: "openclaw", label: "OpenClaw", dir: resolveOpenClawSkillsDir },
|
|
22
23
|
hermes: { id: "hermes", label: "Hermes", dir: () => path.join(os.homedir(), ".hermes", "skills") },
|
|
24
|
+
// ZCode currently exposes skills through its plugin cache rather than a
|
|
25
|
+
// documented user-writable skills directory. Surface it in the inventory
|
|
26
|
+
// and filters, but never offer sync/delete operations against the cache.
|
|
27
|
+
zcode: { id: "zcode", label: "ZCode", manageable: false },
|
|
23
28
|
agents: { id: "agents", label: "Agents", visible: false, dir: () => path.join(os.homedir(), ".agents", "skills") },
|
|
24
29
|
};
|
|
25
30
|
|
|
31
|
+
function resolveCodexHome() {
|
|
32
|
+
return String(process.env.CODEX_HOME || "").trim() || path.join(os.homedir(), ".codex");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveZcodeHome() {
|
|
36
|
+
return String(process.env.ZCODE_HOME || "").trim() || path.join(os.homedir(), ".zcode");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolveOpenClawHome() {
|
|
40
|
+
return String(process.env.TOKENTRACKER_OPENCLAW_HOME || "").trim() || path.join(os.homedir(), ".openclaw");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// OpenClaw can point at an arbitrary active workspace. Only scan that one
|
|
44
|
+
// explicit workspace; recursively scanning ~/.openclaw would incorrectly
|
|
45
|
+
// import backup/config snapshots belonging to other devices.
|
|
46
|
+
function resolveOpenClawSkillsDir() {
|
|
47
|
+
const home = resolveOpenClawHome();
|
|
48
|
+
const override = String(process.env.TOKENTRACKER_OPENCLAW_WORKSPACE || "").trim();
|
|
49
|
+
let workspace = override;
|
|
50
|
+
if (!workspace) {
|
|
51
|
+
const config = readJson(path.join(home, "openclaw.json"), null);
|
|
52
|
+
workspace = String(config?.agents?.defaults?.workspace || "").trim();
|
|
53
|
+
}
|
|
54
|
+
if (!workspace) workspace = path.join(home, "workspace");
|
|
55
|
+
if (!path.isAbsolute(workspace)) workspace = path.resolve(home, workspace);
|
|
56
|
+
return path.join(workspace, "skills");
|
|
57
|
+
}
|
|
58
|
+
|
|
26
59
|
// Dual contract: a target exposes either dir() → string (single path) or
|
|
27
60
|
// dirs() → string[] (parallel-write to multiple paths, e.g. Antigravity which
|
|
28
61
|
// has separate user-skills dirs for the main app and the IDE). Consumers must
|
|
29
62
|
// route through these helpers so the single-path targets stay zero-overhead.
|
|
30
63
|
function targetDirs(target) {
|
|
64
|
+
if (!target || target.manageable === false) return [];
|
|
31
65
|
if (typeof target.dirs === "function") return target.dirs();
|
|
32
|
-
return [target.dir()];
|
|
66
|
+
if (typeof target.dir === "function") return [target.dir()];
|
|
67
|
+
return [];
|
|
33
68
|
}
|
|
34
69
|
|
|
35
70
|
// Used for surfacing one path in UI/local-api responses. For multi-dir targets
|
|
36
71
|
// this is the canonical "first" entry by convention (main app before IDE).
|
|
37
72
|
function targetPrimaryDir(target) {
|
|
38
|
-
return targetDirs(target)[0];
|
|
73
|
+
return targetDirs(target)[0] || null;
|
|
39
74
|
}
|
|
40
75
|
|
|
41
76
|
const FETCH_TIMEOUT_MS = 20_000;
|
|
@@ -203,6 +238,7 @@ function targetList() {
|
|
|
203
238
|
id: target.id,
|
|
204
239
|
label: target.label,
|
|
205
240
|
path: targetPrimaryDir(target),
|
|
241
|
+
manageable: target.manageable !== false,
|
|
206
242
|
}));
|
|
207
243
|
}
|
|
208
244
|
|
|
@@ -267,7 +303,7 @@ function findSkillMarker(dir) {
|
|
|
267
303
|
|
|
268
304
|
const MAX_LOCAL_SKILL_SCAN_DEPTH = 3;
|
|
269
305
|
|
|
270
|
-
function scanSkillDirectories(rootDir) {
|
|
306
|
+
function scanSkillDirectories(rootDir, { maxDepth = MAX_LOCAL_SKILL_SCAN_DEPTH } = {}) {
|
|
271
307
|
const found = [];
|
|
272
308
|
const walk = (dir, relDir = "", depth = 0) => {
|
|
273
309
|
let entries = [];
|
|
@@ -288,13 +324,136 @@ function scanSkillDirectories(rootDir) {
|
|
|
288
324
|
}
|
|
289
325
|
// Direct symlinked skills are accepted above, but symlinked group folders
|
|
290
326
|
// are not traversed so the scan stays within the target skills tree.
|
|
291
|
-
if (entry.isDirectory() && depth + 1 <
|
|
327
|
+
if (entry.isDirectory() && depth + 1 < maxDepth) walk(full, rel, depth + 1);
|
|
292
328
|
}
|
|
293
329
|
};
|
|
294
330
|
walk(rootDir);
|
|
295
331
|
return found;
|
|
296
332
|
}
|
|
297
333
|
|
|
334
|
+
const INVENTORY_PLUGIN_SCAN_DEPTH = 6;
|
|
335
|
+
|
|
336
|
+
function completeTargetStates(activeTargetId) {
|
|
337
|
+
return Object.fromEntries(
|
|
338
|
+
Object.keys(TARGETS).map((id) => [id, id === activeTargetId ? "synced" : "off"]),
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function inventorySkillFromMarker({
|
|
343
|
+
marker,
|
|
344
|
+
directory,
|
|
345
|
+
id,
|
|
346
|
+
targetId,
|
|
347
|
+
scope,
|
|
348
|
+
sourceName = null,
|
|
349
|
+
}) {
|
|
350
|
+
try {
|
|
351
|
+
const metadata = readSkillMetadata(
|
|
352
|
+
fs.readFileSync(marker, "utf8"),
|
|
353
|
+
installNameFromDirectory(directory) || directory,
|
|
354
|
+
);
|
|
355
|
+
return {
|
|
356
|
+
id,
|
|
357
|
+
key: id,
|
|
358
|
+
name: metadata.name,
|
|
359
|
+
description: metadata.description,
|
|
360
|
+
directory,
|
|
361
|
+
readmeUrl: null,
|
|
362
|
+
repoOwner: null,
|
|
363
|
+
repoName: null,
|
|
364
|
+
repoBranch: null,
|
|
365
|
+
installedAt: null,
|
|
366
|
+
managed: false,
|
|
367
|
+
readOnly: true,
|
|
368
|
+
inventoryOnly: true,
|
|
369
|
+
scope,
|
|
370
|
+
sourceName,
|
|
371
|
+
targets: [targetId],
|
|
372
|
+
targetStates: completeTargetStates(targetId),
|
|
373
|
+
};
|
|
374
|
+
} catch (_e) {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Plugin caches use <publisher>/<plugin>/<version>/skills/<skill>/SKILL.md.
|
|
380
|
+
// Walk only far enough to find a directory literally named "skills", then use
|
|
381
|
+
// the bounded skill scanner below it. We never traverse node_modules, hidden
|
|
382
|
+
// metadata directories, or symlinked group directories.
|
|
383
|
+
function scanPluginInventoryRoot({ root, targetId }) {
|
|
384
|
+
const found = [];
|
|
385
|
+
const walk = (dir, depth = 0) => {
|
|
386
|
+
let entries = [];
|
|
387
|
+
try {
|
|
388
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
389
|
+
} catch (_e) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
393
|
+
for (const entry of entries) {
|
|
394
|
+
if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
|
|
395
|
+
if (!entry.name || entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
396
|
+
const full = path.join(dir, entry.name);
|
|
397
|
+
if (entry.name.toLowerCase() === "skills") {
|
|
398
|
+
const container = path.relative(root, full).replace(/\\/g, "/");
|
|
399
|
+
const beforeSkills = container.split("/").filter(Boolean).slice(0, -1);
|
|
400
|
+
// Drop the cache version from the identity so installing a newer plugin
|
|
401
|
+
// version updates one inventory row instead of creating a duplicate.
|
|
402
|
+
const looksLikeVersion = (value) => /^v?\d+(?:\.\d+)*$/.test(String(value || ""));
|
|
403
|
+
const packageParts =
|
|
404
|
+
beforeSkills.length > 1 && looksLikeVersion(beforeSkills[beforeSkills.length - 1])
|
|
405
|
+
? beforeSkills.slice(0, -1)
|
|
406
|
+
: beforeSkills;
|
|
407
|
+
const sourceName = packageParts.join("/") || beforeSkills.join("/") || null;
|
|
408
|
+
for (const directory of scanSkillDirectories(full, { maxDepth: 5 })) {
|
|
409
|
+
const marker = findSkillMarker(path.join(full, directory));
|
|
410
|
+
if (!marker) continue;
|
|
411
|
+
const sourceKey = sourceName || "plugin";
|
|
412
|
+
const id = `inventory:${targetId}:plugin:${sourceKey}:${directory}`;
|
|
413
|
+
const skill = inventorySkillFromMarker({
|
|
414
|
+
marker,
|
|
415
|
+
directory,
|
|
416
|
+
id,
|
|
417
|
+
targetId,
|
|
418
|
+
scope: "plugin",
|
|
419
|
+
sourceName,
|
|
420
|
+
});
|
|
421
|
+
if (skill) found.push(skill);
|
|
422
|
+
}
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (depth + 1 < INVENTORY_PLUGIN_SCAN_DEPTH) walk(full, depth + 1);
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
walk(root);
|
|
429
|
+
return found;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function listInventorySkills() {
|
|
433
|
+
const sources = [
|
|
434
|
+
{
|
|
435
|
+
root: path.join(resolveCodexHome(), "plugins", "cache"),
|
|
436
|
+
targetId: "codex",
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
root: path.join(os.homedir(), ".claude", "plugins", "cache"),
|
|
440
|
+
targetId: "claude",
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
root: path.join(resolveZcodeHome(), "cli", "plugins", "cache"),
|
|
444
|
+
targetId: "zcode",
|
|
445
|
+
},
|
|
446
|
+
];
|
|
447
|
+
const byId = new Map();
|
|
448
|
+
for (const source of sources) {
|
|
449
|
+
const skills = scanPluginInventoryRoot(source);
|
|
450
|
+
// Later (normally newer, lexically sorted cache version) copies replace an
|
|
451
|
+
// older version with the same stable plugin+skill identity.
|
|
452
|
+
for (const skill of skills) byId.set(skill.id.toLowerCase(), skill);
|
|
453
|
+
}
|
|
454
|
+
return Array.from(byId.values());
|
|
455
|
+
}
|
|
456
|
+
|
|
298
457
|
const HASH_IGNORE = new Set([".git", ".DS_Store", "Thumbs.db", ".gitignore"]);
|
|
299
458
|
|
|
300
459
|
// Stable content fingerprint of a skill directory: walk files in sorted order,
|
|
@@ -625,7 +784,7 @@ function removeEmptyAncestors(startDir, stopDir) {
|
|
|
625
784
|
|
|
626
785
|
function syncSkillToTarget(directory, targetId) {
|
|
627
786
|
const target = TARGETS[targetId];
|
|
628
|
-
if (!target) throw new Error(`Unsupported target: ${targetId}`);
|
|
787
|
+
if (!target || target.manageable === false) throw new Error(`Unsupported target: ${targetId}`);
|
|
629
788
|
const source = managedSkillPath(directory);
|
|
630
789
|
if (!fs.existsSync(source)) throw new Error(`Managed skill not found: ${directory}`);
|
|
631
790
|
for (const baseDir of targetDirs(target)) {
|
|
@@ -738,7 +897,11 @@ function listInstalledSkills() {
|
|
|
738
897
|
}
|
|
739
898
|
}
|
|
740
899
|
|
|
741
|
-
return [...managed, ...unmanaged.values()].sort((a, b) =>
|
|
900
|
+
return [...managed, ...unmanaged.values(), ...listInventorySkills()].sort((a, b) => {
|
|
901
|
+
const byName = a.name.localeCompare(b.name);
|
|
902
|
+
if (byName !== 0) return byName;
|
|
903
|
+
return String(a.id || a.key || "").localeCompare(String(b.id || b.key || ""));
|
|
904
|
+
});
|
|
742
905
|
}
|
|
743
906
|
|
|
744
907
|
async function installSkill(skillInput, targetIds = ["claude", "codex"]) {
|
package/src/lib/usage-limits.js
CHANGED
|
@@ -523,15 +523,16 @@ async function fetchCodexUsageLimits(
|
|
|
523
523
|
// 401/403/404 from wham means "no usage data available for this auth state" — render
|
|
524
524
|
// a neutral empty state instead of a red "Fetch failed" error.
|
|
525
525
|
if (res.status === 401 || res.status === 403 || res.status === 404) {
|
|
526
|
-
return { body: null };
|
|
526
|
+
return { body: null, status: res.status };
|
|
527
527
|
}
|
|
528
528
|
if (res.status !== 200) {
|
|
529
529
|
throw new Error(`Codex API returned ${res.status}`);
|
|
530
530
|
}
|
|
531
|
-
return { body: await res.json() };
|
|
531
|
+
return { body: await res.json(), status: res.status };
|
|
532
532
|
}), "Codex", providerTimeoutMs);
|
|
533
533
|
if (!usage.body) {
|
|
534
534
|
return {
|
|
535
|
+
upstream_status: usage.status,
|
|
535
536
|
primary_window: null,
|
|
536
537
|
secondary_window: null,
|
|
537
538
|
credit_window: null,
|
|
@@ -558,6 +559,7 @@ async function fetchCodexUsageLimits(
|
|
|
558
559
|
}
|
|
559
560
|
}
|
|
560
561
|
return {
|
|
562
|
+
upstream_status: usage.status,
|
|
561
563
|
...normalizeCodexRateWindows(body.rate_limit || {}),
|
|
562
564
|
credit_window: normalizeCodexCreditWindow(body.spend_control?.individual_limit),
|
|
563
565
|
...normalizeCodexSparkRateWindows(body.additional_rate_limits),
|
|
@@ -3051,14 +3053,14 @@ async function fetchUsageLimitsUncached({
|
|
|
3051
3053
|
]);
|
|
3052
3054
|
const claudePlanType = claudeSubscription?.planType || null;
|
|
3053
3055
|
|
|
3054
|
-
//
|
|
3055
|
-
//
|
|
3056
|
-
//
|
|
3057
|
-
// refresh failure falls through to using the existing (possibly stale) token, then the
|
|
3058
|
-
// 4xx graceful path in fetchCodexUsageLimits surfaces a neutral state instead of red.
|
|
3056
|
+
// Match the official Codex CLI: prefer the access token's JWT expiry and refresh only
|
|
3057
|
+
// within five minutes of it; fall back to last_refresh >8 days for opaque/legacy tokens.
|
|
3058
|
+
// Best-effort: a refresh failure still falls through to the existing access token.
|
|
3059
3059
|
let refreshError = null;
|
|
3060
3060
|
let codexAuthRefreshed = codexAuth;
|
|
3061
|
-
if (codexAuth
|
|
3061
|
+
if (codexAuth
|
|
3062
|
+
&& isTokenStale(codexAuth.lastRefresh, nowMs, codexAuth.accessToken)
|
|
3063
|
+
&& codexAuth.refreshToken) {
|
|
3062
3064
|
try {
|
|
3063
3065
|
const newTokens = await refreshCodexTokens({
|
|
3064
3066
|
refreshToken: codexAuth.refreshToken,
|
|
@@ -3225,28 +3227,18 @@ async function fetchUsageLimitsUncached({
|
|
|
3225
3227
|
claude.service_status = claudeServiceStatus;
|
|
3226
3228
|
}
|
|
3227
3229
|
|
|
3230
|
+
const codexRefreshRequiresReauth = refreshError?.code === "REFRESH_TOKEN_EXPIRED";
|
|
3231
|
+
const codexLiveUsageSucceeded = codexResult?.status === "fulfilled"
|
|
3232
|
+
&& codexResult.value.upstream_status === 200;
|
|
3228
3233
|
let codex;
|
|
3229
3234
|
if (!codexToken) {
|
|
3230
3235
|
codex = { configured: false };
|
|
3231
|
-
} else if (
|
|
3232
|
-
|
|
3233
|
-
//
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
auth_action_required: "reauth",
|
|
3238
|
-
};
|
|
3239
|
-
} else if (!codexResult || codexResult.status === "rejected") {
|
|
3240
|
-
// Live fetch failed or timed out (Codex hits chatgpt.com fresh every poll with no
|
|
3241
|
-
// rate-limit cooldown, so a slow network shows up here often). Serve the last successful
|
|
3242
|
-
// read so the bars stay visible instead of a red error, mirroring the Claude stale path.
|
|
3243
|
-
const cached = readCodexLimitsCache({ home, nowMs });
|
|
3244
|
-
if (cached) {
|
|
3245
|
-
codex = cached;
|
|
3246
|
-
} else {
|
|
3247
|
-
codex = { configured: true, error: codexResult?.reason?.message || "Unknown error" };
|
|
3248
|
-
}
|
|
3249
|
-
} else {
|
|
3236
|
+
} else if (codexResult?.status === "fulfilled"
|
|
3237
|
+
&& (!codexRefreshRequiresReauth || codexLiveUsageSucceeded)) {
|
|
3238
|
+
// A proactive refresh can fail while the existing access token is still valid.
|
|
3239
|
+
// Prefer a confirmed 200 live usage read over the refresh error so usable quota
|
|
3240
|
+
// data is not discarded before the access token actually expires. A neutral
|
|
3241
|
+
// 401/403/404 no-data response must not mask a failed refresh.
|
|
3250
3242
|
codex = {
|
|
3251
3243
|
configured: true,
|
|
3252
3244
|
error: null,
|
|
@@ -3257,13 +3249,32 @@ async function fetchUsageLimitsUncached({
|
|
|
3257
3249
|
spark_primary_window: codexResult.value.spark_primary_window,
|
|
3258
3250
|
spark_secondary_window: codexResult.value.spark_secondary_window,
|
|
3259
3251
|
reset_credits: codexResult.value.reset_credits,
|
|
3260
|
-
// Live read is current as of now; the stale fallback path
|
|
3252
|
+
// Live read is current as of now; the stale fallback path below serves the
|
|
3261
3253
|
// disk cache with `stale: true`. Always emitting both lets the client show a
|
|
3262
3254
|
// data-age label uniformly (see the Claude live-success block).
|
|
3263
3255
|
stale: false,
|
|
3264
3256
|
cached_at: new Date(nowMs).toISOString(),
|
|
3265
3257
|
};
|
|
3266
3258
|
writeCodexLimitsCache(codex, { home, nowMs });
|
|
3259
|
+
} else if (codexRefreshRequiresReauth) {
|
|
3260
|
+
// Refresh token is dead — the user must re-run `codex` to log in again. Surface a
|
|
3261
|
+
// specific, actionable message rather than the generic "Fetch failed", but only
|
|
3262
|
+
// after the existing access token also failed to fetch live usage above.
|
|
3263
|
+
codex = {
|
|
3264
|
+
configured: true,
|
|
3265
|
+
error: refreshError.message,
|
|
3266
|
+
auth_action_required: "reauth",
|
|
3267
|
+
};
|
|
3268
|
+
} else if (!codexResult || codexResult.status === "rejected") {
|
|
3269
|
+
// Live fetch failed or timed out (Codex hits chatgpt.com fresh every poll with no
|
|
3270
|
+
// rate-limit cooldown, so a slow network shows up here often). Serve the last successful
|
|
3271
|
+
// read so the bars stay visible instead of a red error, mirroring the Claude stale path.
|
|
3272
|
+
const cached = readCodexLimitsCache({ home, nowMs });
|
|
3273
|
+
if (cached) {
|
|
3274
|
+
codex = cached;
|
|
3275
|
+
} else {
|
|
3276
|
+
codex = { configured: true, error: codexResult?.reason?.message || "Unknown error" };
|
|
3277
|
+
}
|
|
3267
3278
|
}
|
|
3268
3279
|
|
|
3269
3280
|
const data = {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{m as o,d as N,j as r}from"./__vite-browser-external-RQ7lZFvr.js";import{Z as $}from"./zap-CrW1Qm1b.js";import{F as A}from"./flame-D9HUvqS6.js";const j=[["path",{d:"M10 22V7a1 1 0 0 0-1-1H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-5a1 1 0 0 0-1-1H2",key:"1ah6g2"}],["rect",{x:"14",y:"2",width:"8",height:"8",rx:"1",key:"88lufb"}]],E=o("blocks",j);const L=[["path",{d:"M12 18V5",key:"adv99a"}],["path",{d:"M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4",key:"1e3is1"}],["path",{d:"M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5",key:"1gqd8o"}],["path",{d:"M17.997 5.125a4 4 0 0 1 2.526 5.77",key:"iwvgf7"}],["path",{d:"M18 18a4 4 0 0 0 2-7.464",key:"efp6ie"}],["path",{d:"M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517",key:"1gq6am"}],["path",{d:"M6 18a4 4 0 0 1-2-7.464",key:"k1g0md"}],["path",{d:"M6.003 5.125a4 4 0 0 0-2.526 5.77",key:"q97ue3"}]],C=o("brain",L);const T=[["path",{d:"M8 2v4",key:"1cmpym"}],["path",{d:"M16 2v4",key:"4m81vk"}],["rect",{width:"18",height:"18",x:"3",y:"4",rx:"2",key:"1hopcy"}],["path",{d:"M3 10h18",key:"8toen8"}],["path",{d:"M8 14h.01",key:"6423bh"}],["path",{d:"M12 14h.01",key:"1etili"}],["path",{d:"M16 14h.01",key:"1gbofw"}],["path",{d:"M8 18h.01",key:"lrp35t"}],["path",{d:"M12 18h.01",key:"mhygvu"}],["path",{d:"M16 18h.01",key:"kzsmim"}]],z=o("calendar-days",T);const B=[["path",{d:"M11.562 3.266a.5.5 0 0 1 .876 0L15.39 8.87a1 1 0 0 0 1.516.294L21.183 5.5a.5.5 0 0 1 .798.519l-2.834 10.246a1 1 0 0 1-.956.734H5.81a1 1 0 0 1-.957-.734L2.02 6.02a.5.5 0 0 1 .798-.519l4.276 3.664a1 1 0 0 0 1.516-.294z",key:"1vdc57"}],["path",{d:"M5 21h14",key:"11awu3"}]],q=o("crown",B);const H=[["path",{d:"M12.67 19a2 2 0 0 0 1.416-.588l6.154-6.172a6 6 0 0 0-8.49-8.49L5.586 9.914A2 2 0 0 0 5 11.328V18a1 1 0 0 0 1 1z",key:"18jl4k"}],["path",{d:"M16 8 2 22",key:"vp34q"}],["path",{d:"M17.5 15H9",key:"1oz8nu"}]],R=o("feather",H);const D=[["path",{d:"M18 19a5 5 0 0 1-5-5v8",key:"sz5oeg"}],["path",{d:"M9 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v5",key:"1w6njk"}],["circle",{cx:"13",cy:"12",r:"2",key:"1j92g6"}],["circle",{cx:"20",cy:"19",r:"2",key:"1obnsp"}]],F=o("folder-git-2",D);const I=[["path",{d:"M4 16v-2.38C4 11.5 2.97 10.5 3 8c.03-2.72 1.49-6 4.5-6C9.37 2 10 3.8 10 5.5c0 3.11-2 5.66-2 8.68V16a2 2 0 1 1-4 0Z",key:"1dudjm"}],["path",{d:"M20 20v-2.38c0-2.12 1.03-3.12 1-5.62-.03-2.72-1.49-6-4.5-6C14.63 6 14 7.8 14 9.5c0 3.11 2 5.66 2 8.68V20a2 2 0 1 0 4 0Z",key:"l2t8xc"}],["path",{d:"M16 17h4",key:"1dejxt"}],["path",{d:"M4 13h4",key:"1bwh8b"}]],G=o("footprints",I);const V=[["path",{d:"M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5",key:"mvr1a0"}]],S=o("heart",V);const Z=[["path",{d:"M7.21 15 2.66 7.14a2 2 0 0 1 .13-2.2L4.4 2.8A2 2 0 0 1 6 2h12a2 2 0 0 1 1.6.8l1.6 2.14a2 2 0 0 1 .14 2.2L16.79 15",key:"143lza"}],["path",{d:"M11 12 5.12 2.2",key:"qhuxz6"}],["path",{d:"m13 12 5.88-9.8",key:"hbye0f"}],["path",{d:"M8 7h8",key:"i86dvs"}],["circle",{cx:"12",cy:"17",r:"5",key:"qbz8iq"}],["path",{d:"M12 18v-2h-.5",key:"fawc4q"}]],O=o("medal",Z);const P=[["path",{d:"M18 5h4",key:"1lhgn2"}],["path",{d:"M20 3v4",key:"1olli1"}],["path",{d:"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",key:"kfwtm"}]],X=o("moon-star",P);const K=[["path",{d:"M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5",key:"qeys4"}],["path",{d:"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09",key:"u4xsad"}],["path",{d:"M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z",key:"676m9"}],["path",{d:"M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05",key:"92ym6u"}]],U=o("rocket",K);const W=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],Y=o("shield-check",W);const J=[["path",{d:"M16 7h6v6",key:"box55l"}],["path",{d:"m22 7-8.5 8.5-5-5L2 17",key:"1t1m79"}]],Q=o("trending-up",J),k=[{id:"token_titan",scope:"cloud",icon:q,format:"tokens",art:"/achievements/token-titan.png"},{id:"big_day",scope:"cloud",icon:$,format:"tokens",art:"/achievements/big-day.png"},{id:"wordsmith",scope:"cloud",icon:R,format:"tokens",art:"/achievements/wordsmith.png"},{id:"marathoner",scope:"cloud",icon:G,format:"days",art:"/achievements/marathoner.png"},{id:"streak",scope:"cloud",icon:A,format:"days",art:"/achievements/streak.png"},{id:"weekend_warrior",scope:"cloud",icon:z,format:"days",art:"/achievements/weekend-warrior.png"},{id:"momentum",scope:"cloud",icon:Q,format:"multiplier",art:"/achievements/momentum.png"},{id:"polyglot",scope:"cloud",icon:C,format:"count",art:"/achievements/polyglot.png"},{id:"trendsetter",scope:"cloud",icon:U,format:"count",art:"/achievements/trendsetter.png"},{id:"multitool",scope:"cloud",icon:E,format:"count",art:"/achievements/multitool.png"},{id:"podium",scope:"cloud",icon:O,format:"rank",art:"/achievements/podium.png"},{id:"veteran",scope:"cloud",icon:Y,format:"days",art:"/achievements/veteran.png"},{id:"project_hopper",scope:"local",icon:F,format:"count",art:"/achievements/project-hopper.png"},{id:"project_devotion",scope:"local",icon:S,format:"tokens",art:"/achievements/project-devotion.png"},{id:"night_owl",scope:"local",icon:X,format:"count",art:"/achievements/night-owl.png"}],u=new Map(k.map(e=>[e.id,e])),m=new Map(k.map((e,a)=>[e.id,a]));function de(e,a){return`achievements.badge.${e}.${a}`}function ee(e){return[...e||[]].sort((a,t)=>{const c=(t?.tier||0)-(a?.tier||0);return c!==0?c:(m.get(a?.id)??99)-(m.get(t?.id)??99)})}function re(e){const a=(e||[]).filter(t=>t&&(t.tier||0)>=1&&u.has(t.id));return a.length===0?null:ee(a)[0]}const v={1:"bronze",2:"silver",3:"gold",4:"diamond"},ie=["bronze","silver","gold","diamond"],ae={bronze:{rim:["#a06a44","#5c3a22"],face:["#d29a6c","#96602f"],glyph:"#3f2817",ring:"#e8c3a0",sheen:"rgba(255, 236, 220, 0.45)",label:"#a06a44"},silver:{rim:["#aab3bb","#67707b"],face:["#dde2e7","#9ba5ae"],glyph:"#39424b",ring:"#f2f5f7",sheen:"rgba(255, 255, 255, 0.55)",label:"#8b959f"},gold:{rim:["#c9971c","#8a6508"],face:["#f2ca52","#cf9c26"],glyph:"#5c430e",ring:"#ffe9a8",sheen:"rgba(255, 248, 214, 0.55)",label:"#b8860b"},diamond:{rim:["#62b1e0","#7c6fd9"],face:["#c8ecf6","#84b4ea"],glyph:"#27496d",ring:"#eafcff",sheen:"rgba(255, 255, 255, 0.65)",label:"#5a9bd8"}},y={rim:["#a8ada9","#7c817d"],face:["#cdd2ce","#a3a8a4"],glyph:"#6a706c",ring:"#dde1de",sheen:"rgba(255, 255, 255, 0.25)",label:"#8b908c"};function te(e,a=!1){return a||!e||e<1?y:ae[v[Math.min(e,4)]]||y}function se(e){return v[e]||null}const g={xs:18,sm:24,md:44,xl:88,lg:108},f={xs:.75,sm:1,md:1.5,xl:2,lg:2};function le({badgeId:e,tier:a=0,size:t="md",locked:c=!1,label:i,className:M=""}){const s=u.get(e),h=c||!a||a<1,n=te(a,h),d=t==="fill",l=d?"100%":g[t]||g.md,b=d?4:f[t]||f.md,[_,x]=N.useState(!1),p=s?.icon||null,w=!!s?.art&&!_;return r.jsx("span",{role:i?"img":void 0,"aria-label":i||void 0,"aria-hidden":i?void 0:!0,className:`inline-flex shrink-0 rounded-full ${M}`,style:{width:l,height:l,padding:b,background:`linear-gradient(135deg, ${n.rim[0]} 0%, ${n.ring} 42%, ${n.rim[1]} 100%)`,boxShadow:d||t==="md"||t==="xl"||t==="lg"?"0 0 0 1px rgba(10, 15, 12, 0.06), 0 1px 2px rgba(10, 15, 12, 0.08)":void 0},children:w?r.jsx("img",{src:s.art,alt:"",draggable:!1,loading:"lazy",onError:()=>x(!0),className:"h-full w-full rounded-full object-cover",style:h?{filter:"grayscale(1)",opacity:.55}:void 0}):r.jsx("span",{className:"flex h-full w-full items-center justify-center rounded-full",style:{background:`linear-gradient(145deg, ${n.face[0]}, ${n.face[1]})`},children:p?r.jsx(p,{size:d?64:Math.round(l*.5),color:n.glyph,strokeWidth:2}):null})})}export{le as A,k as B,S as H,Q as T,ae as a,de as b,u as c,ie as d,re as h,te as p,ee as s,se as t};
|