@raquezha/notrace 0.1.1 → 0.2.0

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/notrace/index.d.ts +34 -0
  3. package/dist/notrace/index.js +144 -118
  4. package/dist/notrace/report-app/__tests__/analytics.test.d.ts +1 -0
  5. package/dist/notrace/report-app/__tests__/analytics.test.js +35 -0
  6. package/dist/notrace/report-app/__tests__/card.test.d.ts +1 -0
  7. package/dist/notrace/report-app/__tests__/card.test.js +26 -0
  8. package/dist/notrace/report-app/__tests__/event.test.d.ts +1 -0
  9. package/dist/notrace/report-app/__tests__/event.test.js +20 -0
  10. package/dist/notrace/report-app/__tests__/format.test.d.ts +1 -0
  11. package/dist/notrace/report-app/__tests__/format.test.js +41 -0
  12. package/dist/notrace/report-app/__tests__/report.test.d.ts +1 -0
  13. package/dist/notrace/report-app/__tests__/report.test.js +31 -0
  14. package/dist/notrace/report-app/analytics.d.ts +3 -0
  15. package/dist/notrace/report-app/analytics.js +78 -0
  16. package/dist/notrace/report-app/client.d.ts +2 -0
  17. package/dist/notrace/report-app/client.js +105 -0
  18. package/dist/notrace/report-app/components/card.d.ts +4 -0
  19. package/dist/notrace/report-app/components/card.js +36 -0
  20. package/dist/notrace/report-app/components/dashboard.d.ts +1 -0
  21. package/dist/notrace/report-app/components/dashboard.js +16 -0
  22. package/dist/notrace/report-app/components/event.d.ts +5 -0
  23. package/dist/notrace/report-app/components/event.js +42 -0
  24. package/dist/notrace/report-app/components/message.d.ts +2 -0
  25. package/dist/notrace/report-app/components/message.js +43 -0
  26. package/dist/notrace/report-app/dashboard-report.d.ts +1 -0
  27. package/dist/notrace/report-app/dashboard-report.js +6 -0
  28. package/dist/notrace/report-app/escape.d.ts +1 -0
  29. package/dist/notrace/report-app/escape.js +10 -0
  30. package/dist/notrace/report-app/format.d.ts +13 -0
  31. package/dist/notrace/report-app/format.js +102 -0
  32. package/dist/notrace/report-app/report.d.ts +1 -0
  33. package/dist/notrace/report-app/report.js +29 -0
  34. package/dist/notrace/report-app/shell.d.ts +5 -0
  35. package/dist/notrace/report-app/shell.js +19 -0
  36. package/dist/notrace/report-app/styles.d.ts +1 -0
  37. package/dist/notrace/report-app/styles.js +431 -0
  38. package/dist/notrace/report-app/types.d.ts +28 -0
  39. package/dist/notrace/report-app/types.js +1 -0
  40. package/extensions/notrace/__tests__/ghost-session.test.ts +103 -0
  41. package/extensions/notrace/__tests__/helpers.ts +11 -0
  42. package/extensions/notrace/__tests__/lock-race.test.ts +176 -0
  43. package/extensions/notrace/__tests__/usage-normalization.test.ts +80 -0
  44. package/extensions/notrace/index.ts +160 -124
  45. package/extensions/notrace/report-app/__tests__/analytics.test.ts +41 -0
  46. package/extensions/notrace/report-app/__tests__/card.test.ts +29 -0
  47. package/extensions/notrace/report-app/__tests__/event.test.ts +23 -0
  48. package/extensions/notrace/report-app/__tests__/format.test.ts +46 -0
  49. package/extensions/notrace/report-app/__tests__/report.test.ts +33 -0
  50. package/extensions/notrace/report-app/analytics.ts +79 -0
  51. package/extensions/notrace/report-app/client.ts +106 -0
  52. package/extensions/notrace/report-app/components/card.ts +38 -0
  53. package/extensions/notrace/report-app/components/dashboard.ts +17 -0
  54. package/extensions/notrace/report-app/components/event.ts +39 -0
  55. package/extensions/notrace/report-app/components/message.ts +39 -0
  56. package/extensions/notrace/report-app/dashboard-report.ts +7 -0
  57. package/extensions/notrace/report-app/escape.ts +10 -0
  58. package/extensions/notrace/report-app/format.ts +107 -0
  59. package/extensions/notrace/report-app/report.ts +33 -0
  60. package/extensions/notrace/report-app/shell.ts +24 -0
  61. package/extensions/notrace/report-app/styles.ts +431 -0
  62. package/extensions/notrace/report-app/types.ts +35 -0
  63. package/package.json +4 -2
  64. package/templates/dashboard.sample.html +103 -63
  65. package/templates/dashboard.sample.json +73 -10
  66. package/templates/render-samples.mjs +119 -1
  67. package/templates/session.sample.html +125 -168
  68. package/templates/session.sample.json +66 -7
  69. package/templates/sessions/019ed2ee-1000-76ee-b353-000000000001/notrace.html +125 -163
  70. package/templates/sessions/019ed2ee-1000-76ee-b353-000000000001/notrace.json +50 -0
  71. package/templates/sessions/019ed2ee-1001-76ee-b353-000000000002/notrace.html +125 -162
  72. package/templates/sessions/019ed2ee-1001-76ee-b353-000000000002/notrace.json +50 -0
  73. package/templates/sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.html +125 -163
  74. package/templates/sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.json +50 -0
  75. package/templates/sessions/019ed2ee-massive/notrace.html +498 -0
  76. package/templates/sessions/019ed2ee-massive/notrace.json +14660 -0
  77. package/tsconfig.json +1 -1
  78. package/dist/notrace/renderer.d.ts +0 -4
  79. package/dist/notrace/renderer.js +0 -800
  80. package/extensions/notrace/renderer.ts +0 -810
