@maxiaochao/pi-toolkit 0.2.5 → 0.2.6

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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 2026-09-09 - v0.2.6
2
+
3
+ - fix cache export: segment-view tooltip and event markers now show global request numbers (aligned with the x-axis) instead of relative 1-based; e2e asserts real tooltip values
4
+
1
5
  ## 2026-09-09 - v0.2.5
2
6
 
3
7
  - fix cache export: segment views lost the hover tooltip (it rendered inside the hidden all-history section); move to one page-level tooltip; e2e now asserts real rendering
@@ -205,8 +205,12 @@ function lineChart(title, series, opts = {}) {
205
205
  ];
206
206
 
207
207
  const tsAttr = timestamps ? ` data-timestamps="${esc(timestamps.join("|"), true)}"` : "";
208
+ // Global per-request numbers (same length as the series) so a small page
209
+ // script can rewrite tau's relative "Request N" tooltip line to the global
210
+ // number inside segment views (tau hardcodes index + 1).
211
+ const reqAttr = requestNumbers ? ` data-requestnumbers="${esc(requestNumbers.join("|"), true)}"` : "";
208
212
  const parts = [
209
- `<svg class="usage-chart" viewBox="0 0 ${width} ${height}" role="img" aria-label="${esc(title, true)}" data-left="${left}" data-right="${right}" data-count="${count}"${tsAttr}>`,
213
+ `<svg class="usage-chart" viewBox="0 0 ${width} ${height}" role="img" aria-label="${esc(title, true)}" data-left="${left}" data-right="${right}" data-count="${count}"${tsAttr}${reqAttr}>`,
210
214
  `<text class="chart-title" x="${left}" y="24">${esc(title)}</text>`,
211
215
  ];
