@cccarv82/freya 1.0.31 → 1.0.32

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
@@ -325,7 +325,7 @@
325
325
  async function refreshReports(opts = {}) {
326
326
  try {
327
327
  const r = await api('/api/reports/list', { dir: dirOrDefault() });
328
- state.reports = (r.reports || []).slice(0, 50);
328
+ state.reports = (r.reports || []).slice(0, 10);
329
329
  renderReportsList();
330
330
 
331
331
  const latest = state.reports && state.reports[0] ? state.reports[0] : null;
@@ -344,6 +344,44 @@
344
344
  }
345
345
  }
346
346
 
347
+ async function editTask(t) {
348
+ try {
349
+ const currentSlug = t.projectSlug ? String(t.projectSlug) : '';
350
+ const slug = prompt('projectSlug (ex: vivo/fidelizacao/chg0178682):', currentSlug);
351
+ if (slug === null) return;
352
+
353
+ const currentCat = String(t.category || 'DO_NOW');
354
+ const cat = prompt('category (DO_NOW|SCHEDULE|DELEGATE|IGNORE):', currentCat);
355
+ if (cat === null) return;
356
+
357
+ setPill('run', 'updating…');
358
+ await api('/api/tasks/update', { dir: dirOrDefault(), id: t.id, patch: { projectSlug: slug, category: cat } });
359
+ await refreshToday();
360
+ setPill('ok', 'updated');
361
+ setTimeout(() => setPill('ok', 'idle'), 800);
362
+ } catch (e) {
363
+ setPill('err', 'update failed');
364
+ setOut(String(e && e.message ? e.message : e));
365
+ }
366
+ }
367
+
368
+ async function editBlocker(b) {
369
+ try {
370
+ const currentSlug = b.projectSlug ? String(b.projectSlug) : '';
371
+ const slug = prompt('projectSlug (ex: vivo/bnpl/dpgc):', currentSlug);
372
+ if (slug === null) return;
373
+
374
+ setPill('run', 'updating…');
375
+ await api('/api/blockers/update', { dir: dirOrDefault(), id: b.id, patch: { projectSlug: slug } });
376
+ await refreshToday();
377
+ setPill('ok', 'updated');
378
+ setTimeout(() => setPill('ok', 'idle'), 800);
379
+ } catch (e) {
380
+ setPill('err', 'update failed');
381
+ setOut(String(e && e.message ? e.message : e));
382
+ }
383
+ }
384
+
347
385
  function renderTasks(list) {
348
386
  const el = $('tasksList');
349
387
  if (!el) return;
@@ -357,9 +395,14 @@
357
395
  + '<div style="opacity:.7; font-size:11px; margin-top:4px">' + escapeHtml(String(t.category || ''))
358
396
  + (t.projectSlug ? (' · <span style="font-family:var(--mono); opacity:.9">[' + escapeHtml(String(t.projectSlug)) + ']</span>') : '')
359
397
  + (pri ? (' · ' + escapeHtml(pri)) : '') + '</div></div>'
398
+ + '<div style="display:flex; gap:8px">'
360
399
  + '<button class="btn small" type="button">Complete</button>'
400
+ + '<button class="btn small" type="button">Edit</button>'
401
+ + '</div>'
361
402
  + '</div>';
362
- const btn = row.querySelector('button');
403
+ const btns = row.querySelectorAll('button');
404
+ const btn = btns[0];
405
+ if (btns[1]) btns[1].onclick = () => editTask(t);
363
406
  btn.onclick = async () => {
364
407
  try {
365
408
  setPill('run', 'completing…');
@@ -396,8 +439,13 @@
396
439
  + (b.projectSlug ? (' <span style="font-family:var(--mono); opacity:.8">[' + escapeHtml(String(b.projectSlug)) + ']</span>') : '')
397
440
  + '</div>'
398
441
  + '</div>'
442
+ + '<div style="display:flex; gap:8px; align-items:center">'
399
443
  + '<div style="opacity:.7; font-size:11px; white-space:nowrap">' + escapeHtml(fmtWhen(new Date(b.createdAt || Date.now()).getTime())) + '</div>'
444
+ + '<button class="btn small" type="button">Edit</button>'
445
+ + '</div>'
400
446
  + '</div>';
447
+ const ebtn = row.querySelector('button');
448
+ if (ebtn) ebtn.onclick = () => editBlocker(b);
401
449
  el.appendChild(row);
402
450
  }
403
451
  if (!el.childElementCount) {
@@ -526,6 +574,21 @@
526
574
  }
527
575
  }
528
576
 
577
+ async function exportObsidian() {
578
+ try {
579
+ setPill('run', 'exporting…');
580
+ const r = await api('/api/obsidian/export', { dir: dirOrDefault() });
581
+ setOut('## Obsidian export
582
+
583
+ ' + (r.output || 'ok'));
584
+ setPill('ok', 'exported');
585
+ setTimeout(() => setPill('ok', 'idle'), 800);
586
+ } catch (e) {
587
+ setPill('err', 'export failed');
588
+ setOut(String(e && e.message ? e.message : e));
589
+ }
590
+ }
591
+
529
592
  async function reloadSlugRules() {
530
593
  try {
531
594
  const r = await api('/api/project-slug-map/get', { dir: dirOrDefault() });
@@ -807,6 +870,7 @@
807
870
  window.refreshToday = refreshToday;
808
871
  window.reloadSlugRules = reloadSlugRules;
809
872
  window.saveSlugRules = saveSlugRules;
873
+ window.exportObsidian = exportObsidian;
810
874
  window.renderReportsList = renderReportsList;
811
875
  window.copyOut = copyOut;
812
876
  window.copyPath = copyPath;
package/cli/web.js CHANGED
@@ -675,7 +675,6 @@ function buildHtml(safeDefault) {
675
675
  <textarea id="inboxText" rows="6" placeholder="Cole aqui updates do dia (status, blockers, decisões, ideias)…" style="width:100%; padding:10px 12px; border-radius:12px; border:1px solid var(--line); background: rgba(255,255,255,.72); color: var(--text); outline:none; resize: vertical;"></textarea>
676
676
  <div style="height:10px"></div>
677
677
  <div class="stack">
678
- <button class="btn sideBtn" onclick="saveInbox()">Save to Daily Log</button>
679
678
  <button class="btn primary sideBtn" onclick="saveAndPlan()">Save + Process (Agents)</button>
680
679
  <button class="btn sideBtn" onclick="runSuggestedReports()">Run suggested reports</button>
681
680
  </div>
@@ -775,6 +774,7 @@ function buildHtml(safeDefault) {
775
774
  <div class="stack" style="margin-top:10px">
776
775
  <button class="btn" onclick="reloadSlugRules()">Reload rules</button>
777
776
  <button class="btn" onclick="saveSlugRules()">Save rules</button>
777
+ <button class="btn" onclick="exportObsidian()">Export Obsidian notes</button>
778
778
  </div>
779
779
  </div>
780
780
  </div>
@@ -1553,6 +1553,13 @@ async function cmdWeb({ port, dir, open, dev }) {
1553
1553
  }
1554
1554
 
1555
1555
 
1556
+
1557
+ if (req.url === '/api/obsidian/export') {
1558
+ const r = await run(npmCmd, ['run', 'export-obsidian'], workspaceDir);
1559
+ const out = (r.stdout + r.stderr).trim();
1560
+ return safeJson(res, r.code === 0 ? 200 : 400, r.code === 0 ? { ok: true, output: out } : { error: out || 'export failed', output: out });
1561
+ }
1562
+
1556
1563
  if (req.url === '/api/tasks/list') {
1557
1564
  const limit = Math.max(1, Math.min(50, Number(payload.limit || 10)));
1558
1565
  const cat = payload.category ? String(payload.category).trim() : null;
@@ -1606,6 +1613,30 @@ async function cmdWeb({ port, dir, open, dev }) {
1606
1613
  return safeJson(res, 200, { ok: true, task: updated });
1607
1614
  }
1608
1615
 
1616
+
1617
+ if (req.url === '/api/tasks/update') {
1618
+ const id = String(payload.id || '').trim();
1619
+ if (!id) return safeJson(res, 400, { error: 'Missing id' });
1620
+ const patch = payload.patch && typeof payload.patch === 'object' ? payload.patch : {};
1621
+
1622
+ const file = path.join(workspaceDir, 'data', 'tasks', 'task-log.json');
1623
+ const doc = readJsonOrNull(file) || { schemaVersion: 1, tasks: [] };
1624
+ const tasks = Array.isArray(doc.tasks) ? doc.tasks : [];
1625
+
1626
+ let updated = null;
1627
+ for (const t of tasks) {
1628
+ if (t && t.id === id) {
1629
+ if (typeof patch.projectSlug === 'string') t.projectSlug = patch.projectSlug.trim() || undefined;
1630
+ if (typeof patch.category === 'string') t.category = patch.category.trim();
1631
+ updated = t;
1632
+ break;
1633
+ }
1634
+ }
1635
+ if (!updated) return safeJson(res, 404, { error: 'Task not found' });
1636
+ writeJson(file, doc);
1637
+ return safeJson(res, 200, { ok: true, task: updated });
1638
+ }
1639
+
1609
1640
  if (req.url === '/api/blockers/list') {
1610
1641
  const limit = Math.max(1, Math.min(50, Number(payload.limit || 10)));
1611
1642
  const status = payload.status ? String(payload.status).trim() : 'OPEN';
@@ -1639,6 +1670,29 @@ async function cmdWeb({ port, dir, open, dev }) {
1639
1670
 
1640
1671
  return safeJson(res, 200, { ok: true, blockers: filtered });
1641
1672
  }
1673
+
1674
+ if (req.url === '/api/blockers/update') {
1675
+ const id = String(payload.id || '').trim();
1676
+ if (!id) return safeJson(res, 400, { error: 'Missing id' });
1677
+ const patch = payload.patch && typeof payload.patch === 'object' ? payload.patch : {};
1678
+
1679
+ const file = path.join(workspaceDir, 'data', 'blockers', 'blocker-log.json');
1680
+ const doc = readJsonOrNull(file) || { schemaVersion: 1, blockers: [] };
1681
+ const blockers = Array.isArray(doc.blockers) ? doc.blockers : [];
1682
+
1683
+ let updated = null;
1684
+ for (const b of blockers) {
1685
+ if (b && b.id === id) {
1686
+ if (typeof patch.projectSlug === 'string') b.projectSlug = patch.projectSlug.trim() || undefined;
1687
+ updated = b;
1688
+ break;
1689
+ }
1690
+ }
1691
+ if (!updated) return safeJson(res, 404, { error: 'Blocker not found' });
1692
+ writeJson(file, doc);
1693
+ return safeJson(res, 200, { ok: true, blocker: updated });
1694
+ }
1695
+
1642
1696
  if (req.url === '/api/report') {
1643
1697
  const script = payload.script;
1644
1698
  if (!script) return safeJson(res, 400, { error: 'Missing script' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cccarv82/freya",
3
- "version": "1.0.31",
3
+ "version": "1.0.32",
4
4
  "description": "Personal AI Assistant with local-first persistence",
5
5
  "scripts": {
6
6
  "health": "node scripts/validate-data.js",
@@ -10,6 +10,7 @@
10
10
  "daily": "node scripts/generate-daily-summary.js",
11
11
  "status": "node scripts/generate-executive-report.js",
12
12
  "blockers": "node scripts/generate-blockers-report.js",
13
+ "export-obsidian": "node scripts/export-obsidian.js",
13
14
  "test": "node tests/unit/test-package-config.js && node tests/unit/test-cli-init.js && node tests/unit/test-cli-web-help.js && node tests/unit/test-web-static-assets.js && node tests/unit/test-fs-utils.js && node tests/unit/test-task-schema.js && node tests/unit/test-daily-generation.js && node tests/unit/test-report-generation.js && node tests/unit/test-oracle-retrieval.js && node tests/unit/test-task-completion.js && node tests/unit/test-migrate-data.js && node tests/unit/test-blockers-validation.js && node tests/unit/test-blockers-report.js && node tests/unit/test-sm-weekly-report.js && node tests/integration/test-ingestor-task.js"
14
15
  },
15
16
  "keywords": [],