@@ -1,12 +1,4 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <title>notrace</title>
7
- <link rel="icon" href="data:image/svg+xml,%3Csvg%20width%3D%22100%22%20height%3D%22100%22%20viewBox%3D%220%200%20100%20100%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20role%3D%22img%22%3E%3Ctitle%3Enotrace%20logo%20mark%3C%2Ftitle%3E%3Cdesc%3EA%20wave%20that%20smooths%20into%20a%20flat%20line%2C%20then%20fades%20into%20dots%20%E2%80%94%20color%20shifts%20from%20trace%20orange%20to%20no%20cream%20as%20it%20dissolves.%3C%2Fdesc%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22fadeGrad%22%20x1%3D%220%25%22%20y1%3D%220%25%22%20x2%3D%22100%25%22%20y2%3D%220%25%22%3E%3Cstop%20offset%3D%220%25%22%20stop-color%3D%22%23E2754A%22%2F%3E%3Cstop%20offset%3D%22100%25%22%20stop-color%3D%22%23EDE2D2%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cg%20id%3D%22trace-icon%22%3E%3Cpath%20d%3D%22M6%2C50%20C16%2C18%2026%2C18%2036%2C50%20C46%2C82%2054%2C82%2060%2C50%20C64%2C30%2068%2C30%2071%2C50%22%20fill%3D%22none%22%20stroke%3D%22url(%23fadeGrad)%22%20stroke-width%3D%224%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2274%22%20y1%3D%2250%22%20x2%3D%2279%22%20y2%3D%2250%22%20stroke%3D%22%23D9C9B5%22%20stroke-width%3D%224%22%20stroke-linecap%3D%22round%22%20stroke-opacity%3D%220.6%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%2250%22%20r%3D%222.2%22%20fill%3D%22%23D9C9B5%22%20opacity%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2290%22%20cy%3D%2250%22%20r%3D%221.4%22%20fill%3D%22%23EDE2D2%22%20opacity%3D%220.32%22%2F%3E%3Ccircle%20cx%3D%2294%22%20cy%3D%2250%22%20r%3D%220.9%22%20fill%3D%22%23EDE2D2%22%20opacity%3D%220.15%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
8
- <style>
9
- :root {
1
+ <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>notrace</title><link rel="icon" href="data:image/svg+xml,%3Csvg%20width%3D%22100%22%20height%3D%22100%22%20viewBox%3D%220%200%20100%20100%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20role%3D%22img%22%3E%3Ctitle%3Enotrace%20logo%20mark%3C%2Ftitle%3E%3Cdesc%3EA%20wave%20that%20smooths%20into%20a%20flat%20line%2C%20then%20fades%20into%20dots%20%E2%80%94%20color%20shifts%20from%20trace%20orange%20to%20no%20cream%20as%20it%20dissolves.%3C%2Fdesc%3E%3Cdefs%3E%3ClinearGradient%20id%3D%22fadeGrad%22%20x1%3D%220%25%22%20y1%3D%220%25%22%20x2%3D%22100%25%22%20y2%3D%220%25%22%3E%3Cstop%20offset%3D%220%25%22%20stop-color%3D%22%23E2754A%22%2F%3E%3Cstop%20offset%3D%22100%25%22%20stop-color%3D%22%23EDE2D2%22%2F%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E%3Cg%20id%3D%22trace-icon%22%3E%3Cpath%20d%3D%22M6%2C50%20C16%2C18%2026%2C18%2036%2C50%20C46%2C82%2054%2C82%2060%2C50%20C64%2C30%2068%2C30%2071%2C50%22%20fill%3D%22none%22%20stroke%3D%22url(%23fadeGrad)%22%20stroke-width%3D%224%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2274%22%20y1%3D%2250%22%20x2%3D%2279%22%20y2%3D%2250%22%20stroke%3D%22%23D9C9B5%22%20stroke-width%3D%224%22%20stroke-linecap%3D%22round%22%20stroke-opacity%3D%220.6%22%2F%3E%3Ccircle%20cx%3D%2285%22%20cy%3D%2250%22%20r%3D%222.2%22%20fill%3D%22%23D9C9B5%22%20opacity%3D%220.5%22%2F%3E%3Ccircle%20cx%3D%2290%22%20cy%3D%2250%22%20r%3D%221.4%22%20fill%3D%22%23EDE2D2%22%20opacity%3D%220.32%22%2F%3E%3Ccircle%20cx%3D%2294%22%20cy%3D%2250%22%20r%3D%220.9%22%20fill%3D%22%23EDE2D2%22%20opacity%3D%220.15%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E"><style>:root {
10
2
  --bg: #0c0b0a;
11
3
  --panel: rgba(255,255,255,0.04);
12
4
  --panel-strong: rgba(255,255,255,0.06);
@@ -55,6 +47,30 @@
55
47
  gap: 16px;
56
48
  align-items: start;
57
49
  }
50
+ .hero-split {
51
+ display: grid;
52
+ grid-template-columns: minmax(0, 1fr) auto;
53
+ gap: 16px;
54
+ align-items: start;
55
+ }
56
+ .hero-right {
57
+ display: grid;
58
+ gap: 12px;
59
+ justify-items: end;
60
+ min-width: 0;
61
+ }
62
+ .hero-session {
63
+ display: grid;
64
+ gap: 4px;
65
+ text-align: right;
66
+ min-width: 0;
67
+ }
68
+ .hero-meta {
69
+ display: flex;
70
+ flex-wrap: wrap;
71
+ gap: 8px;
72
+ justify-content: flex-end;
73
+ }
58
74
  .brand { margin-bottom: 10px; }
59
75
  .brand-link {
60
76
  display: inline-flex;
@@ -133,11 +149,52 @@
133
149
  border: 1px solid var(--border);
134
150
  border-radius: 18px;
135
151
  padding: 18px;
152
+ min-width: 0;
136
153
  }
137
154
  .metric-card small { display: block; color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.72rem; font-weight: 700; }
138
- .metric-card strong { display: block; margin-top: 8px; font-size: 1.55rem; }
155
+ .metric-card strong { display: block; margin-top: 8px; font-size: clamp(1rem, 2vw, 1.55rem); overflow-wrap: anywhere; }
139
156
  .panel { padding: 0; overflow: hidden; }
140
157
  .section-title { margin: 0; padding: 20px 22px; border-bottom: 1px solid var(--border); font-size: 1rem; }
158
+ .summary-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
159
+ .kv-grid {
160
+ display: grid;
161
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
162
+ gap: 16px;
163
+ }
164
+ .kv-card {
165
+ background: rgba(0,0,0,0.18);
166
+ border: 1px solid var(--border);
167
+ border-radius: 16px;
168
+ padding: 16px;
169
+ }
170
+ .kv-title {
171
+ font-size: 0.72rem;
172
+ text-transform: uppercase;
173
+ color: var(--accent);
174
+ font-weight: 700;
175
+ letter-spacing: 0.08em;
176
+ margin-bottom: 10px;
177
+ }
178
+ .kv-list { display: grid; gap: 8px; }
179
+ .kv-row { display: flex; justify-content: space-between; gap: 12px; align-items: start; }
180
+ .kv-key { color: var(--muted); }
181
+ .kv-value { color: var(--text); text-align: right; word-break: break-word; }
182
+ .tiny-breakdown {
183
+ margin-top: -10px;
184
+ margin-bottom: 8px;
185
+ color: var(--muted);
186
+ font-size: 0.82rem;
187
+ display: flex;
188
+ flex-wrap: wrap;
189
+ gap: 8px 14px;
190
+ }
191
+ .tiny-breakdown strong { color: var(--text); font-size: inherit; font-weight: 600; }
192
+ .collapsible { margin-top: 24px; }
193
+ .collapsible > summary { list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 18px 22px; font-size: 1rem; font-weight: 700; }
194
+ .collapsible > summary::-webkit-details-marker { display: none; }
195
+ .collapsible > summary:hover { background: rgba(255,255,255,0.02); }
196
+ .collapsible > summary::after { content: "▾"; color: var(--muted); font-size: 0.9rem; }
197
+ .collapsible:not([open]) > summary::after { content: "▸"; }
141
198
  .empty { padding: 32px 22px; color: var(--muted); }
142
199
  table { width: 100%; border-collapse: collapse; }
143
200
  th, td { padding: 14px 18px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
@@ -279,6 +336,8 @@
279
336
  margin: 0;
280
337
  background: transparent;
281
338
  border: none;
339
+ max-height: 400px;
340
+ overflow-y: auto;
282
341
  }
283
342
  .footer-note {
284
343
  margin-top: 22px;
@@ -333,61 +392,43 @@
333
392
  border-color: rgba(216,132,98,0.45);
334
393
  background: var(--accent-soft);
335
394
  }
395
+ .back-to-top {
396
+ position: fixed;
397
+ right: 20px;
398
+ bottom: 20px;
399
+ z-index: 20;
400
+ display: inline-flex;
401
+ align-items: center;
402
+ gap: 8px;
403
+ padding: 10px 14px;
404
+ border: 1px solid var(--border);
405
+ border-radius: 999px;
406
+ background: rgba(12,11,10,0.88);
407
+ color: var(--text);
408
+ text-decoration: none;
409
+ box-shadow: var(--shadow);
410
+ backdrop-filter: blur(10px);
411
+ opacity: 0;
412
+ pointer-events: none;
413
+ transform: translateY(8px);
414
+ transition: opacity 160ms ease, transform 160ms ease, border-color 120ms ease, background 120ms ease;
415
+ }
416
+ .back-to-top.visible {
417
+ opacity: 1;
418
+ pointer-events: auto;
419
+ transform: translateY(0);
420
+ }
421
+ .back-to-top:hover { border-color: rgba(216,132,98,0.45); background: rgba(216,132,98,0.12); }
336
422
  .container { padding: 20px 14px 48px; }
337
423
  .hero { padding: 20px; }
338
- .hero-top { grid-template-columns: 1fr; }
339
- .meta { justify-content: flex-start; margin-top: 8px; }
340
- .wordmark { width: 280px; height: 92px; }
424
+ .hero-top, .hero-split { grid-template-columns: 1fr; }
425
+ .meta, .hero-meta { justify-content: flex-start; margin-top: 8px; }
426
+ .hero-right, .hero-session { justify-items: start; text-align: left; }
427
+ .wordmark { width: min(280px, 100%); height: auto; }
428
+ .metrics { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
341
429
  th:nth-child(5), td:nth-child(5) { display: none; }
342
430
  .event summary { align-items: flex-start; }
343
- }
344
- </style>
345
- </head>
346
- <body><div class="container">
347
- <section class="hero">
348
- <div class="hero-split">
349
- <a class="brand-link" href="index.html"><svg class="wordmark" viewBox="0 0 420 138" aria-label="notrace" role="img" xmlns="http://www.w3.org/2000/svg">
350
- <defs>
351
- <linearGradient id="fadeGrad" x1="0%" y1="0%" x2="100%" y2="0%">
352
- <stop offset="0%" stop-color="#E2754A"/>
353
- <stop offset="100%" stop-color="#EDE2D2"/>
354
- </linearGradient>
355
- </defs>
356
- <g id="trace-icon" transform="translate(1 -18) scale(0.93)">
357
- <path d="M6,50 C16,18 26,18 36,50 C46,82 54,82 60,50 C64,30 68,30 71,50"
358
- fill="none" stroke="url(#fadeGrad)" stroke-width="4" stroke-linecap="round"/>
359
- <line x1="74" y1="50" x2="79" y2="50" stroke="#D9C9B5" stroke-width="4" stroke-linecap="round" stroke-opacity="0.6"/>
360
- <circle cx="85" cy="50" r="2.2" fill="#D9C9B5" opacity="0.5"/>
361
- <circle cx="90" cy="50" r="1.4" fill="#EDE2D2" opacity="0.32"/>
362
- <circle cx="94" cy="50" r="0.9" fill="#EDE2D2" opacity="0.15"/>
363
- </g>
364
- <text x="0" y="114" fill="#ECE3DA" style="fill:#ECE3DA" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">no</text>
365
- <text x="82" y="114" fill="#d88462" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">trace</text>
366
- </svg></a>
367
- <div class="hero-right">
368
- <div class="hero-session">
369
- <strong style="color: var(--text); font-weight: 500;">Global Index</strong>
370
- <span style="color: var(--muted);">Machine-wide session evidence.</span>
371
- </div>
372
- <div class="hero-meta">
373
- <span class="hero-pill">3 sessions</span>
374
- </div>
375
- </div>
376
- </div>
377
- <div class="metrics">
378
- <div class="metric-card"><small>Sessions</small><strong>3</strong></div>
379
- <div class="metric-card"><small>Total Tokens</small><strong>15,174</strong></div>
380
- <div class="metric-card"><small>Total Cost</small><strong>$0.08050</strong></div>
381
- </div>
382
- </section>
383
- <section class="panel">
384
- <h2 class="section-title">Session Reports</h2>
385
- <table data-dashboard-table><thead><tr><th class="col-index sortable-head"><button class="sort-btn" data-sort-key="index"><span class="sort-label">#</span><span class="sort-state">↓</span></button></th><th>Session</th><th>Project</th><th class="sortable-head"><button class="sort-btn" data-sort-key="workflow"><span class="sort-label">Workflow</span><span class="sort-state"></span></button></th><th class="sortable-head"><button class="sort-btn" data-sort-key="started"><span class="sort-label">Started</span><span class="sort-state"></span></button></th><th>Task</th><th class="sortable-head num-cell"><button class="sort-btn" data-sort-key="tokens"><span class="sort-label">Tokens</span><span class="sort-state"></span></button></th><th class="sortable-head num-cell"><button class="sort-btn" data-sort-key="cost"><span class="sort-label">Cost</span><span class="sort-state"></span></button></th></tr></thead><tbody>
386
- <tr data-index="3" data-workflow="Generic" data-started="1781691240000" data-tokens="5910" data-cost="0.0334"><td class="index-cell">3</td><td><a class="session-link" href="sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.html"><strong>019ed2ee</strong><span class="session-sub">019ed2ee-1002-76ee-b353-000000000003</span></a></td><td><span class="hero-pill">Unknown</span></td><td><span class="workflow-pill workflow-generic">Generic</span></td><td><div class="date-cell"><strong>2026-06-17</strong><span>18:14</span></div></td><td>General session</td><td class="num-cell">5,910</td><td class="num-cell">$0.03340</td></tr><tr data-index="2" data-workflow="Research" data-started="1781689020000" data-tokens="5754" data-cost="0.0267"><td class="index-cell">2</td><td><a class="session-link" href="sessions/019ed2ee-1001-76ee-b353-000000000002/notrace.html"><strong>019ed2ee</strong><span class="session-sub">019ed2ee-1001-76ee-b353-000000000002</span></a></td><td><span class="hero-pill">Unknown</span></td><td><span class="workflow-pill workflow-research">Research</span></td><td><div class="date-cell"><strong>2026-06-17</strong><span>17:37</span></div></td><td>Branch topic-02</td><td class="num-cell">5,754</td><td class="num-cell">$0.02670</td></tr><tr data-index="1" data-workflow="RPIV" data-started="1781686800000" data-tokens="3510" data-cost="0.0204"><td class="index-cell">1</td><td><a class="session-link" href="sessions/019ed2ee-1000-76ee-b353-000000000001/notrace.html"><strong>019ed2ee</strong><span class="session-sub">019ed2ee-1000-76ee-b353-000000000001</span></a></td><td><span class="hero-pill">Unknown</span></td><td><span class="workflow-pill workflow-rpiv">RPIV</span></td><td><div class="date-cell"><strong>2026-06-17</strong><span>17:00</span></div></td><td>NR-101</td><td class="num-cell">3,510</td><td class="num-cell">$0.02040</td></tr>
387
- </tbody></table>
388
- </section>
389
- <footer class="footer-note minimal">notrace • raquezha 2026</footer>
390
- </div><script>(() => {
431
+ }</style></head><body><div class="container"><section class="hero"><div class="hero-split"><a class="brand-link" href="index.html"><svg class="wordmark" viewBox="0 0 420 138" aria-label="notrace" role="img" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="fadeGrad" x1="0%" y1="0%" x2="100%" y2="0%"><stop offset="0%" stop-color="#E2754A"/><stop offset="100%" stop-color="#EDE2D2"/></linearGradient></defs><g id="trace-icon" transform="translate(1 -18) scale(0.93)"><path d="M6,50 C16,18 26,18 36,50 C46,82 54,82 60,50 C64,30 68,30 71,50" fill="none" stroke="url(#fadeGrad)" stroke-width="4" stroke-linecap="round"/><line x1="74" y1="50" x2="79" y2="50" stroke="#D9C9B5" stroke-width="4" stroke-linecap="round" stroke-opacity="0.6"/><circle cx="85" cy="50" r="2.2" fill="#D9C9B5" opacity="0.5"/><circle cx="90" cy="50" r="1.4" fill="#EDE2D2" opacity="0.32"/><circle cx="94" cy="50" r="0.9" fill="#EDE2D2" opacity="0.15"/></g><text x="0" y="114" fill="#ECE3DA" style="fill:#ECE3DA" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">no</text><text x="82" y="114" fill="#d88462" font-family="Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif" font-size="96" font-weight="900" letter-spacing="-7">trace</text></svg></a><div class="hero-right"><div class="hero-session"><strong style="color: var(--text); font-weight: 500;">Global Index</strong><span style="color: var(--muted);">Machine-wide session evidence.</span></div><div class="hero-meta"><span class="hero-pill">4 sessions</span></div></div></div><div class="metrics"><div class="metric-card"><small>Sessions</small><strong>4</strong></div><div class="metric-card"><small>Total Tokens</small><strong>5,115,174</strong></div><div class="metric-card"><small>Total Cost</small><strong>$75.58050</strong></div></div></section><section class="panel"><h2 class="section-title">Session Reports</h2><table data-dashboard-table><thead><tr><th class="col-index sortable-head"><button class="sort-btn" data-sort-key="index"><span class="sort-label">#</span><span class="sort-state">↓</span></button></th><th>Session</th><th>Project</th><th class="sortable-head"><button class="sort-btn" data-sort-key="workflow"><span class="sort-label">Workflow</span><span class="sort-state"></span></button></th><th class="sortable-head"><button class="sort-btn" data-sort-key="started"><span class="sort-label">Started</span><span class="sort-state"></span></button></th><th>Task</th><th class="sortable-head num-cell"><button class="sort-btn" data-sort-key="tokens"><span class="sort-label">Tokens</span><span class="sort-state"></span></button></th><th class="sortable-head num-cell"><button class="sort-btn" data-sort-key="cost"><span class="sort-label">Cost</span><span class="sort-state"></span></button></th></tr></thead><tbody><tr data-index="4" data-workflow="Generic" data-started="1781784000000" data-tokens="5100000" data-cost="75.5"><td class="index-cell">4</td><td><a class="session-link" href="sessions/019ed2ee-massive/notrace.html"><strong>019ed2ee</strong><span class="session-sub">019ed2ee-massive</span></a></td><td><span class="hero-pill">Unknown</span></td><td><span class="workflow-pill workflow-generic">Generic</span></td><td><div class="date-cell"><strong>2026-06-18</strong><span>20:00</span></div></td><td>test-massive</td><td class="num-cell">5,100,000</td><td class="num-cell">$75.50000</td></tr><tr data-index="3" data-workflow="Generic" data-started="1781691240000" data-tokens="5910" data-cost="0.0334"><td class="index-cell">3</td><td><a class="session-link" href="sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.html"><strong>019ed2ee</strong><span class="session-sub">019ed2ee-1002-76ee-b353-000000000003</span></a></td><td><span class="hero-pill">Unknown</span></td><td><span class="workflow-pill workflow-generic">Generic</span></td><td><div class="date-cell"><strong>2026-06-17</strong><span>18:14</span></div></td><td>General session</td><td class="num-cell">5,910</td><td class="num-cell">$0.03340</td></tr><tr data-index="2" data-workflow="Research" data-started="1781689020000" data-tokens="5754" data-cost="0.0267"><td class="index-cell">2</td><td><a class="session-link" href="sessions/019ed2ee-1001-76ee-b353-000000000002/notrace.html"><strong>019ed2ee</strong><span class="session-sub">019ed2ee-1001-76ee-b353-000000000002</span></a></td><td><span class="hero-pill">Unknown</span></td><td><span class="workflow-pill workflow-research">Research</span></td><td><div class="date-cell"><strong>2026-06-17</strong><span>17:37</span></div></td><td>Branch topic-02</td><td class="num-cell">5,754</td><td class="num-cell">$0.02670</td></tr><tr data-index="1" data-workflow="RPIV" data-started="1781686800000" data-tokens="3510" data-cost="0.0204"><td class="index-cell">1</td><td><a class="session-link" href="sessions/019ed2ee-1000-76ee-b353-000000000001/notrace.html"><strong>019ed2ee</strong><span class="session-sub">019ed2ee-1000-76ee-b353-000000000001</span></a></td><td><span class="hero-pill">Unknown</span></td><td><span class="workflow-pill workflow-rpiv">RPIV</span></td><td><div class="date-cell"><strong>2026-06-17</strong><span>17:00</span></div></td><td>NR-101</td><td class="num-cell">3,510</td><td class="num-cell">$0.02040</td></tr></tbody></table></section><footer class="footer-note minimal">notrace • raquezha 2026</footer></div><script>(() => {
391
432
  const table = document.querySelector('[data-dashboard-table]');
392
433
  if (!table) return;
393
434
  const tbody = table.querySelector('tbody');
@@ -439,5 +480,4 @@
439
480
  });