212
216
  for (let tick = 0; tick < 6; tick++) {
@@ -233,7 +237,10 @@ function lineChart(title, series, opts = {}) {
233
237
  .forEach((event, eventIndex) => {
234
238
  const [x] = point(Math.max(0, Math.min(count - 1, event.requestNumber - 1)), 0);
235
239
  const markerY = top + 7 + (eventIndex % 3) * 9;
236
- const description = `${event.label} before request ${event.requestNumber} at ${event.timestamp}`;
240
+ // data-request stays RELATIVE (tau's tooltip matches index + 1); the human
241
+ // description shows the GLOBAL request number (chartEvents keeps it).
242
+ const shown = event.globalRequestNumber ?? event.requestNumber;
243
+ const description = `${event.label} before request ${shown} at ${event.timestamp}`;
237
244
  parts.push(
238
245
  `<g class="usage-event usage-event-${esc(event.kind, true)}" data-request="${event.requestNumber}" ` +
239
246
  `data-event-info="${esc(description, true)}" role="img" aria-label="${esc(description, true)}">` +
@@ -542,10 +549,14 @@ function eventsForRequests(events, requests) {
542
549
  return events.filter((event) => event.requestNumber >= from && event.requestNumber <= to);
543
550
  }
544
551
 
545
- function chartEvents(events, requests) {
552
+ export function chartEvents(events, requests) {
546
553
  if (!requests.length) return [];
547
554
  const first = requests[0].number;
548
- return events.map((event) => ({ ...event, requestNumber: event.requestNumber - first + 1 }));
555
+ return events.map((event) => ({
556
+ ...event,
557
+ requestNumber: event.requestNumber - first + 1, // relative, for tau's data-request matching
558
+ globalRequestNumber: event.requestNumber, // absolute, for readable labels
559
+ }));
549
560
  }
550
561
 
551
562
  function renderDashboardView(requests, events, toolCalls, compactions, scopeLabel) {
@@ -756,6 +767,23 @@ for (const select of document.querySelectorAll("[data-context-segment-select]"))
756
767
  select.addEventListener("change", show);
757
768
  show();
758
769
  }
770
+ // tau's tooltip hardcodes "Request " + (index + 1), which is relative inside a
771
+ // segment view while the x-axis shows global request numbers. Rewrite the
772
+ // tooltip's leading request number to the chart's global number on hover.
773
+ // Registered after tau's own pointermove listener, so it runs after tau writes.
774
+ document.querySelectorAll(".usage-chart").forEach((chart) => {
775
+ const nums = (chart.dataset.requestnumbers || "").split("|").map(Number);
776
+ chart.addEventListener("pointermove", () => {
777
+ const tooltip = document.querySelector(".usage-tooltip");
778
+ if (!tooltip) return;
779
+ const m = tooltip.textContent.match(/^Request (\\d+)/);
780
+ if (!m) return;
781
+ const global = nums[Number(m[1]) - 1];
782
+ if (global && global !== Number(m[1])) {
783
+ tooltip.textContent = tooltip.textContent.replace(/^Request \\d+/, "Request " + global);
784
+ }
785
+ });
786
+ });
759
787
  </script>
760
788
  </main></body></html>`;
761
789
  }
@@ -269,7 +269,8 @@ async function run() {
269
269
  check("e2e no IndexSizeError / uncaught errors in All view",
270
270
  !allCharts.errs.some((e) => /IndexSizeError|Uncaught/i.test(e)), JSON.stringify(allCharts.errs));
271
271
 
272
- // 3. latest segment view (no internal breaks): full-width tooltips
272
+ // 3. latest segment view (no internal breaks): full-width tooltips aligned
273
+ // to GLOBAL request numbers (fixture segment-4 = requests 40..45)
273
274
  await evalJs(`window.__probe.setView("segment-4")`);
274
275
  const seg4 = await evalJs(`
275
276
  (() => {
@@ -281,9 +282,28 @@ async function run() {
281
282
  check("e2e segment-4 tooltip works at start and end",
282
283
  seg4.near.visible && seg4.far.visible && seg4.farReq !== seg4.nearReq,
283
284
  JSON.stringify(seg4));
285
+ check("e2e segment-4 tooltip aligns to GLOBAL request numbers (40..45, not 1..6)",
286
+ seg4.nearReq === 40 && seg4.farReq === 45,
287
+ JSON.stringify(seg4));
284
288
  check("e2e segment view has no uncaught errors",
285
289
  !seg4.errs.some((e) => /IndexSizeError|Uncaught/i.test(e)), JSON.stringify(seg4.errs));
286
290
 
291
+ // 4. event markers in a segment view keep relative data-request for tau
292
+ // matching but describe the GLOBAL request number
293
+ await evalJs(`window.__probe.setView("segment-2")`);
294
+ const ev = await evalJs(`
295
+ (() => {
296
+ const chart = [...document.querySelectorAll("svg.usage-chart")]
297
+ .find((s) => s.getAttribute("aria-label") === "Prompt input by request" &&
298
+ s.closest(".usage-context-view") && !s.closest(".usage-context-view").hidden);
299
+ const g = chart.querySelector(".usage-event");
300
+ return g ? { dataRequest: g.getAttribute("data-request"), info: g.getAttribute("data-event-info") } : null;
301
+ })()
302
+ `);
303
+ check("e2e segment event marker: data-request relative, description global",
304
+ ev && ev.dataRequest === "1" && ev.info.includes("before request 25"),
305
+ JSON.stringify(ev));
306
+
287
307
  cdp.close();
288
308
  if (usesWindowsChrome && windowsPid) {
289
309
  try { execFileSync("taskkill.exe", ["/PID", String(windowsPid), "/T", "/F"]); } catch { /* best effort */ }
@@ -4,7 +4,7 @@ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import registerCacheExport from "../index.ts";
7
- import { parseEntries, analyzeStreaks, analyzeMisses, buildContextSegments, lineChartForTest, renderDashboard } from "../render.ts";
7
+ import { parseEntries, analyzeStreaks, analyzeMisses, buildContextSegments, lineChartForTest, renderDashboard, chartEvents } from "../render.ts";
8
8
 
9
9
  let pass = 0, fail = 0;
10
10
  function check(name, cond, detail = "") {
@@ -346,6 +346,23 @@ const hitOf = (r) => r.cached / (r.fresh + r.cached + r.cacheWrite);
346
346
  dashboard.slice(0, 500));
347
347
  }
348
348
 
349
+ // P3. segment-view request numbers align to global (tooltip override + event labels)
350
+ {
351
+ const chart = lineChartForTest("seg", [["cached", [1, 2, 3]]], { requestNumbers: [40, 41, 42] });
352
+ check("P3 chart carries global data-requestnumbers", chart.includes('data-requestnumbers="40|41|42"'), chart.slice(0, 220));
353
+ const ev = chartEvents([{ kind: "model", requestNumber: 310, label: "Model changed to b", timestamp: "12:00:00" }], [{ number: 310 }, { number: 311 }, { number: 312 }]);
354
+ check("P3 chartEvents keeps relative requestNumber (tau matching) and global label number",
355
+ ev[0].requestNumber === 1 && ev[0].globalRequestNumber === 310,
356
+ JSON.stringify(ev[0]));
357
+ const labeled = lineChartForTest("seg", [["cached", [1, 2, 3]]], {
358
+ requestNumbers: [310, 311, 312],
359
+ events: [{ kind: "model", requestNumber: 1, label: "Model changed to b", timestamp: "12:00:00", globalRequestNumber: 310 }],
360
+ });
361
+ check("P3 event description shows global request while data-request stays relative",
362
+ labeled.includes("before request 310 at 12:00:00") && labeled.includes('data-request="1"'),
363
+ labeled.slice(0, 700));
364
+ }
365
+
349
366
  // Q. subagent results remain visible as main-session tool input -----------
350
367
  {
351
368
  const entries = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maxiaochao/pi-toolkit",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Personal pi coding agent toolkit: /todos, /btw, /cache_export extensions, browser automation, and bundled theme/skills.",
5
5
  "type": "module",
6
6
  "keywords": [