@phren/cli 0.0.20 → 0.0.22

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.
@@ -588,9 +588,7 @@ export function renderProjectReferenceEnhancementScript(_authToken) {
588
588
  });
589
589
  })();`;
590
590
  }
591
- export function renderReviewQueueEditSyncScript() {
592
- return "";
593
- }
591
+ // renderReviewQueueEditSyncScript removed — was dead code returning ""
594
592
  export function renderTasksAndSettingsScript(authToken) {
595
593
  const safeToken = JSON.stringify(authToken).slice(1, -1);
596
594
  return `(function() {
@@ -606,27 +604,11 @@ export function renderTasksAndSettingsScript(authToken) {
606
604
  return fetch(url).then(function(r) { return r.json(); });
607
605
  }
608
606
 
609
- var _taskViewMode = 'list';
610
-
611
607
  function priorityBadge(p) {
612
608
  if (!p) return '';
613
- var colors = { high: '#ef4444', medium: '#f59e0b', low: '#6b7280' };
614
- var color = colors[p] || '#6b7280';
615
609
  return '<span class="task-priority-badge task-priority-' + esc(p) + '">' + esc(p) + '</span>';
616
610
  }
617
611
 
618
- function sessionBadge(sessionId) {
619
- if (!sessionId) return '';
620
- var short = sessionId.length > 8 ? sessionId.slice(0, 8) : sessionId;
621
- return '<span class="task-session-badge" title="Session ' + esc(sessionId) + '">' + esc(short) + '</span>';
622
- }
623
-
624
- function statusChip(section, checked) {
625
- if (checked || section === 'Done') return '<span class="task-status-chip task-status-done" title="Done"><svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M3 8.5l3.5 3.5 6.5-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Done</span>';
626
- if (section === 'Active') return '<span class="task-status-chip task-status-active" title="In Progress">In Progress</span>';
627
- return '<span class="task-status-chip task-status-pending" title="Pending">Pending</span>';
628
- }
629
-
630
612
  function projectBadge(proj) {
631
613
  return '<span class="task-project-badge">' + esc(proj) + '</span>';
632
614
  }
@@ -733,55 +715,40 @@ export function renderTasksAndSettingsScript(authToken) {
733
715
  var container = document.getElementById('tasks-list');
734
716
  if (!container) return;
735
717
  if (!tasks.length && !doneTasks.length) {
736
- container.innerHTML = '<div class="task-empty-state"><svg viewBox="0 0 48 48" width="64" height="64" style="display:block;margin:0 auto 16px"><ellipse cx="24" cy="24" rx="16" ry="15" fill="#7B68AE" opacity="0.25"/><ellipse cx="24" cy="24" rx="12" ry="11.5" fill="#7B68AE" opacity="0.4"/><circle cx="19" cy="22" r="1.5" fill="#2D2255"/><circle cx="29" cy="22" r="1.5" fill="#2D2255"/><path d="M21 28c1 1.2 2.5 1.5 3.5 1.3 1-.2 2-1 2.5-1.3" stroke="#2D2255" stroke-width="1" fill="none" stroke-linecap="round"/></svg><div style="font-size:var(--text-md);font-weight:600;color:var(--ink);margin-bottom:4px">Nothing to do!</div><div style="color:var(--muted);font-size:var(--text-sm)">Add a task to get started.</div></div>';
718
+ container.innerHTML = '<div class="task-empty-state"><svg viewBox="0 0 48 48" width="48" height="48" style="display:block;margin:0 auto 12px"><ellipse cx="24" cy="24" rx="16" ry="15" fill="#7B68AE" opacity="0.25"/><ellipse cx="24" cy="24" rx="12" ry="11.5" fill="#7B68AE" opacity="0.4"/><circle cx="19" cy="22" r="1.5" fill="#2D2255"/><circle cx="29" cy="22" r="1.5" fill="#2D2255"/><path d="M21 28c1 1.2 2.5 1.5 3.5 1.3 1-.2 2-1 2.5-1.3" stroke="#2D2255" stroke-width="1" fill="none" stroke-linecap="round"/></svg><div style="font-size:var(--text-md);font-weight:600;color:var(--ink);margin-bottom:4px">Nothing to do!</div><div style="color:var(--muted);font-size:var(--text-sm)">Add a task to get started.</div></div>';
737
719
  return;
738
720
  }
739
721
 
740
- // Group by priority within sections
741
722
  var priorityOrder = { high: 0, medium: 1, low: 2 };
742
723
  function sortByPriority(a, b) {
743
- // Unchecked before checked
744
- var aChecked = a.checked || a.section === 'Done' ? 1 : 0;
745
- var bChecked = b.checked || b.section === 'Done' ? 1 : 0;
746
- if (aChecked !== bChecked) return aChecked - bChecked;
747
- // Pinned first
748
724
  if (a.pinned && !b.pinned) return -1;
749
725
  if (!a.pinned && b.pinned) return 1;
750
- // Then by priority
751
726
  var pa = priorityOrder[a.priority] !== undefined ? priorityOrder[a.priority] : 1;
752
727
  var pb = priorityOrder[b.priority] !== undefined ? priorityOrder[b.priority] : 1;
753
728
  return pa - pb;
754
729
  }
755
730
 
756
- // Separate into priority groups (exclude checked tasks even if not in Done section)
757
- function isActive(t) { return t.section !== 'Done' && !t.checked; }
758
- var high = tasks.filter(function(t) { return t.priority === 'high' && isActive(t); }).sort(sortByPriority);
759
- var medium = tasks.filter(function(t) { return t.priority === 'medium' && isActive(t); }).sort(sortByPriority);
760
- var low = tasks.filter(function(t) { return t.priority === 'low' && isActive(t); }).sort(sortByPriority);
761
- var noPriority = tasks.filter(function(t) { return !t.priority && isActive(t); }).sort(sortByPriority);
762
- var doneVisible = tasks.filter(function(t) { return t.section === 'Done' || t.checked; });
763
-
764
- function renderTaskCard(t) {
765
- var borderClass = t.priority === 'high' ? ' task-card-high' : t.priority === 'medium' ? ' task-card-medium' : t.priority === 'low' ? ' task-card-low' : '';
766
- var doneClass = (t.section === 'Done' || t.checked) ? ' task-card-done' : '';
767
- var html = '<div class="task-card' + borderClass + doneClass + '">';
768
- html += '<div class="task-card-top">';
769
- html += statusChip(t.section, t.checked);
770
- html += projectBadge(t.project);
731
+ function isNotDone(t) { return t.section !== 'Done' && !t.checked; }
732
+
733
+ function renderTaskRow(t) {
734
+ var isDone = t.section === 'Done' || t.checked;
735
+ var priClass = t.priority ? 'task-row-priority-' + esc(t.priority) : 'task-row-priority-none';
736
+ var html = '<div class="task-row' + (isDone ? ' task-row-done' : '') + '">';
737
+ html += '<div class="task-row-priority ' + priClass + '"></div>';
738
+ html += '<div class="task-row-content">';
739
+ html += '<span class="task-row-text">' + esc(t.line) + '</span>';
740
+ html += '</div>';
741
+ html += '<div class="task-row-meta">';
771
742
  html += pinIndicator(t.pinned);
772
743
  html += githubBadge(t.githubIssue, t.githubUrl);
773
744
  html += priorityBadge(t.priority);
774
- html += sessionBadge(t.sessionId);
775
- html += '</div>';
776
- html += '<div class="task-card-body">';
777
- html += '<span class="task-card-text">' + esc(t.line) + '</span>';
778
- if (t.context) html += '<span class="task-card-context">' + esc(t.context) + '</span>';
745
+ html += projectBadge(t.project);
779
746
  html += '</div>';
780
- html += '<div class="task-card-actions">';
781
- if (t.section !== 'Done' && !t.checked) {
782
- html += '<button class="task-done-btn" data-ts-action="completeTask" data-project="' + esc(t.project) + '" data-item="' + esc(t.line) + '" title="Mark done"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M3 8.5l3.5 3.5 6.5-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Done</button>';
747
+ html += '<div class="task-row-actions">';
748
+ if (!isDone) {
749
+ html += '<button class="task-action-btn task-action-complete" data-ts-action="completeTask" data-project="' + esc(t.project) + '" data-item="' + esc(t.line) + '" title="Mark done"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M3 8.5l3.5 3.5 6.5-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>';
783
750
  }
784
- html += '<button class="task-remove-btn" data-ts-action="removeTask" data-project="' + esc(t.project) + '" data-item="' + esc(t.line) + '" title="Delete task" style="background:none;border:1px solid var(--border);border-radius:var(--radius-sm);padding:2px 8px;cursor:pointer;color:var(--muted);font-size:var(--text-xs)"><svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg></button>';
751
+ html += '<button class="task-action-btn task-action-delete" data-ts-action="removeTask" data-project="' + esc(t.project) + '" data-item="' + esc(t.line) + '" title="Delete task"><svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg></button>';
785
752
  html += '</div>';
786
753
  html += '</div>';
787
754
  return html;
@@ -807,49 +774,42 @@ export function renderTasksAndSettingsScript(authToken) {
807
774
  topProjects.forEach(function(p) { html += '<span class="task-summary-project">' + esc(p) + ' (' + projectCounts[p] + ')</span>'; });
808
775
  html += '</span>';
809
776
  }
810
- html += '<span class="task-view-toggle" style="margin-left:auto">';
811
- html += '<button class="task-view-btn' + (_taskViewMode === 'list' ? ' active' : '') + '" data-ts-action="setTaskView" data-mode="list" title="List view"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>';
812
- html += '<button class="task-view-btn' + (_taskViewMode === 'compact' ? ' active' : '') + '" data-ts-action="setTaskView" data-mode="compact" title="Compact view"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><rect x="1" y="2" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="9" y="2" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="1" y="9" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="9" y="9" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/></svg></button>';
813
- html += '</span>';
814
777
  html += '</div>';
815
778
 
816
779
  // Add task input at top (only when a specific project is selected)
817
- var projects = projectFilter ? [projectFilter] : [];
818
- projects.forEach(function(proj) {
780
+ if (projectFilter) {
819
781
  html += '<div class="task-add-bar">';
820
- html += '<input id="task-add-input-' + esc(proj) + '" type="text" class="task-add-input" placeholder="Add a task to ' + esc(proj) + '\u2026" data-ts-action="addTaskKeydown" data-project="' + esc(proj) + '">';
821
- html += '<button class="task-add-btn" data-ts-action="addTask" data-project="' + esc(proj) + '"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg> Add</button>';
782
+ html += '<input id="task-add-input-' + esc(projectFilter) + '" type="text" class="task-add-input" placeholder="Add a task to ' + esc(projectFilter) + '\u2026" data-ts-action="addTaskKeydown" data-project="' + esc(projectFilter) + '">';
783
+ html += '<button class="task-add-btn" data-ts-action="addTask" data-project="' + esc(projectFilter) + '"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg> Add</button>';
822
784
  html += '</div>';
823
- });
785
+ }
786
+
787
+ // Group by section: Active first, then Queue
788
+ var activeTasks = tasks.filter(function(t) { return t.section === 'Active' && isNotDone(t); }).sort(sortByPriority);
789
+ var queueTasks = tasks.filter(function(t) { return t.section !== 'Active' && isNotDone(t); }).sort(sortByPriority);
824
790
 
825
- // Priority sections
826
- function renderSection(title, items, icon) {
791
+ function renderSection(title, items) {
827
792
  if (!items.length) return '';
828
- var gridClass = _taskViewMode === 'compact' ? 'task-card-grid task-card-grid-compact' : 'task-card-grid';
829
- var shtml = '<div class="task-priority-section">';
830
- shtml += '<div class="task-section-header"><span class="task-section-icon">' + icon + '</span> ' + title + ' <span class="task-section-count">' + items.length + '</span></div>';
831
- shtml += '<div class="' + gridClass + '">';
832
- items.forEach(function(t) { shtml += renderTaskCard(t); });
793
+ var shtml = '<div class="task-section-group">';
794
+ shtml += '<div class="task-section-header">' + title + ' <span class="task-section-count">' + items.length + '</span></div>';
795
+ shtml += '<div class="task-list">';
796
+ items.forEach(function(t) { shtml += renderTaskRow(t); });
833
797
  shtml += '</div></div>';
834
798
  return shtml;
835
799
  }
836
800
 
837
- html += renderSection('High Priority', high, '<svg width="10" height="10" viewBox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="#ef4444"/></svg>');
838
- html += renderSection('Medium Priority', medium, '<svg width="10" height="10" viewBox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="#f59e0b"/></svg>');
839
- html += renderSection('Low Priority', low, '<svg width="10" height="10" viewBox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="#6b7280"/></svg>');
840
- if (noPriority.length) {
841
- html += renderSection('Tasks', noPriority, '<svg width="10" height="10" viewBox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="var(--accent)"/></svg>');
842
- }
801
+ html += renderSection('Active', activeTasks);
802
+ html += renderSection('Queue', queueTasks);
843
803
 
844
804
  // Done section (collapsible)
845
- var allDone = showDone ? doneVisible : doneTasks;
805
+ var allDone = showDone ? tasks.filter(function(t) { return t.section === 'Done' || t.checked; }) : doneTasks;
846
806
  if (allDone.length) {
847
807
  html += '<div class="task-done-section">';
848
808
  html += '<button class="task-done-toggle" data-ts-action="toggleDoneSection">';
849
809
  html += '<span class="task-toggle-arrow">\u25B6</span> Completed <span class="task-section-count">' + allDone.length + '</span></button>';
850
810
  html += '<div class="task-done-list" style="display:none">';
851
- html += '<div class="task-card-grid">';
852
- allDone.forEach(function(t) { html += renderTaskCard(t); });
811
+ html += '<div class="task-list">';
812
+ allDone.forEach(function(t) { html += renderTaskRow(t); });
853
813
  html += '</div></div></div>';
854
814
  }
855
815
 
@@ -1172,122 +1132,13 @@ export function renderTasksAndSettingsScript(authToken) {
1172
1132
  var _origSwitchTab = window.switchTab;
1173
1133
  var _tasksLoaded = false;
1174
1134
  var _settingsLoaded = false;
1175
- var _sessionsLoaded = false;
1176
1135
  window.switchTab = function(tab) {
1177
1136
  if (typeof _origSwitchTab === 'function') _origSwitchTab(tab);
1178
1137
  if (tab === 'tasks' && !_tasksLoaded) { _tasksLoaded = true; loadTasks(); }
1179
1138
  if (tab === 'settings' && !_settingsLoaded) { _settingsLoaded = true; loadSettings(); }
1180
- if (tab === 'sessions' && !_sessionsLoaded) { _sessionsLoaded = true; loadSessions(); }
1181
- };
1182
-
1183
- var _sessionsData = [];
1184
- window.loadSessions = function() {
1185
- var projectFilter = document.getElementById('sessions-filter-project');
1186
- var project = projectFilter ? projectFilter.value : '';
1187
- var apiUrl = _tsAuthToken ? tsAuthUrl('/api/sessions') : '/api/sessions';
1188
- if (project) apiUrl += (apiUrl.includes('?') ? '&' : '?') + 'project=' + encodeURIComponent(project);
1189
- loadJson(apiUrl).then(function(data) {
1190
- if (!data.ok) throw new Error(data.error || 'Failed to load sessions');
1191
- _sessionsData = data.sessions || [];
1192
- renderSessionsList(_sessionsData);
1193
- // Populate project filter
1194
- if (projectFilter && projectFilter.options.length <= 1) {
1195
- var projects = {};
1196
- _sessionsData.forEach(function(s) { if (s.project) projects[s.project] = true; });
1197
- Object.keys(projects).sort().forEach(function(p) {
1198
- var opt = document.createElement('option');
1199
- opt.value = p; opt.textContent = p;
1200
- projectFilter.appendChild(opt);
1201
- });
1202
- }
1203
- }).catch(function(err) {
1204
- var list = document.getElementById('sessions-list');
1205
- if (list) list.innerHTML = '<div style="padding:40px;color:var(--muted);text-align:center">' + esc(err.message) + '</div>';
1206
- });
1207
- };
1208
-
1209
- function renderSessionsList(sessions) {
1210
- var list = document.getElementById('sessions-list');
1211
- var detail = document.getElementById('session-detail');
1212
- var countEl = document.getElementById('sessions-count');
1213
- if (detail) detail.style.display = 'none';
1214
- if (countEl) countEl.textContent = sessions.length + ' session(s)';
1215
- if (!list) return;
1216
- if (sessions.length === 0) {
1217
- list.innerHTML = '<div style="padding:40px;color:var(--muted);text-align:center"><svg viewBox="0 0 32 32" width="32" height="32" style="display:block;margin:0 auto 12px"><ellipse cx="16" cy="16" rx="10" ry="9.5" fill="#7B68AE" opacity="0.4"/><path d="M12 15l1-1 1 1-1 1z" fill="#2D2255"/><path d="M18 15l1-1 1 1-1 1z" fill="#2D2255"/><path d="M15 18.5c0.3-0.3 0.7-0.3 1 0" stroke="#2D2255" stroke-width="0.6" fill="none"/></svg>No sessions found.</div>';
1218
- return;
1219
- }
1220
- list.innerHTML = '<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm)">' +
1221
- '<thead><tr style="border-bottom:1px solid var(--border);text-align:left">' +
1222
- '<th style="padding:8px">Session</th><th style="padding:8px">Project</th><th style="padding:8px">Started</th>' +
1223
- '<th style="padding:8px">Ended</th><th style="padding:8px">Duration</th><th style="padding:8px">Findings</th></tr></thead><tbody>' +
1224
- sessions.map(function(s) {
1225
- var id = s.sessionId.slice(0, 8);
1226
- var startDate = (s.startedAt || '').slice(0, 16).replace('T', ' ');
1227
- var endDate = s.endedAt ? (s.endedAt || '').slice(0, 16).replace('T', ' ') : '<span style="color:var(--green)">active</span>';
1228
- var dur = s.durationMins != null ? s.durationMins + 'm' : '—';
1229
- var summarySnip = s.summary ? '<div class="text-muted" style="font-size:var(--text-xs);max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc(s.summary.slice(0, 80)) + '</div>' : '';
1230
- return '<tr style="border-bottom:1px solid var(--border);cursor:pointer" data-ts-action="showSessionDetail" data-session-id="' + esc(s.sessionId) + '">' +
1231
- '<td style="padding:8px;font-family:monospace">' + esc(id) + summarySnip + '</td>' +
1232
- '<td style="padding:8px">' + esc(s.project || '—') + '</td>' +
1233
- '<td style="padding:8px">' + esc(startDate) + '</td>' +
1234
- '<td style="padding:8px">' + endDate + '</td>' +
1235
- '<td style="padding:8px">' + esc(dur) + '</td>' +
1236
- '<td style="padding:8px">' + (s.findingsAdded || 0) + '</td></tr>';
1237
- }).join('') + '</tbody></table>';
1238
- }
1239
-
1240
- window.showSessionDetail = function(sessionId) {
1241
- var apiUrl = _tsAuthToken ? tsAuthUrl('/api/sessions') : '/api/sessions';
1242
- apiUrl += (apiUrl.includes('?') ? '&' : '?') + 'sessionId=' + encodeURIComponent(sessionId);
1243
- var list = document.getElementById('sessions-list');
1244
- var detail = document.getElementById('session-detail');
1245
- if (list) list.style.display = 'none';
1246
- if (detail) { detail.style.display = 'block'; detail.innerHTML = '<div style="padding:20px;color:var(--muted)">Loading session...</div>'; }
1247
- loadJson(apiUrl).then(function(data) {
1248
- if (!data.ok) throw new Error(data.error || 'Session not found');
1249
- var s = data.session;
1250
- var findings = data.findings || [];
1251
- var tasks = data.tasks || [];
1252
- var date = (s.startedAt || '').slice(0, 16).replace('T', ' ');
1253
- var dur = s.durationMins != null ? s.durationMins + ' min' : '—';
1254
- var html = '<div style="margin-bottom:12px"><button class="btn btn-sm" data-ts-action="backToSessionsList">← Back</button></div>' +
1255
- '<div class="card" style="margin-bottom:16px"><div class="card-body">' +
1256
- '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px">' +
1257
- '<div><strong>Session</strong><div class="text-muted" style="font-family:monospace">' + esc(s.sessionId.slice(0, 8)) + '</div></div>' +
1258
- '<div><strong>Project</strong><div class="text-muted">' + esc(s.project || '—') + '</div></div>' +
1259
- '<div><strong>Date</strong><div class="text-muted">' + esc(date) + '</div></div>' +
1260
- '<div><strong>Duration</strong><div class="text-muted">' + esc(dur) + '</div></div>' +
1261
- '<div><strong>Findings</strong><div class="text-muted">' + findings.length + '</div></div>' +
1262
- '<div><strong>Tasks</strong><div class="text-muted">' + tasks.length + '</div></div>' +
1263
- '<div><strong>Status</strong><div class="text-muted">' + esc(s.status) + '</div></div>' +
1264
- '</div>' +
1265
- (s.summary ? '<div style="margin-top:12px;padding:12px;background:var(--bg);border-radius:var(--radius-sm)"><strong>Summary</strong><div style="margin-top:4px">' + esc(s.summary) + '</div></div>' : '') +
1266
- '</div></div>';
1267
- if (findings.length > 0) {
1268
- html += '<div class="card" style="margin-bottom:16px"><div class="card-header"><h3>Findings (' + findings.length + ')</h3></div><div class="card-body"><ul style="margin:0;padding-left:20px">';
1269
- findings.forEach(function(f) { html += '<li style="margin-bottom:4px"><span class="text-muted">[' + esc(f.project) + ']</span> ' + esc(f.text) + '</li>'; });
1270
- html += '</ul></div></div>';
1271
- }
1272
- if (tasks.length > 0) {
1273
- html += '<div class="card" style="margin-bottom:16px"><div class="card-header"><h3>Tasks (' + tasks.length + ')</h3></div><div class="card-body"><ul style="margin:0;padding-left:20px">';
1274
- tasks.forEach(function(t) { html += '<li style="margin-bottom:4px"><span class="text-muted">[' + esc(t.project) + '/' + esc(t.section) + ']</span> ' + esc(t.text) + '</li>'; });
1275
- html += '</ul></div></div>';
1276
- }
1277
- if (detail) detail.innerHTML = html;
1278
- }).catch(function(err) {
1279
- if (detail) detail.innerHTML = '<div style="padding:20px;color:var(--muted)">' + esc(err.message) + '</div>';
1280
- });
1281
- };
1282
-
1283
- window.backToSessionsList = function() {
1284
- var list = document.getElementById('sessions-list');
1285
- var detail = document.getElementById('session-detail');
1286
- if (list) list.style.display = 'block';
1287
- if (detail) detail.style.display = 'none';
1288
1139
  };
1289
1140
 
1290
- // Event delegation for dynamically generated tasks/settings/sessions UI
1141
+ // Event delegation for dynamically generated tasks/settings UI
1291
1142
  document.addEventListener('click', function(e) {
1292
1143
  var target = e.target;
1293
1144
  if (!target || typeof target.closest !== 'function') return;
@@ -1298,15 +1149,12 @@ export function renderTasksAndSettingsScript(authToken) {
1298
1149
  else if (action === 'completeTask') { completeTaskFromUi(actionEl.getAttribute('data-project'), actionEl.getAttribute('data-item')); }
1299
1150
  else if (action === 'removeTask') { removeTaskFromUi(actionEl.getAttribute('data-project'), actionEl.getAttribute('data-item')); }
1300
1151
  else if (action === 'addTask') { addTaskFromUi(actionEl.getAttribute('data-project')); }
1301
- else if (action === 'setTaskView') { _taskViewMode = actionEl.getAttribute('data-mode') || 'list'; filterTasks(); }
1302
1152
  else if (action === 'setFindingSensitivity') { setFindingSensitivity(actionEl.getAttribute('data-level')); }
1303
1153
  else if (action === 'toggleAutoCapture') { setAutoCapture(actionEl.getAttribute('data-enabled') !== 'true'); }
1304
1154
  else if (action === 'setTaskMode') { setTaskMode(actionEl.getAttribute('data-mode')); }
1305
1155
  else if (action === 'setProactivity') { setProactivity(actionEl.getAttribute('data-level')); }
1306
1156
  else if (action === 'toggleMcpEnabled') { setMcpEnabled(actionEl.getAttribute('data-enabled') !== 'true'); }
1307
1157
  else if (action === 'toggleIntegrationTool') { toggleIntegrationTool(actionEl.getAttribute('data-tool')); }
1308
- else if (action === 'showSessionDetail') { showSessionDetail(actionEl.getAttribute('data-session-id')); }
1309
- else if (action === 'backToSessionsList') { backToSessionsList(); }
1310
1158
  else if (action === 'setProjectFindingSensitivity') {
1311
1159
  var proj = getSettingsProject();
1312
1160
  var level = actionEl.getAttribute('data-level');
@@ -1567,368 +1415,6 @@ export function renderSearchScript(authToken) {
1567
1415
  };
1568
1416
  })();`;
1569
1417
  }
1570
- // renderGraphPopupScript removed — replaced by renderGraphHostScript + sigma popover
1571
- function __removed_renderGraphPopupScript() {
1572
- return `(function() {
1573
- var popup = document.getElementById('graph-popup');
1574
- var popupCard = document.getElementById('graph-popup-card');
1575
- var popupLabel = document.getElementById('graph-popup-label');
1576
- var popupTitle = document.getElementById('graph-popup-title');
1577
- var popupMeta = document.getElementById('graph-popup-meta');
1578
- var popupBody = document.getElementById('graph-popup-body');
1579
- var popupClose = document.getElementById('graph-popup-close');
1580
- var esc = window._phrenEsc || function(s) { return String(s); };
1581
- var authUrl = window._phrenAuthUrl || function(path) { return path; };
1582
- var authBody = window._phrenAuthBody || function(body) { return body; };
1583
- var fetchCsrfToken = window._phrenFetchCsrfToken || function(cb) { cb(null); };
1584
- var currentDetail = null;
1585
- var isEditing = false;
1586
-
1587
- function showToast(msg, type) {
1588
- var container = document.getElementById('toast-container');
1589
- if (!container) return;
1590
- var toast = document.createElement('div');
1591
- toast.className = 'toast' + (type ? ' ' + type : '');
1592
- toast.textContent = msg;
1593
- container.appendChild(toast);
1594
- setTimeout(function() {
1595
- if (toast.parentNode) toast.parentNode.removeChild(toast);
1596
- }, 2800);
1597
- }
1598
-
1599
- function typeLabel(kind) {
1600
- if (kind === 'finding') return 'Finding';
1601
- if (kind === 'task') return 'Task';
1602
- if (kind === 'entity') return 'Fragment';
1603
- if (kind === 'reference') return 'Reference';
1604
- return 'Project';
1605
- }
1606
-
1607
- function popupPoint(point) {
1608
- return point || { x: 28, y: 28 };
1609
- }
1610
-
1611
- function renderMeta(detail) {
1612
- if (!popupMeta) return;
1613
- var parts = [];
1614
- if (detail.project) parts.push('<span class="graph-pill">' + esc(detail.project) + '</span>');
1615
- if (detail.section) parts.push('<span class="graph-pill">' + esc(detail.section) + '</span>');
1616
- if (detail.priority) parts.push('<span class="graph-pill">' + esc(detail.priority + ' priority') + '</span>');
1617
- if (detail.entityType) parts.push('<span class="graph-pill">' + esc(detail.entityType) + '</span>');
1618
- if (detail.topicLabel) parts.push('<span class="graph-pill">' + esc(detail.topicLabel) + '</span>');
1619
- if (detail.health) parts.push('<span class="graph-pill graph-pill-' + esc(detail.health) + '">' + esc(detail.health) + '</span>');
1620
- popupMeta.innerHTML = parts.join('');
1621
- }
1622
-
1623
- function statLine(label, value) {
1624
- return '<div class="graph-popup-line"><span>' + esc(label) + '</span><strong>' + esc(value) + '</strong></div>';
1625
- }
1626
-
1627
- function renderDocs(detail) {
1628
- if (!detail.refDocs || !detail.refDocs.length) return '';
1629
- var docs = detail.refDocs.slice(0, 8).map(function(ref) {
1630
- var doc = typeof ref === 'string' ? ref : (ref.doc || '');
1631
- return '<div class="graph-popup-doc">' + esc(doc) + '</div>';
1632
- }).join('');
1633
- return '<div class="graph-popup-section"><h4>Linked docs</h4><div class="graph-popup-docs">' + docs + '</div></div>';
1634
- }
1635
-
1636
- function renderProject(detail) {
1637
- var counts = detail.connections || {};
1638
- return '' +
1639
- '<div class="graph-popup-summary">' + esc(detail.fullLabel || detail.label || detail.id) + '</div>' +
1640
- '<div class="graph-popup-stats">' +
1641
- statLine('Neighbors', counts.total || 0) +
1642
- statLine('Findings', counts.findings || 0) +
1643
- statLine('Tasks', counts.tasks || 0) +
1644
- statLine('Fragments', counts.entities || 0) +
1645
- statLine('References', counts.references || 0) +
1646
- '</div>';
1647
- }
1648
-
1649
- function renderFinding(detail) {
1650
- return '' +
1651
- '<div class="graph-popup-summary" id="graph-popup-text">' + esc(detail.fullLabel || detail.label) + '</div>' +
1652
- '<div class="graph-popup-actions">' +
1653
- '<button class="btn btn-sm" data-graph-action="edit">Edit</button>' +
1654
- '<button class="btn btn-sm" data-graph-action="delete" style="border-color:var(--danger);color:var(--danger)">Delete</button>' +
1655
- '</div>' +
1656
- renderDocs(detail);
1657
- }
1658
-
1659
- function renderTask(detail) {
1660
- var section = detail.section || 'Queue';
1661
- var priority = detail.priority || 'none';
1662
- return '' +
1663
- '<div class="graph-popup-summary" id="graph-popup-text">' + esc(detail.fullLabel || detail.label) + '</div>' +
1664
- '<div class="graph-popup-section"><h4>Status</h4><div class="graph-popup-actions">' +
1665
- '<button class="btn btn-sm' + (section === 'Active' ? ' active' : '') + '" data-graph-action="task-status" data-status="Active">Active</button>' +
1666
- '<button class="btn btn-sm' + (section === 'Queue' ? ' active' : '') + '" data-graph-action="task-status" data-status="Queue">Queue</button>' +
1667
- '<button class="btn btn-sm" data-graph-action="task-status" data-status="Done">Done</button>' +
1668
- '</div></div>' +
1669
- '<div class="graph-popup-section"><h4>Priority</h4><div class="graph-popup-actions">' +
1670
- '<button class="btn btn-sm' + (priority === 'high' ? ' active' : '') + '" data-graph-action="task-priority" data-priority="high">High</button>' +
1671
- '<button class="btn btn-sm' + (priority === 'medium' ? ' active' : '') + '" data-graph-action="task-priority" data-priority="medium">Medium</button>' +
1672
- '<button class="btn btn-sm' + (priority === 'low' ? ' active' : '') + '" data-graph-action="task-priority" data-priority="low">Low</button>' +
1673
- '</div></div>' +
1674
- '<div class="graph-popup-actions">' +
1675
- '<button class="btn btn-sm" data-graph-action="edit">Edit</button>' +
1676
- '<button class="btn btn-sm" data-graph-action="delete" style="border-color:var(--danger);color:var(--danger)">Delete</button>' +
1677
- '</div>';
1678
- }
1679
-
1680
- function renderEntity(detail) {
1681
- var projects = (detail.connectedProjects || []).map(function(project) {
1682
- return '<span class="graph-pill">' + esc(project) + '</span>';
1683
- }).join('');
1684
- return '' +
1685
- '<div class="graph-popup-summary">' + esc(detail.fullLabel || detail.label) + '</div>' +
1686
- '<div class="graph-popup-stats">' +
1687
- statLine('References', detail.refCount || 0) +
1688
- statLine('Projects', (detail.connectedProjects || []).length) +
1689
- statLine('Neighbors', (detail.connections && detail.connections.total) || 0) +
1690
- '</div>' +
1691
- (projects ? '<div class="graph-popup-section"><h4>Projects</h4><div class="graph-popup-pills">' + projects + '</div></div>' : '') +
1692
- renderDocs(detail);
1693
- }
1694
-
1695
- function renderReference(detail) {
1696
- return '' +
1697
- '<div class="graph-popup-summary">' + esc(detail.fullLabel || detail.label) + '</div>' +
1698
- '<div class="graph-popup-stats">' +
1699
- statLine('Project', detail.project || 'shared') +
1700
- statLine('Neighbors', (detail.connections && detail.connections.total) || 0) +
1701
- '</div>' +
1702
- renderDocs(detail);
1703
- }
1704
-
1705
- function renderEditor(detail) {
1706
- return '' +
1707
- '<div class="graph-popup-editor">' +
1708
- '<textarea id="graph-popup-editor-input">' + esc(detail.fullLabel || detail.label) + '</textarea>' +
1709
- '<div class="graph-popup-actions">' +
1710
- '<button class="btn btn-sm btn-primary" data-graph-action="save-edit">Save</button>' +
1711
- '<button class="btn btn-sm" data-graph-action="cancel-edit">Cancel</button>' +
1712
- '</div>' +
1713
- '</div>';
1714
- }
1715
-
1716
- function renderBody(detail) {
1717
- if (!popupBody) return;
1718
- if (isEditing && (detail.kind === 'finding' || detail.kind === 'task')) {
1719
- popupBody.innerHTML = renderEditor(detail);
1720
- return;
1721
- }
1722
- if (detail.kind === 'project') popupBody.innerHTML = renderProject(detail);
1723
- else if (detail.kind === 'finding') popupBody.innerHTML = renderFinding(detail);
1724
- else if (detail.kind === 'task') popupBody.innerHTML = renderTask(detail);
1725
- else if (detail.kind === 'entity') popupBody.innerHTML = renderEntity(detail);
1726
- else popupBody.innerHTML = renderReference(detail);
1727
- }
1728
-
1729
- function positionPopup(point) {
1730
- if (!popupCard) return;
1731
- var container = document.querySelector('#tab-graph .graph-container');
1732
- if (!container) return;
1733
- var rect = container.getBoundingClientRect();
1734
- var width = popupCard.offsetWidth || 360;
1735
- var height = popupCard.offsetHeight || 260;
1736
- var safe = popupPoint(point);
1737
- var left = Math.max(14, Math.min(safe.x + 18, rect.width - width - 14));
1738
- var top = Math.max(14, Math.min(safe.y + 18, rect.height - height - 14));
1739
- popupCard.style.left = left + 'px';
1740
- popupCard.style.top = top + 'px';
1741
- }
1742
-
1743
- function renderPopup(detail, point) {
1744
- if (!popup || !popupLabel || !popupTitle) return;
1745
- currentDetail = detail;
1746
- popupLabel.textContent = typeLabel(detail.kind);
1747
- popupTitle.textContent = detail.label || detail.fullLabel || detail.id;
1748
- renderMeta(detail);
1749
- renderBody(detail);
1750
- popup.classList.add('open');
1751
- requestAnimationFrame(function() { positionPopup(point); });
1752
- }
1753
-
1754
- function closePopup(skipSelectionClear) {
1755
- currentDetail = null;
1756
- isEditing = false;
1757
- if (popup) popup.classList.remove('open');
1758
- if (!skipSelectionClear && typeof window.graphClearSelection === 'function') window.graphClearSelection();
1759
- }
1760
-
1761
- function refetchGraph(keepNodeId) {
1762
- if (typeof window.loadGraph !== 'function') return;
1763
- window.loadGraph();
1764
- if (keepNodeId && window.phrenGraph && typeof window.phrenGraph.selectNode === 'function') {
1765
- var attempts = 0;
1766
- var timer = setInterval(function() {
1767
- attempts++;
1768
- if (window.phrenGraph.selectNode(keepNodeId) || attempts > 18) clearInterval(timer);
1769
- }, 120);
1770
- }
1771
- }
1772
-
1773
- function postForm(url, method, body, onOk) {
1774
- fetchCsrfToken(function(csrfToken) {
1775
- var nextBody = authBody(body);
1776
- if (csrfToken) nextBody += '&_csrf=' + encodeURIComponent(csrfToken);
1777
- fetch(url, {
1778
- method: method,
1779
- headers: { 'content-type': 'application/x-www-form-urlencoded' },
1780
- body: nextBody
1781
- }).then(function(r) { return r.json(); }).then(function(data) {
1782
- if (!data.ok) throw new Error(data.error || 'Request failed');
1783
- onOk(data);
1784
- }).catch(function(err) {
1785
- showToast(String((err && err.message) || err || 'Request failed'), 'err');
1786
- });
1787
- });
1788
- }
1789
-
1790
- function saveFindingEdit(nextText) {
1791
- postForm(authUrl('/api/findings/' + encodeURIComponent(currentDetail.project)), 'PUT',
1792
- 'old_text=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label) + '&new_text=' + encodeURIComponent(nextText),
1793
- function() {
1794
- currentDetail.fullLabel = nextText;
1795
- currentDetail.label = nextText.length > 55 ? nextText.slice(0, 52) + '...' : nextText;
1796
- isEditing = false;
1797
- renderPopup(currentDetail);
1798
- refetchGraph(currentDetail.id);
1799
- showToast('Finding updated', 'ok');
1800
- }
1801
- );
1802
- }
1803
-
1804
- function saveTaskEdit(nextText) {
1805
- postForm('/api/tasks/update', 'POST',
1806
- 'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label) + '&text=' + encodeURIComponent(nextText),
1807
- function() {
1808
- currentDetail.fullLabel = nextText;
1809
- currentDetail.label = nextText.length > 55 ? nextText.slice(0, 52) + '...' : nextText;
1810
- isEditing = false;
1811
- renderPopup(currentDetail);
1812
- refetchGraph(currentDetail.id);
1813
- showToast('Task updated', 'ok');
1814
- }
1815
- );
1816
- }
1817
-
1818
- function updateTask(payload) {
1819
- var body = 'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label);
1820
- Object.keys(payload).forEach(function(key) {
1821
- body += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(payload[key]);
1822
- });
1823
- postForm('/api/tasks/update', 'POST', body, function() {
1824
- if (payload.section) currentDetail.section = payload.section;
1825
- if (payload.priority) currentDetail.priority = payload.priority;
1826
- renderPopup(currentDetail);
1827
- refetchGraph(payload.section === 'Done' ? null : currentDetail.id);
1828
- if (payload.section === 'Done') closePopup(true);
1829
- showToast('Task updated', 'ok');
1830
- });
1831
- }
1832
-
1833
- function completeTask() {
1834
- postForm('/api/tasks/complete', 'POST',
1835
- 'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label),
1836
- function() {
1837
- closePopup(true);
1838
- refetchGraph(null);
1839
- showToast('Task completed', 'ok');
1840
- }
1841
- );
1842
- }
1843
-
1844
- function deleteCurrent() {
1845
- if (!currentDetail) return;
1846
- if (currentDetail.kind === 'finding') {
1847
- postForm(authUrl('/api/findings/' + encodeURIComponent(currentDetail.project)), 'DELETE',
1848
- 'text=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label),
1849
- function() {
1850
- closePopup(true);
1851
- refetchGraph(null);
1852
- showToast('Finding deleted', 'ok');
1853
- }
1854
- );
1855
- } else if (currentDetail.kind === 'task') {
1856
- postForm('/api/tasks/remove', 'POST',
1857
- 'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label),
1858
- function() {
1859
- closePopup(true);
1860
- refetchGraph(null);
1861
- showToast('Task deleted', 'ok');
1862
- }
1863
- );
1864
- }
1865
- }
1866
-
1867
- if (popupClose) popupClose.addEventListener('click', function(e) {
1868
- e.preventDefault();
1869
- e.stopPropagation();
1870
- closePopup(false);
1871
- });
1872
-
1873
- if (popupCard) {
1874
- popupCard.addEventListener('click', function(e) {
1875
- var target = e.target;
1876
- if (!target || typeof target.closest !== 'function' || !currentDetail) return;
1877
- var actionEl = target.closest('[data-graph-action]');
1878
- if (!actionEl) return;
1879
- var action = actionEl.getAttribute('data-graph-action');
1880
- if (action === 'edit') {
1881
- isEditing = true;
1882
- renderPopup(currentDetail);
1883
- } else if (action === 'cancel-edit') {
1884
- isEditing = false;
1885
- renderPopup(currentDetail);
1886
- } else if (action === 'save-edit') {
1887
- var input = document.getElementById('graph-popup-editor-input');
1888
- var nextText = input ? input.value.trim() : '';
1889
- if (!nextText) {
1890
- showToast('Text cannot be empty', 'err');
1891
- return;
1892
- }
1893
- if (currentDetail.kind === 'finding') saveFindingEdit(nextText);
1894
- else if (currentDetail.kind === 'task') saveTaskEdit(nextText);
1895
- } else if (action === 'delete') {
1896
- deleteCurrent();
1897
- } else if (action === 'task-status') {
1898
- var status = actionEl.getAttribute('data-status') || 'Queue';
1899
- if (status === 'Done') completeTask();
1900
- else updateTask({ section: status });
1901
- } else if (action === 'task-priority') {
1902
- updateTask({ priority: actionEl.getAttribute('data-priority') || 'medium' });
1903
- }
1904
- });
1905
- }
1906
-
1907
- document.addEventListener('pointerdown', function(e) {
1908
- if (!popup || !popup.classList.contains('open')) return;
1909
- var target = e.target;
1910
- if (!target || typeof target.closest !== 'function') return;
1911
- if (popupCard && popupCard.contains(target)) return;
1912
- if (target.closest('.graph-filters') || target.closest('.graph-controls')) return;
1913
- closePopup(false);
1914
- });
1915
-
1916
- if (window.phrenGraph && typeof window.phrenGraph.onNodeSelect === 'function') {
1917
- window.phrenGraph.onNodeSelect(function(detail, point) {
1918
- isEditing = false;
1919
- renderPopup(detail, point);
1920
- });
1921
- }
1922
-
1923
- if (window.phrenGraph && typeof window.phrenGraph.onSelectionClear === 'function') {
1924
- window.phrenGraph.onSelectionClear(function() {
1925
- currentDetail = null;
1926
- isEditing = false;
1927
- if (popup) popup.classList.remove('open');
1928
- });
1929
- }
1930
- })();`;
1931
- }
1932
1418
  export function renderEventWiringScript() {
1933
1419
  return `(function() {
1934
1420
  // --- Navigation tabs ---
@@ -1987,10 +1473,6 @@ export function renderEventWiringScript() {
1987
1473
  var tasksFilterSection = document.getElementById('tasks-filter-section');
1988
1474
  if (tasksFilterSection) tasksFilterSection.addEventListener('change', function() { filterTasks(); });
1989
1475
 
1990
- // --- Sessions filter ---
1991
- var sessionsFilterProject = document.getElementById('sessions-filter-project');
1992
- if (sessionsFilterProject) sessionsFilterProject.addEventListener('change', function() { loadSessions(); });
1993
-
1994
1476
  // --- Mascot click animation ---
1995
1477
  var mascotSvg = document.querySelector('.header-brand svg');
1996
1478
  if (mascotSvg) {