@cccarv82/freya 2.3.0 → 2.3.2

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/cli/web-ui.js CHANGED
@@ -663,6 +663,7 @@
663
663
  const items = Array.isArray(state.projects) ? state.projects : [];
664
664
  const filtered = items.filter((p) => {
665
665
  const hay = [p.client, p.program, p.stream, p.project, p.slug, (p.tags||[]).join(' ')].join(' ').toLowerCase();
666
+ if (kind !== 'all' && String(i.kind||'') !== kind) return false;
666
667
  return !filter || hay.includes(filter);
667
668
  });
668
669
  el.innerHTML = '';
@@ -703,12 +704,23 @@
703
704
  if (!el) return;
704
705
  const filter = String(($('timelineFilter') && $('timelineFilter').value) || '').toLowerCase();
705
706
  const items = Array.isArray(state.timeline) ? state.timeline : [];
707
+ const kind = state.timelineKind || 'all';
706
708
  const filtered = items.filter((i) => {
707
709
  const hay = [i.kind, i.title, i.content, (i.tags || []).join(' ')].join(' ').toLowerCase();
708
710
  return !filter || hay.includes(filter);
709
711
  });
710
712
  el.innerHTML = '';
713
+ let currentDate = null;
711
714
  for (const it of filtered) {
715
+ if (it.date && it.date !== currentDate) {
716
+ currentDate = it.date;
717
+ const head = document.createElement('div');
718
+ head.className = 'help';
719
+ head.style.fontWeight = '800';
720
+ head.style.marginTop = '6px';
721
+ head.textContent = currentDate;
722
+ el.appendChild(head);
723
+ }
712
724
  const card = document.createElement('div');
713
725
  card.className = 'reportCard';
714
726
  card.innerHTML = '<div class="reportHead">'
@@ -726,6 +738,11 @@
726
738
  }
727
739
  }
728
740
 
741
+ function setTimelineKind(kind) {
742
+ state.timelineKind = kind;
743
+ renderTimeline();
744
+ }
745
+
729
746
  async function refreshTimeline() {
730
747
  try {
731
748
  const r = await api('/api/timeline', { dir: dirOrDefault() });
@@ -743,7 +760,28 @@
743
760
  const el = $('incidentsBox');
744
761
  if (el) {
745
762
  const md = r.markdown || '';
746
- el.innerHTML = md ? renderMarkdown(md) : '<div class="help">Nenhum incidente registrado.</div>';
763
+ if (!md) { el.innerHTML = '<div class="help">Nenhum incidente registrado.</div>'; return; }
764
+ const lines = md.split(/\n/);
765
+ const cards = [];
766
+ let current = null;
767
+ for (const line of lines) {
768
+ if (line.startsWith('- **')) {
769
+ if (current) cards.push(current);
770
+ current = { title: line.replace('- **', '').replace('**', '').trim(), body: [] };
771
+ } else if (current && line.trim().startsWith('- ')) {
772
+ current.body.push(line.trim().replace(/^- /, ''));
773
+ }
774
+ }
775
+ if (current) cards.push(current);
776
+ el.innerHTML = '';
777
+ if (!cards.length) { el.innerHTML = renderMarkdown(md); return; }
778
+ for (const c of cards) {
779
+ const card = document.createElement('div');
780
+ card.className = 'reportCard';
781
+ card.innerHTML = '<div class="reportTitle">' + escapeHtml(c.title) + '</div>'
782
+ + c.body.map((b) => '<div class="help" style="margin-top:4px">' + escapeHtml(b) + '</div>').join('');
783
+ el.appendChild(card);
784
+ }
747
785
  }
748
786
  } catch {
749
787
  const el = $('incidentsBox');
@@ -751,13 +789,20 @@
751
789
  }
752
790
  }
753
791
 