440
481
 
441
482
  sortBy(currentKey);
442
- })();</script></body>
443
- </html>
483
+ })();</script></body></html>
@@ -13,9 +13,16 @@
13
13
  "dir": "/repo/.workflow/tasks/NR-101"
14
14
  },
15
15
  "conditions": {
16
- "models": ["gpt-5.4"],
17
- "providers": ["openai"],
18
- "extensions": ["notrace", "noheadroom"]
16
+ "models": [
17
+ "gpt-5.4"
18
+ ],
19
+ "providers": [
20
+ "openai"
21
+ ],
22
+ "extensions": [
23
+ "notrace",
24
+ "noheadroom"
25
+ ]
19
26
  },
20
27
  "activity": {
21
28
  "turnCount": 4,
@@ -49,9 +56,15 @@
49
56
  "dir": null
50
57
  },
51
58
  "conditions": {
52
- "models": ["claude-sonnet-4"],
53
- "providers": ["anthropic"],
54
- "extensions": ["notrace"]
59
+ "models": [
60
+ "claude-sonnet-4"
61
+ ],
62
+ "providers": [
63
+ "anthropic"
64
+ ],
65
+ "extensions": [
66
+ "notrace"
67
+ ]
55
68
  },
56
69
  "activity": {
57
70
  "turnCount": 5,
@@ -85,9 +98,16 @@
85
98
  "dir": null
86
99
  },
