quotacap 0.0.47 → 0.0.49

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.
@@ -7,7 +7,12 @@ export function parseClaudeUsage(result, now = new Date()) {
7
7
  result.match(/Current week[^\d%]*(\d+)%\s+used/i);
8
8
  const usedPct = weeklyMatch ? parseInt(weeklyMatch[1], 10) : 0;
9
9
  const sessionPct = sessionMatch ? parseInt(sessionMatch[1], 10) : undefined;
10
- let resetsAt = parseResetText(result, now);
10
+ // The paced window's reset lives on the "Current week" line. Parse that
11
+ // line alone: within ~5h of the weekly roll the session reset is sooner,
12
+ // and whole-text farthest-wins would pick it instead (muse precedent:
13
+ // scope to the weekly section, then degrade to +7d when it won't parse).
14
+ const weeklyLine = result.match(/^.*current week.*$/gim)?.[0];
15
+ let resetsAt = parseResetText(weeklyLine ?? result, now);
11
16
  const parsedReset = !!resetsAt;
12
17
  if (!resetsAt)
13
18
  resetsAt = new Date(now.getTime() + 7 * 86400000).toISOString();
@@ -2,7 +2,15 @@ import { parseResetText } from "./parse.js";
2
2
  export function parseManualUsage(provider, text, now = new Date()) {
3
3
  const m = text.match(/(\d+)% used/);
4
4
  const usedPct = m ? parseInt(m[1], 10) : 0;
5
- const parsedReset = parseResetText(text, now);
5
+ // Prefer the weekly line's reset: within ~5h of the weekly roll the 5h
6
+ // reset is sooner, and whole-text farthest-wins would pick it instead.
7
+ // Fall back to whole-text only when the weekly line states no reset at
8
+ // all (e.g. a paste with the reset on its own line).
9
+ const weeklyLine = text.match(/^.*(?:current week|weekly).*$/gim)?.[0];
10
+ let parsedReset = weeklyLine ? parseResetText(weeklyLine, now) : null;
11
+ if (!parsedReset && (!weeklyLine || !/resets/i.test(weeklyLine))) {
12
+ parsedReset = parseResetText(text, now);
13
+ }
6
14
  const resetsAt = parsedReset ?? new Date(now.getTime() + 3 * 86400000).toISOString();
7
15
  const periodStart = (parsedReset ? new Date(new Date(resetsAt).getTime() - 7 * 86400000) : new Date(now.getTime() - 7 * 86400000)).toISOString();
8
16
  let sessionPct;
@@ -60,9 +60,11 @@ function parseRelativeDuration(raw, now) {
60
60
  return new Date(now.getTime() + ms);
61
61
  }
62
62
  export function parseResetText(text, now) {
63
- // Farthest future reset wins. Claude output lists the session reset before
64
- // the weekly one; kimi lists the weekly window before its 5h rolling one —
65
- // the period reset is always the farthest, so one rule serves both.
63
+ // Farthest future reset wins across the given text. Callers whose output
64
+ // carries two windows must pre-scope to the paced window's line first —
65
+ // near the weekly roll the session reset is sooner, so whole-text
66
+ // farthest-wins would pick the wrong one (claude/manual scope; kimi/muse
67
+ // pass pre-scoped snippets).
66
68
  const matches = [...text.matchAll(/resets\s+([^\n(]+?)\s*(?:\(|$)/gm)];
67
69
  let best = null;
68
70
  for (const m of matches) {
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // generated by scripts/build-embed.mjs — do not edit
2
- export const VERSION = "0.0.47";
2
+ export const VERSION = "0.0.49";
@@ -13,6 +13,8 @@ export const STEM_PX = 14;
13
13
  const RAIL_REF_PX = 1072;
14
14
  /** Gap kept between dodged pills. */
15
15
  const DODGE_GAP_PX = 6;
16
+ /** Computed overlap tolerated before pins dodge; pills may touch slightly. */
17
+ const GROUP_OVERLAP_TOL_PX = 10;
16
18
  /** Widest one dodge group may spread; past this pills shingle with overlap. */
17
19
  const MAX_GROUP_SPREAD_PX = 160;
18
20
  /** Half the pill width for a display name: 16ch cap, ~7px per char + chrome. */
@@ -142,7 +144,7 @@ export function placePins(rows, asOf, opts) {
142
144
  edge = -Infinity;
143
145
  };
144
146
  for (const slot of lane) {
145
- if (slot.x - slot.half > edge + DODGE_GAP_PX)
147
+ if (slot.x - slot.half > edge - GROUP_OVERLAP_TOL_PX)
146
148
  flush();
147
149
  group.push(slot);
148
150
  edge = Math.max(edge, slot.x + slot.half);
@@ -171,6 +173,18 @@ export function placePins(rows, asOf, opts) {
171
173
  s.target.offsetPx = centers[i] + shift - s.x;
172
174
  });
173
175
  }
176
+ // Singletons near the edges shift just enough to stay on the rail; the
177
+ // diagonal stem reconnects the pill to its dot. Groups already clamp.
178
+ for (const s of lane) {
179
+ if (s.target.offsetPx !== 0)
180
+ continue;
181
+ const left = s.x - s.half;
182
+ const right = s.x + s.half;
183
+ if (left < 0)
184
+ s.target.offsetPx = -left;
185
+ else if (right > width)
186
+ s.target.offsetPx = width - right;
187
+ }
174
188
  }
175
189
  for (const item of items) {
176
190
  if (item.kind === "pin")