claudemon 0.3.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"PieChart.d.ts","sourceRoot":"","sources":["../../src/components/PieChart.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB;AAqDD,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,SAAS,GACV,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CAuFpC"}
1
+ {"version":3,"file":"PieChart.d.ts","sourceRoot":"","sources":["../../src/components/PieChart.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB;AAqCD,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,SAAS,GACV,EAAE,aAAa,GAAG,KAAK,CAAC,YAAY,CAuFpC"}
@@ -16,33 +16,27 @@ function getBoldColor(pct) {
16
16
  return chalk.bold.red;
17
17
  }
18
18
  function formatResetTime(reset) {
19
- const now = new Date();
20
- const resetLocal = reset;
21
- const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
22
- const resetDate = new Date(resetLocal.getFullYear(), resetLocal.getMonth(), resetLocal.getDate());
23
- const fmt = (d) => {
24
- let hours = d.getHours();
25
- const minutes = d.getMinutes();
26
- const ampm = hours >= 12 ? "pm" : "am";
27
- hours = hours % 12 || 12;
28
- return `${hours}:${minutes.toString().padStart(2, "0")}${ampm}`;
29
- };
30
- // Same day
31
- if (nowDate.getTime() === resetDate.getTime()) {
32
- return fmt(resetLocal);
19
+ const diffMs = reset.getTime() - Date.now();
20
+ if (diffMs <= 0)
21
+ return "now";
22
+ const totalMinutes = Math.floor(diffMs / 60000);
23
+ const totalHours = Math.floor(diffMs / 3600000);
24
+ const totalDays = Math.floor(diffMs / 86400000);
25
+ if (totalMinutes < 1)
26
+ return "in less than a minute";
27
+ if (totalMinutes < 60) {
28
+ return `in ${totalMinutes} minute${totalMinutes !== 1 ? "s" : ""}`;
33
29
  }
34
- // Tomorrow
35
- const tomorrow = new Date(nowDate);
36
- tomorrow.setDate(tomorrow.getDate() + 1);
37
- if (tomorrow.getTime() === resetDate.getTime()) {
38
- return `tomorrow at ${fmt(resetLocal)}`;
30
+ if (totalHours < 24) {
31
+ const remainingMin = totalMinutes % 60;
32
+ if (remainingMin === 0)
33
+ return `in ${totalHours} hour${totalHours !== 1 ? "s" : ""}`;
34
+ return `in ${totalHours} hour${totalHours !== 1 ? "s" : ""}, ${remainingMin} min`;
39
35
  }
40
- // Other
41
- const months = [
42
- "jan", "feb", "mar", "apr", "may", "jun",
43
- "jul", "aug", "sep", "oct", "nov", "dec",
44
- ];
45
- return `${months[resetLocal.getMonth()]} ${resetLocal.getDate()} at ${fmt(resetLocal)}`;
36
+ const remainingHrs = totalHours % 24;
37
+ if (remainingHrs === 0)
38
+ return `in ${totalDays} day${totalDays !== 1 ? "s" : ""}`;
39
+ return `in ${totalDays} day${totalDays !== 1 ? "s" : ""}, ${remainingHrs} hour${remainingHrs !== 1 ? "s" : ""}`;
46
40
  }
47
41
  export function PieChart({ usagePct, label, resetTime, }) {
48
42
  const pct = Math.max(0, Math.min(100, usagePct));
@@ -1 +1 @@
1
- {"version":3,"file":"PieChart.js","sourceRoot":"","sources":["../../src/components/PieChart.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PieChart.js","sourceRoot":"","sources":["../../src/components/PieChart.tsx"],"names":[],"mappings":";AAKA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,GAAG,GAAG,EAAE;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC;IACjC,IAAI,GAAG,GAAG,EAAE;QAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC;AACnB,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,GAAG,GAAG,EAAE;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;IACtC,IAAI,GAAG,GAAG,EAAE;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AACxB,CAAC;AAED,SAAS,eAAe,CAAC,KAAW;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE5C,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAE9B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC;IAEhD,IAAI,YAAY,GAAG,CAAC;QAAE,OAAO,uBAAuB,CAAC;IACrD,IAAI,YAAY,GAAG,EAAE,EAAE,CAAC;QACtB,OAAO,MAAM,YAAY,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,UAAU,GAAG,EAAE,EAAE,CAAC;QACpB,MAAM,YAAY,GAAG,YAAY,GAAG,EAAE,CAAC;QACvC,IAAI,YAAY,KAAK,CAAC;YAAE,OAAO,MAAM,UAAU,QAAQ,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACrF,OAAO,MAAM,UAAU,QAAQ,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,MAAM,CAAC;IACpF,CAAC;IACD,MAAM,YAAY,GAAG,UAAU,GAAG,EAAE,CAAC;IACrC,IAAI,YAAY,KAAK,CAAC;QAAE,OAAO,MAAM,SAAS,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAClF,OAAO,MAAM,SAAS,OAAO,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAClH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EACvB,QAAQ,EACR,KAAK,EACL,SAAS,GACK;IACd,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAEpC,mBAAmB;IACnB,MAAM,MAAM,GAAG,GAAG,CAAC;IACnB,MAAM,MAAM,GAAG,GAAG,CAAC;IACnB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAExC,iCAAiC;IACjC,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,MAAM,CAAC;IACvB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,CAAC;IAI3B,MAAM,IAAI,GAAa,EAAE,CAAC;IAE1B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,GAAW,EAAE,CAAC;QACxB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YACpC,MAAM,EAAE,GAAG,GAAG,GAAG,OAAO,CAAC;YACzB,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,GAAG,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YAE1C,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;gBACrC,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;gBAChC,IAAI,KAAK,GAAG,CAAC;oBAAE,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;gBAEpC,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;oBACvB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;gBACzC,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClB,CAAC;IAED,kCAAkC;IAClC,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,QAAQ,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,IAAI,EAAE,CAAC;YACjC,IAAI,CAAC,SAAS,CAAE,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QACpE,CAAC;IACH,CAAC;IAED,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,SAAS,GAAG,CAAC,CAAC;IAC/B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,QAAQ,GAAG,IAAI,EAAE,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,MAAM,GAAG,UAAU,GAAG,CAAC,CAAC;YAC9B,IAAI,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,IAAI,EAAE,CAAC;gBACjC,IAAI,CAAC,QAAQ,CAAE,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;YAClE,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;YACvB,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACzD,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,aACxD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CACtB,KAAC,IAAI,cAAU,IAAI,IAAR,CAAC,CAAe,CAC5B,CAAC,EACD,SAAS,IAAI,CACZ,MAAC,IAAI,IAAC,QAAQ,8BAAS,eAAe,CAAC,SAAS,CAAC,IAAQ,CAC1D,IACG,CACP,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,IAAI,GAAG,IAAI,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,IAAI,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,SAAS,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAUvE;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAQvE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAE/C;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAI7D;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAI7D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAQ5D"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,IAAI,GAAG,IAAI,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,IAAI,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,SAAS,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAUvE;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAQvE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAE/C;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAI7D;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAI7D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAe5D"}
package/dist/models.js CHANGED
@@ -51,10 +51,18 @@ export function formatCountdown(totalSeconds) {
51
51
  const days = Math.floor(totalSeconds / 86400);
52
52
  const hours = Math.floor((totalSeconds % 86400) / 3600);
53
53
  const minutes = Math.floor((totalSeconds % 3600) / 60);
54
- if (days > 0)
55
- return `${days}d ${hours}h`;
56
- if (hours > 0)
57
- return `${hours}h ${minutes}m`;
58
- return `${minutes}m`;
54
+ if (days > 0) {
55
+ if (hours === 0)
56
+ return `in ${days} day${days !== 1 ? "s" : ""}`;
57
+ return `in ${days} day${days !== 1 ? "s" : ""}, ${hours} hour${hours !== 1 ? "s" : ""}`;
58
+ }
59
+ if (hours > 0) {
60
+ if (minutes === 0)
61
+ return `in ${hours} hour${hours !== 1 ? "s" : ""}`;
62
+ return `in ${hours} hour${hours !== 1 ? "s" : ""}, ${minutes} min`;
63
+ }
64
+ if (minutes < 1)
65
+ return "in less than a minute";
66
+ return `in ${minutes} minute${minutes !== 1 ? "s" : ""}`;
59
67
  }
60
68
  //# sourceMappingURL=models.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA;;GAEG;AA4BH,MAAM,UAAU,eAAe,CAAC,OAA4B;IAC1D,OAAO;QACL,gBAAgB,EAAE,CAAC;QACnB,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,CAAC;QACnB,iBAAiB,EAAE,IAAI;QACvB,WAAW,EAAE,EAAE;QACf,QAAQ,EAAE,KAAK;QACf,GAAG,OAAO;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAA4B;IAC1D,OAAO;QACL,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,SAAS,EAAE,CAAC;QACZ,UAAU,EAAE,CAAC;QACb,GAAG,OAAO;KACX,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,CAAY;IACrC,OAAO,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,UAAU,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,CAAY;IACnD,IAAI,CAAC,CAAC,CAAC,iBAAiB;QAAE,OAAO,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,CAAY;IACnD,IAAI,CAAC,CAAC,CAAC,iBAAiB;QAAE,OAAO,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9C,CAAC;SAAM,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC;IACzC,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,IAAI,YAAY,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACvD,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC;IAC1C,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,GAAG,KAAK,KAAK,OAAO,GAAG,CAAC;IAC9C,OAAO,GAAG,OAAO,GAAG,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@
8
8
 
9
9
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
10
10
  import { Type } from "@sinclair/typebox";
11
+ import { matchesKey, truncateToWidth, visibleWidth } from "@mariozechner/pi-tui";
11
12
  import { execFileSync } from "node:child_process";
12
13
  import { existsSync, readFileSync } from "node:fs";
13
14
  import { homedir, platform } from "node:os";
@@ -178,23 +179,361 @@ function formatQuota(q: QuotaData): string {
178
179
  return lines.join("\n");
179
180
  }
180
181
 
182
+ // ---------------------------------------------------------------------------
183
+ // TUI Dashboard Component (replaces broken pi.exec approach)
184
+ // ---------------------------------------------------------------------------
185
+
186
+ function formatResetTime(reset: Date): string {
187
+ const diffMs = reset.getTime() - Date.now();
188
+ if (diffMs <= 0) return "now";
189
+ const totalMinutes = Math.floor(diffMs / 60000);
190
+ const totalHours = Math.floor(diffMs / 3600000);
191
+ const totalDays = Math.floor(diffMs / 86400000);
192
+ if (totalMinutes < 1) return "in <1 min";
193
+ if (totalMinutes < 60) return `in ${totalMinutes}m`;
194
+ if (totalHours < 24) {
195
+ const remainingMin = totalMinutes % 60;
196
+ return remainingMin === 0 ? `in ${totalHours}h` : `in ${totalHours}h ${remainingMin}m`;
197
+ }
198
+ const remainingHrs = totalHours % 24;
199
+ return remainingHrs === 0 ? `in ${totalDays}d` : `in ${totalDays}d ${remainingHrs}h`;
200
+ }
201
+
202
+ function getColorFn(pct: number, theme: any): (s: string) => string {
203
+ if (pct < 50) return (s: string) => theme.fg("success", s);
204
+ if (pct < 80) return (s: string) => theme.fg("warning", s);
205
+ return (s: string) => theme.fg("error", s);
206
+ }
207
+
208
+ function renderDonut(pct: number, label: string, resetTime: Date | null, theme: any): string[] {
209
+ const clamped = Math.max(0, Math.min(100, pct));
210
+ const colorFn = getColorFn(clamped, theme);
211
+
212
+ const outerR = 6.5;
213
+ const innerR = 5.0;
214
+ const rows = Math.floor(outerR * 2) + 1;
215
+ const cols = Math.floor(outerR * 4) + 1;
216
+ const usedAngle = 2 * Math.PI * (clamped / 100);
217
+ const centerY = outerR;
218
+ const centerX = outerR * 2;
219
+
220
+ const grid: { char: string; style: ((s: string) => string) | null }[][] = [];
221
+
222
+ for (let row = 0; row < rows; row++) {
223
+ const line: { char: string; style: ((s: string) => string) | null }[] = [];
224
+ for (let col = 0; col < cols; col++) {
225
+ const dy = row - centerY;
226
+ const dx = (col - centerX) / 2.0;
227
+ const dist = Math.sqrt(dx * dx + dy * dy);
228
+
229
+ if (innerR <= dist && dist <= outerR) {
230
+ let angle = Math.atan2(dx, -dy);
231
+ if (angle < 0) angle += 2 * Math.PI;
232
+ if (angle <= usedAngle) {
233
+ line.push({ char: "█", style: colorFn });
234
+ } else {
235
+ line.push({ char: "░", style: (s: string) => theme.fg("dim", s) });
236
+ }
237
+ } else {
238
+ line.push({ char: " ", style: null });
239
+ }
240
+ }
241
+ grid.push(line);
242
+ }
243
+
244
+ // Place percentage in center
245
+ const pctStr = `${Math.round(clamped)}%`;
246
+ const centerRow = Math.floor(rows / 2);
247
+ const startCol = Math.floor(centerX - pctStr.length / 2);
248
+ for (let i = 0; i < pctStr.length; i++) {
249
+ const colIdx = startCol + i;
250
+ if (colIdx >= 0 && colIdx < cols) {
251
+ grid[centerRow]![colIdx] = { char: pctStr[i]!, style: (s: string) => theme.bold(colorFn(s)) };
252
+ }
253
+ }
254
+
255
+ // Place label below percentage
256
+ const labelRow = centerRow + 1;
257
+ const labelStart = Math.floor(centerX - label.length / 2);
258
+ if (labelRow < rows) {
259
+ for (let i = 0; i < label.length; i++) {
260
+ const colIdx = labelStart + i;
261
+ if (colIdx >= 0 && colIdx < cols) {
262
+ grid[labelRow]![colIdx] = { char: label[i]!, style: (s: string) => theme.fg("muted", s) };
263
+ }
264
+ }
265
+ }
266
+
267
+ // Render grid to lines
268
+ const lines: string[] = [];
269
+ for (const row of grid) {
270
+ let line = "";
271
+ for (const cell of row) {
272
+ line += cell.style ? cell.style(cell.char) : cell.char;
273
+ }
274
+ lines.push(line);
275
+ }
276
+
277
+ // Reset time line
278
+ if (resetTime) {
279
+ const resetStr = `Resets ${formatResetTime(resetTime)}`;
280
+ const pad = Math.max(0, Math.floor((cols - resetStr.length) / 2));
281
+ lines.push(" ".repeat(pad) + theme.fg("dim", resetStr));
282
+ } else {
283
+ lines.push("");
284
+ }
285
+
286
+ return lines;
287
+ }
288
+
289
+ function renderModelQuotas(quotaData: QuotaData, theme: any, width: number): string[] {
290
+ if (quotaData.modelQuotas.length === 0) return [];
291
+
292
+ const lines: string[] = [];
293
+ lines.push(theme.bold(" Per-Model Breakdown"));
294
+ lines.push("");
295
+
296
+ for (let i = 0; i < quotaData.modelQuotas.length; i++) {
297
+ const mq = quotaData.modelQuotas[i]!;
298
+ const prefix = i === quotaData.modelQuotas.length - 1 ? " └ " : " ├ ";
299
+ const colorFn = getColorFn(mq.usagePct, theme);
300
+ const barWidth = 15;
301
+ const filled = Math.round((mq.usagePct / 100) * barWidth);
302
+ const empty = barWidth - filled;
303
+ const bar = colorFn("█".repeat(filled)) + theme.fg("dim", "░".repeat(empty));
304
+ const pctStr = colorFn(`${Math.round(mq.usagePct)}%`.padStart(4));
305
+ const name = mq.modelName.length > 28 ? mq.modelName.slice(0, 25) + "..." : mq.modelName;
306
+ lines.push(`${prefix}${name.padEnd(28)} ${bar} ${pctStr}`);
307
+ }
308
+
309
+ return lines;
310
+ }
311
+
312
+ class ClaudemonDashboard {
313
+ private quotaData: QuotaData | null = null;
314
+ private isLoading = true;
315
+ private errorMessage = "";
316
+ private lastRefreshAgo = 0;
317
+ private lastRefreshTime = 0;
318
+ private showHelp = false;
319
+ private refreshInterval: ReturnType<typeof setInterval> | null = null;
320
+ private tickInterval: ReturnType<typeof setInterval> | null = null;
321
+ private autoRefreshInterval: ReturnType<typeof setInterval> | null = null;
322
+ private tui: { requestRender: () => void };
323
+ private theme: any;
324
+ private onClose: () => void;
325
+ private token: string;
326
+ private cachedWidth = 0;
327
+ private cachedLines: string[] = [];
328
+ private version = 0;
329
+ private cachedVersion = -1;
330
+
331
+ constructor(
332
+ tui: { requestRender: () => void },
333
+ theme: any,
334
+ token: string,
335
+ onClose: () => void,
336
+ ) {
337
+ this.tui = tui;
338
+ this.theme = theme;
339
+ this.token = token;
340
+ this.onClose = onClose;
341
+
342
+ // Initial fetch
343
+ this.doRefresh();
344
+
345
+ // Auto-refresh every 30 seconds
346
+ this.autoRefreshInterval = setInterval(() => this.doRefresh(), 30000);
347
+
348
+ // Tick the "last refreshed" counter every second
349
+ this.tickInterval = setInterval(() => {
350
+ if (this.lastRefreshTime > 0) {
351
+ this.lastRefreshAgo = Math.floor((Date.now() - this.lastRefreshTime) / 1000);
352
+ this.version++;
353
+ this.tui.requestRender();
354
+ }
355
+ }, 1000);
356
+ }
357
+
358
+ private async doRefresh(): Promise<void> {
359
+ this.isLoading = true;
360
+ this.errorMessage = "";
361
+ this.version++;
362
+ this.tui.requestRender();
363
+
364
+ try {
365
+ const quota = await fetchQuota(this.token);
366
+ this.quotaData = quota;
367
+ this.lastRefreshTime = Date.now();
368
+ this.lastRefreshAgo = 0;
369
+ this.isLoading = false;
370
+ } catch (e) {
371
+ this.isLoading = false;
372
+ this.errorMessage = e instanceof Error ? e.message : String(e);
373
+ }
374
+ this.version++;
375
+ this.tui.requestRender();
376
+ }
377
+
378
+ private dispose(): void {
379
+ if (this.autoRefreshInterval) clearInterval(this.autoRefreshInterval);
380
+ if (this.tickInterval) clearInterval(this.tickInterval);
381
+ }
382
+
383
+ handleInput(data: string): void {
384
+ if (matchesKey(data, "q") || matchesKey(data, "escape")) {
385
+ this.dispose();
386
+ this.onClose();
387
+ } else if (matchesKey(data, "r")) {
388
+ this.doRefresh();
389
+ } else if (data === "?") {
390
+ this.showHelp = !this.showHelp;
391
+ this.version++;
392
+ this.tui.requestRender();
393
+ }
394
+ }
395
+
396
+ render(width: number): string[] {
397
+ if (this.cachedVersion === this.version && this.cachedWidth === width) {
398
+ return this.cachedLines;
399
+ }
400
+
401
+ const theme = this.theme;
402
+ const lines: string[] = [];
403
+
404
+ // Top border
405
+ lines.push(theme.fg("border", "─".repeat(width)));
406
+
407
+ // Header
408
+ const planType = this.quotaData?.planType ?? "pro";
409
+ const title = theme.bold("✨ Claude Usage Monitor") + " " + theme.fg("accent", `[${planType.toUpperCase()}]`);
410
+ let status: string;
411
+ if (this.errorMessage) {
412
+ status = theme.fg("error", `! ${this.errorMessage}`);
413
+ } else if (this.isLoading) {
414
+ status = theme.fg("dim", "⟳ loading...");
415
+ } else if (this.lastRefreshAgo === 0) {
416
+ status = theme.fg("success", "⟳ just now");
417
+ } else {
418
+ status = theme.fg("dim", `⟳ ${this.lastRefreshAgo}s ago`);
419
+ }
420
+
421
+ const titleWidth = visibleWidth(title);
422
+ const statusWidth = visibleWidth(status);
423
+ const gap = Math.max(1, width - titleWidth - statusWidth - 4);
424
+ lines.push(" " + title + " ".repeat(gap) + status + " ");
425
+ lines.push(theme.fg("border", "─".repeat(width)));
426
+
427
+ if (this.showHelp) {
428
+ // Help screen
429
+ lines.push("");
430
+ lines.push(theme.bold(" Keybindings"));
431
+ lines.push("");
432
+ lines.push(" " + theme.fg("accent", "q / Esc") + " — Close dashboard");
433
+ lines.push(" " + theme.fg("accent", "r") + " — Force refresh");
434
+ lines.push(" " + theme.fg("accent", "?") + " — Toggle help");
435
+ lines.push("");
436
+ } else if (!this.quotaData && this.isLoading) {
437
+ // Loading state
438
+ lines.push("");
439
+ lines.push(" " + theme.fg("dim", "Loading quota data..."));
440
+ lines.push("");
441
+ } else if (!this.quotaData && this.errorMessage) {
442
+ // Error state
443
+ lines.push("");
444
+ lines.push(" " + theme.fg("error", this.errorMessage));
445
+ lines.push("");
446
+ } else if (this.quotaData) {
447
+ // Donut charts side by side
448
+ const fiveHourLines = renderDonut(
449
+ this.quotaData.fiveHourUsagePct,
450
+ "5-Hour Quota",
451
+ this.quotaData.fiveHourResetTime,
452
+ theme,
453
+ );
454
+ const sevenDayLines = renderDonut(
455
+ this.quotaData.sevenDayUsagePct,
456
+ "Weekly Quota",
457
+ this.quotaData.sevenDayResetTime,
458
+ theme,
459
+ );
460
+
461
+ // Determine chart widths
462
+ const chartWidth = Math.max(...fiveHourLines.map(l => visibleWidth(l)), ...sevenDayLines.map(l => visibleWidth(l)));
463
+ const gapBetween = 6;
464
+ const totalChartsWidth = chartWidth * 2 + gapBetween;
465
+ const leftPad = Math.max(2, Math.floor((width - totalChartsWidth) / 2));
466
+
467
+ const maxLines = Math.max(fiveHourLines.length, sevenDayLines.length);
468
+ lines.push("");
469
+ for (let i = 0; i < maxLines; i++) {
470
+ const left = fiveHourLines[i] ?? "";
471
+ const right = sevenDayLines[i] ?? "";
472
+ const leftPadded = left + " ".repeat(Math.max(0, chartWidth - visibleWidth(left)));
473
+ const row = " ".repeat(leftPad) + leftPadded + " ".repeat(gapBetween) + right;
474
+ lines.push(truncateToWidth(row, width));
475
+ }
476
+ lines.push("");
477
+
478
+ // Model quotas
479
+ const modelLines = renderModelQuotas(this.quotaData, theme, width);
480
+ if (modelLines.length > 0) {
481
+ lines.push(theme.fg("border", "─".repeat(width)));
482
+ for (const ml of modelLines) {
483
+ lines.push(truncateToWidth(ml, width));
484
+ }
485
+ lines.push("");
486
+ }
487
+ }
488
+
489
+ // Footer
490
+ lines.push(theme.fg("border", "─".repeat(width)));
491
+ const helpText = theme.fg("dim", "q: Close r: Refresh ?: Help");
492
+ lines.push(" " + helpText);
493
+
494
+ this.cachedLines = lines;
495
+ this.cachedWidth = width;
496
+ this.cachedVersion = this.version;
497
+ return lines;
498
+ }
499
+
500
+ invalidate(): void {
501
+ this.cachedWidth = 0;
502
+ this.cachedVersion = -1;
503
+ }
504
+ }
505
+
181
506
  // ---------------------------------------------------------------------------
182
507
  // Extension entry point
183
508
  // ---------------------------------------------------------------------------
184
509
 
185
510
  export default function (pi: ExtensionAPI) {
186
- // /claudemon command — show quota inline or launch TUI
511
+ // /claudemon command — show quota inline or launch TUI dashboard
187
512
  pi.registerCommand("claudemon", {
188
513
  description: "Show Claude usage quota (--tui to launch dashboard)",
189
514
  handler: async (args, ctx) => {
190
515
  const trimmed = (args ?? "").trim();
191
516
 
192
- // --tui flag: launch the full TUI dashboard
517
+ // --tui flag: launch the native pi TUI dashboard
193
518
  if (trimmed === "--tui" || trimmed === "-t") {
194
- const result = await pi.exec("npx", ["claudemon"], { timeout: 300000 });
195
- if (result.code !== 0 && result.stderr) {
196
- ctx.ui.notify(`claudemon exited with error: ${result.stderr.slice(0, 200)}`, "error");
519
+ const token = getOAuthToken();
520
+ if (!token) {
521
+ ctx.ui.notify(
522
+ "Not authenticated. Run `claudemon setup` or `npx claudemon setup` first.",
523
+ "error",
524
+ );
525
+ return;
197
526
  }
527
+
528
+ await ctx.ui.custom<void>((tui, theme, _keybindings, done) => {
529
+ const dashboard = new ClaudemonDashboard(tui, theme, token, () => done());
530
+ return {
531
+ render: (w: number) => dashboard.render(w),
532
+ invalidate: () => dashboard.invalidate(),
533
+ handleInput: (data: string) => dashboard.handleInput(data),
534
+ };
535
+ });
536
+
198
537
  return;
199
538
  }
200
539
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemon",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Claude Usage Monitor TUI - monitor your Claude usage in real-time",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",