87
100
  "conditions": {
88
- "models": ["gemini-3.5-flash"],
89
- "providers": ["google"],
90
- "extensions": ["notrace", "noheadroom"]
101
+ "models": [
102
+ "gemini-3.5-flash"
103
+ ],
104
+ "providers": [
105
+ "google"
106
+ ],
107
+ "extensions": [
108
+ "notrace",
109
+ "noheadroom"
110
+ ]
91
111
  },
92
112
  "activity": {
93
113
  "turnCount": 6,
@@ -108,6 +128,49 @@
108
128
  "html": "sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.html",
109
129
  "record": "sessions/019ed2ee-1002-76ee-b353-000000000003/notrace.json"
110
130
  }
131
+ },
132
+ {
133
+ "sessionId": "019ed2ee-massive",
134
+ "startedAt": "2026-06-18T12:00:00.000Z",
135
+ "endedAt": "2026-06-18T13:00:00.000Z",
136
+ "captureMode": "full",
137
+ "task": {
138
+ "workflow": "chaos",
139
+ "id": "test-massive",
140
+ "path": null,
141
+ "dir": null
142
+ },
143
+ "conditions": {
144
+ "models": [
145
+ "claude-opus",
146
+ "gpt-4-turbo"
147
+ ],
148
+ "providers": [
149
+ "multi"
150
+ ],
151
+ "extensions": [
152
+ "notrace"
153
+ ]
154
+ },
155
+ "activity": {
156
+ "turnCount": 50,
157
+ "llmCallCount": 50,
158
+ "toolCallCount": 250,
159
+ "toolErrorCount": 0,
160
+ "durationMs": 3600000,
161
+ "totals": {
162
+ "inputTokens": 5000000,
163
+ "outputTokens": 100000,
164
+ "cacheReadTokens": 0,
165
+ "cacheWriteTokens": 0,
166
+ "totalTokens": 5100000,
167
+ "totalCostUsd": 75.5
168
+ }
169
+ },
170
+ "artifacts": {
171
+ "html": "sessions/019ed2ee-massive/notrace.html",
172
+ "record": "sessions/019ed2ee-massive/notrace.json"
173
+ }
111
174
  }
