@phuc1403/musketeer 0.12.0 → 0.12.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phuc1403/musketeer",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Distributable custom Claude Code harness — one declarative command scaffolds a curated company of musketeers (skills/agents/hooks) into any project's .claude/.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -24,8 +24,9 @@ const { getGitInfo } = require('./hooks/lib/git-info-cache.cjs');
24
24
  // Buffer constant for fallback context calculation
25
25
  const AUTOCOMPACT_BUFFER = 40000;
26
26
 
27
- // Quota cache older than this is not rendered — a stale number is worse than none.
28
- const USAGE_CACHE_RENDER_TTL_MS = 300000;
27
+ // Quota cache older than this is not rendered — a stale number is worse than none. Twice the refresh
28
+ // hook's 5-minute fetch interval, so a quiet spell between tool calls does not blank the segment.
29
+ const USAGE_CACHE_RENDER_TTL_MS = 600000;
29
30
  // Any window at or above this utilization flips the quota segment to red.
30
31
  const QUOTA_HIGH_PERCENT = 85;
31
32
 
@@ -189,13 +190,12 @@ function readUsageCache() {
189
190
  }
190
191
 
191
192
  /**
192
- * Coerce an API utilization value to a whole percent.
193
- * The API returns either a 0-1 fraction or an already-scaled percent.
193
+ * Coerce an API utilization value to a whole percent. The API reports an already-scaled percent, so a
194
+ * value below 1 is a small percent, not a fraction.
194
195
  * @returns {number|null} Percent, or null when the value is unusable
195
196
  */
196
197
  function normalizeUtilization(utilization) {
197
198
  if (typeof utilization !== 'number' || !Number.isFinite(utilization)) return null;
198
- if (utilization > 0 && utilization < 1) return Math.round(utilization * 100);
199
199
  return Math.max(0, Math.round(utilization));
200
200
  }
201
201
 
@@ -204,7 +204,7 @@ function normalizeUtilization(utilization) {
204
204
  * @returns {string} Empty string once the deadline has passed
205
205
  */
206
206
  function formatCountdown(msLeft) {
207
- if (msLeft <= 0) return '';
207
+ if (!Number.isFinite(msLeft) || msLeft <= 0) return '';
208
208
  const mins = Math.floor(msLeft / 60000);
209
209
  if (mins < 60) return `${mins}m`;
210
210
  if (mins < 1440) {
@@ -216,13 +216,13 @@ function formatCountdown(msLeft) {
216
216
  }
217
217
 
218
218
  /**
219
- * Build the quota window strings, e.g. ["5h 14% (2h21m)", "wk 43% (5d)"].
219
+ * Build the quota windows, e.g. [{text: "5h 14% (2h21m)", percent: 14}, {text: "wk 43% (5d)", percent: 43}].
220
220
  *
221
221
  * Reads the pre-calculated `snapshot` when the cache carries one, and falls
222
222
  * back to the raw `data.*.utilization` otherwise — the hook in this project
223
223
  * writes only `{timestamp, status, data}`, so the fallback is the normal path.
224
224
  *
225
- * @returns {string[]} One entry per window; empty when unavailable or stale
225
+ * @returns {{text: string, percent: number}[]} One entry per window; empty when unavailable or stale
226
226
  */
227
227
  function buildUsageWindows(cache) {
228
228
  if (!cache || cache.status !== 'available') return [];
@@ -241,7 +241,7 @@ function buildUsageWindows(cache) {
241
241
  const cd = formatCountdown(new Date(window.resets_at).getTime() - now);
242
242
  if (cd) countdown = ` (${cd})`;
243
243
  }
244
- return `${label} ${percent}%${countdown}`;
244
+ return { text: `${label} ${percent}%${countdown}`, percent };
245
245
  }).filter(Boolean);
246
246
  }
247
247
 
@@ -251,7 +251,7 @@ function buildUsageWindows(cache) {
251
251
  */
252
252
  function buildUsageString(ctx) {
253
253
  if (!Array.isArray(ctx.usageWindows) || ctx.usageWindows.length === 0) return null;
254
- return ctx.usageWindows.join(' ');
254
+ return ctx.usageWindows.map((w) => w.text).join(' ');
255
255
  }
256
256
 
257
257
  /**
@@ -259,14 +259,7 @@ function buildUsageString(ctx) {
259
259
  * @returns {(s: string) => string} Color function from the colors module
260
260
  */
261
261
  function getQuotaColor(usageWindows) {
262
- // Match the percent token specifically — the label carries digits too ("5h 90%").
263
- const percents = (usageWindows || [])
264
- .map((windowText) => {
265
- const match = String(windowText).match(/(\d+)%/);
266
- return match ? Number(match[1]) : null;
267
- })
268
- .filter((percent) => Number.isFinite(percent));
269
- return percents.some((n) => n >= QUOTA_HIGH_PERCENT) ? red : green;
262
+ return (usageWindows || []).some((w) => Number(w.percent) >= QUOTA_HIGH_PERCENT) ? red : green;
270
263
  }
271
264
 
272
265
  /**
@@ -596,7 +589,18 @@ async function main() {
596
589
  }
597
590
  }
598
591
 
599
- main().catch(() => {
600
- console.log('📁 error');
601
- process.exit(1);
602
- });
592
+ // Run only when Claude Code executes the file; a require() (the tests) gets the helpers without rendering.
593
+ if (require.main === module) {
594
+ main().catch(() => {
595
+ console.log('📁 error');
596
+ process.exit(1);
597
+ });
598
+ }
599
+
600
+ module.exports = {
601
+ normalizeUtilization,
602
+ formatCountdown,
603
+ buildUsageWindows,
604
+ getQuotaColor,
605
+ USAGE_CACHE_RENDER_TTL_MS,
606
+ };