792
+ function setHeatmapSort(sort) {
793
+ state.heatmapSort = sort;
794
+ refreshHeatmap();
795
+ }
796
+
754
797
  async function refreshHeatmap() {
755
798
  try {
756
799
  const r = await api('/api/tasks/heatmap', { dir: dirOrDefault() });
757
800
  const el = $('heatmapGrid');
758
801
  if (!el) return;
759
802
  el.innerHTML = '';
760
- const items = r.items || [];
803
+ let items = r.items || [];
804
+ const sort = state.heatmapSort || 'pending';
805
+ items = items.slice().sort((a,b)=> (b[sort]||0) - (a[sort]||0));
761
806
  for (const it of items) {
762
807
  const row = document.createElement('div');
763
808
  row.className = 'rep';
@@ -1540,6 +1585,8 @@
1540
1585
  window.refreshTimeline = refreshTimeline;
1541
1586
  window.refreshIncidents = refreshIncidents;
1542
1587
  window.refreshHeatmap = refreshHeatmap;
1588
+ window.setHeatmapSort = setHeatmapSort;
1589
+ window.setTimelineKind = setTimelineKind;
1543
1590
  window.refreshBlockersInsights = refreshBlockersInsights;
1544
1591
  window.refreshHealthChecklist = refreshHealthChecklist;
1545
1592
  window.copyOut = copyOut;
package/cli/web.js CHANGED
@@ -2072,19 +2072,42 @@ if (req.url === '/api/reports/list') {
2072
2072
 
2073
2073
  function autoLinkNotes(textInput) {
2074
2074
  try {
2075
+ const lc = textInput.toLowerCase();
2075
2076
  const projectsDir = path.join(workspaceDir, 'docs', 'projects');
2076
- if (!exists(projectsDir)) return '';
2077
- const files = fs.readdirSync(projectsDir).filter((f) => f.endsWith('.md'));
2078
2077
  const links = [];
2079
- for (const f of files) {
2080
- const name = f.replace('.md', '');
2081
- const slug = name.toLowerCase();
2082
- if (textInput.toLowerCase().includes(slug)) links.push(`[[${name}]]`);
2078
+
2079
+ if (exists(projectsDir)) {
2080
+ const files = fs.readdirSync(projectsDir).filter((f) => f.endsWith('.md'));
2081
+ for (const f of files) {
2082
+ const name = f.replace('.md', '');
2083
+ const full = path.join(projectsDir, f);
2084
+ const txt = fs.readFileSync(full, 'utf8');
2085
+ const m = txt.match(/DataPath:\s*data\/Clients\/(.+?)\//i);
2086
+ const slug = m ? m[1].toLowerCase() : name.toLowerCase();
2087
+ if (lc.includes(slug)) links.push('[[' + name + ']]');
2088
+ }
2089
+ }
2090
+
2091
+ const base = path.join(workspaceDir, 'data', 'Clients');
2092
+ if (exists(base)) {
2093
+ const stack = [base];
2094
+ while (stack.length) {
2095
+ const dirp = stack.pop();
2096
+ const entries = fs.readdirSync(dirp, { withFileTypes: true });
2097
+ for (const ent of entries) {
2098
+ const full = path.join(dirp, ent.name);
2099
+ if (ent.isDirectory()) stack.push(full);
2100
+ else if (ent.isFile() && ent.name === 'status.json') {
2101
+ const slug = path.relative(base, path.dirname(full)).replace(/\\/g, '/').toLowerCase();
2102
+ if (lc.includes(slug)) links.push('[[' + slug + ']]');
2103
+ }
2104
+ }
2105
+ }
2083
2106
  }
2084
- if (!links.length) return '';
2085
- return `
2086
2107
 
2087
- Links: ${links.join(' ')}`;
2108
+ const uniq = Array.from(new Set(links));
2109
+ if (!uniq.length) return '';
2110
+ return '\n\nLinks: ' + uniq.join(' ');
2088
2111
  } catch {
2089
2112
  return '';
2090
2113
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cccarv82/freya",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "description": "Personal AI Assistant with local-first persistence",
5
5
  "scripts": {
6
6
  "health": "node scripts/validate-data.js && node scripts/validate-structure.js",