112
175
  ]
113
- }
176
+ }
@@ -1,25 +1,143 @@
1
1
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
- import { generateDashboardHtml, generateHtmlReport } from "../dist/notrace/renderer.js";
4
+ import { generateDashboardHtml } from "../dist/notrace/report-app/dashboard-report.js";
5
+ import { generateHtmlReport } from "../dist/notrace/report-app/report.js";
5
6
 
6
7
  const here = path.dirname(fileURLToPath(import.meta.url));
7
8
  const dashboardData = JSON.parse(readFileSync(path.join(here, "dashboard.sample.json"), "utf8"));
8
9
  const sessionData = JSON.parse(readFileSync(path.join(here, "session.sample.json"), "utf8"));
9
10
  const repositoryName = dashboardData.repositoryName || sessionData.repository?.name || "nothing";
10
11
 
12
+ function createRng(seed = 42) {
13
+ let state = seed >>> 0;
14
+ return () => {
15
+ state = (state * 1664525 + 1013904223) >>> 0;
16
+ return state / 0x100000000;
17
+ };
18
+ }
19
+
11
20
  writeFileSync(path.join(here, "dashboard.sample.html"), generateDashboardHtml(dashboardData.sessions, { repositoryName }));
12
21
  writeFileSync(path.join(here, "session.sample.html"), generateHtmlReport(sessionData));
