agentacta 1.3.0 → 1.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/app.js +57 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentacta",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Audit trail and search engine for AI agent sessions",
5
5
  "main": "index.js",
6
6
  "bin": {
package/public/app.js CHANGED
@@ -49,6 +49,7 @@ function dlExport(url, filename) {
49
49
 
50
50
  function fmtTokens(n) {
51
51
  if (!n) return '0';
52
+ if (n >= 1_000_000_000) return (n / 1_000_000_000).toFixed(4) + 'B';
52
53
  if (n >= 1_000_000) return (n / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'M';
53
54
  if (n >= 1_000) return (n / 1_000).toFixed(1).replace(/\.0$/, '') + 'K';
54
55
  return n.toLocaleString();
@@ -94,6 +95,50 @@ function transitionView() {
94
95
  content.classList.add('view-enter');
95
96
  }
96
97
 
98
+ // --- Hash routing ---
99
+ window._navDepth = 0;
100
+
101
+ function setHash(hash, replace) {
102
+ const target = '#' + hash;
103
+ if (window.location.hash === target) return;
104
+ if (replace) {
105
+ history.replaceState(null, '', target);
106
+ } else {
107
+ history.pushState(null, '', target);
108
+ window._navDepth++;
109
+ }
110
+ }
111
+
112
+ function updateNavActive(view) {
113
+ $$('.nav-item').forEach(i => i.classList.remove('active'));
114
+ const navItem = $(`.nav-item[data-view="${view}"]`);
115
+ if (navItem) navItem.classList.add('active');
116
+ }
117
+
118
+ function handleRoute() {
119
+ const raw = (window.location.hash || '').slice(1) || 'search';
120
+ if (window._sseCleanup) { window._sseCleanup(); window._sseCleanup = null; }
121
+
122
+ if (raw.startsWith('session/')) {
123
+ const id = decodeURIComponent(raw.slice('session/'.length));
124
+ if (id) { viewSession(id); return; }
125
+ }
126
+
127
+ const view = raw === 'sessions' || raw === 'timeline' || raw === 'files' || raw === 'stats' ? raw : 'search';
128
+ window._lastView = view;
129
+ updateNavActive(view);
130
+ if (view === 'sessions') viewSessions();
131
+ else if (view === 'files') viewFiles();
132
+ else if (view === 'timeline') viewTimeline();
133
+ else if (view === 'stats') viewStats();
134
+ else viewSearch(window._lastSearchQuery || '');
135
+ }
136
+
137
+ window.addEventListener('popstate', () => {
138
+ if (window._navDepth > 0) window._navDepth--;
139
+ handleRoute();
140
+ });
141
+
97
142
  function renderEvent(ev) {
98
143
  const badge = `<span class="event-badge ${badgeClass(ev.type, ev.role)}">${ev.type === 'tool_call' ? 'tool' : ev.role || ev.type}</span>`;
99
144
  let body = '';
@@ -385,6 +430,7 @@ async function viewSessions() {
385
430
  async function viewSession(id) {
386
431
  if (window._sseCleanup) { window._sseCleanup(); window._sseCleanup = null; }
387
432
  window._currentSessionId = id;
433
+ setHash('session/' + encodeURIComponent(id));
388
434
  window.scrollTo(0, 0);
389
435
  const data = await api(`/sessions/${id}`);
390
436
 
@@ -469,12 +515,13 @@ async function viewSession(id) {
469
515
  }
470
516
 
471
517
  $('#backBtn').addEventListener('click', () => {
472
- if (onScroll) { window.removeEventListener('scroll', onScroll); onScroll = null; }
473
- if (window._sseCleanup) { window._sseCleanup(); window._sseCleanup = null; }
474
- if (window._lastView === 'timeline') viewTimeline();
475
- else if (window._lastView === 'files') viewFiles();
476
- else if (window._lastView === 'search') viewSearch(window._lastSearchQuery || '');
477
- else viewSessions();
518
+ if (window._navDepth > 0) {
519
+ history.back();
520
+ } else {
521
+ const view = window._lastView || 'sessions';
522
+ setHash(view, true);
523
+ handleRoute();
524
+ }
478
525
  });
479
526
 
480
527
  $('#copySessionId').addEventListener('click', async () => {
@@ -603,6 +650,7 @@ async function viewSession(id) {
603
650
  window.addEventListener('scroll', sseScrollHandler, { passive: true });
604
651
 
605
652
  window._sseCleanup = () => {
653
+ if (onScroll) { window.removeEventListener('scroll', onScroll); onScroll = null; }
606
654
  clearInterval(pollInterval);
607
655
  window.removeEventListener('scroll', sseScrollHandler);
608
656
  const ind = document.getElementById('newEventsIndicator');
@@ -906,10 +954,10 @@ window._lastView = 'sessions';
906
954
  $$('.nav-item').forEach(item => {
907
955
  item.addEventListener('click', () => {
908
956
  if (window._sseCleanup) { window._sseCleanup(); window._sseCleanup = null; }
909
- $$('.nav-item').forEach(i => i.classList.remove('active'));
910
- item.classList.add('active');
911
957
  const view = item.dataset.view;
912
958
  window._lastView = view;
959
+ updateNavActive(view);
960
+ setHash(view);
913
961
  if (view === 'search') viewSearch();
914
962
  else if (view === 'sessions') viewSessions();
915
963
  else if (view === 'files') viewFiles();
@@ -918,7 +966,7 @@ $$('.nav-item').forEach(item => {
918
966
  });
919
967
  });
920
968
 
921
- viewSearch();
969
+ handleRoute();
922
970
 
923
971
  // Swipe right from left edge to go back
924
972
  (function initSwipeBack() {