13
22
 
14
23
  for (const session of dashboardData.sessions) {
15
24
  const htmlPath = path.join(here, session.artifacts.html);
16
25
  const recordPath = path.join(here, session.artifacts.record);
26
+
27
+
28
+ let sessionEvents = sessionData.events;
29
+ if (session.sessionId === "019ed2ee-massive") {
30
+ sessionEvents = [];
31
+ let ts = 1781705100000;
32
+
33
+ const random = createRng(20260703);
34
+ // Model profiles
35
+ const profiles = [
36
+ { id: "claude-3-5-sonnet", provider: "anthropic", weight: 60, costPerMIn: 3.0, costPerMOut: 15.0 },
37
+ { id: "gpt-4o", provider: "openai", weight: 30, costPerMIn: 5.0, costPerMOut: 15.0 },
38
+ { id: "claude-3-opus", provider: "anthropic", weight: 5, costPerMIn: 15.0, costPerMOut: 75.0 },
39
+ { id: "gemini-1.5-pro", provider: "google", weight: 5, costPerMIn: 3.5, costPerMOut: 10.5 }
40
+ ];
41
+
42
+ function pickModel() {
43
+ const r = random() * 100;
44
+ let sum = 0;
45
+ for (const p of profiles) {
46
+ sum += p.weight;
47
+ if (r <= sum) return p;
48
+ }
49
+ return profiles[0];
50
+ }
51
+
52
+ let baseContext = 4000;
53
+ let contextGrowth = 1.05;
54
+
55
+ let totalIn = 0;
56
+ let totalOut = 0;
57
+ let totalCost = 0;
58
+ let toolCalls = 0;
59
+
60
+ for (let i = 0; i < 140; i++) {
61
+ const model = pickModel();
62
+
63
+ // Context grows naturally as session goes on, with jitter
64
+ baseContext = Math.min(180000, baseContext * contextGrowth);
65
+ let inputTokens = Math.floor(baseContext * (0.8 + random() * 0.4));
66
+ let outputTokens = Math.floor(random() * 800) + 50;
67
+
68
+ // Sometimes Opus reads massive contexts
69
+ if (model.id === "claude-3-opus") inputTokens += 100000;
70
+ // Sometimes Gemini reads huge cache
71
+ if (model.id === "gemini-1.5-pro") inputTokens += 200000;
72
+
73
+ let callCost = (inputTokens / 1_000_000) * model.costPerMIn + (outputTokens / 1_000_000) * model.costPerMOut;
74
+
75
+ totalIn += inputTokens;
76
+ totalOut += outputTokens;
77
+ totalCost += callCost;
78
+
79
+ sessionEvents.push({
80
+ type: "llm_completion",
81
+ model: model.id,
82
+ provider: model.provider,
83
+ inputPayload: { messages: [{role: "user", content: "Organic simulated context..."}] },
84
+ outputContent: "Simulated output generation phase.",
85
+ usage: {
86
+ input: inputTokens,
87
+ output: outputTokens,
88
+ totalTokens: inputTokens + outputTokens,
89
+ cost: { total: callCost }
90
+ },
91
+ timestamp: ts
92
+ });
93
+
94
+ ts += 2000 + random() * 15000; // LLM think time
95
+
96
+ // Generate 0 to 12 tool calls
97
+ const toolsToRun = Math.floor(Math.pow(random(), 1.5) * 12);
98
+ for (let j = 0; j < toolsToRun; j++) {
99
+ toolCalls++;
100
+ const toolName = random() > 0.3 ? "bash" : "read_file";
101
+ const isErr = random() > 0.92;
102
+
103
+ sessionEvents.push({
104
+ type: "tool_start",
105
+ toolName: toolName,
106
+ args: { param: "simulated_arg" },
107
+ timestamp: ts
108
+ });
109
+
110
+ ts += 100 + random() * 3000; // Tool execution time
111
+
112
+ sessionEvents.push({
113
+ type: "tool_end",
114
+ toolName: toolName,
115
+ result: isErr ? { error: "Simulated execution error" } : { stdout: "Success", exitCode: 0 },
116
+ isError: isErr,
117
+ timestamp: ts
118
+ });
119
+ ts += 1000 + random() * 2000; // Wait before next tool
120
+ }
121
+ }
122
+
123
+ // Update dashboard metadata to match the random generation
124
+ session.activity.llmCallCount = 140;
125
+ session.activity.toolCallCount = toolCalls;
126
+ session.activity.totals.inputTokens = totalIn;
127
+ session.activity.totals.outputTokens = totalOut;
128
+ session.activity.totals.totalTokens = totalIn + totalOut;
129
+ session.activity.totals.totalCostUsd = totalCost;
130
+ }
131
+
17
132
  const sessionPage = {
133
+
18
134
  ...sessionData,
19
135
  traceId: session.sessionId,
136
+ events: sessionEvents,
20
137
  session: {
21
138
  ...sessionData.session,
22
139
  id: session.sessionId,
140
+
23
141
  startedAt: session.startedAt,
24
142
  endedAt: session.endedAt,
25
143
  durationMs: session.activity?.durationMs ?? sessionData.session?.durationMs ?? 0,