@cccarv82/freya 1.0.49 → 1.0.51

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/cli/web.js +53 -15
  2. package/package.json +1 -1
package/cli/web.js CHANGED
@@ -611,6 +611,7 @@ function run(cmd, args, cwd) {
611
611
  function isAllowedChatSearchPath(relPath) {
612
612
  if (!relPath) return false;
613
613
  if (relPath.startsWith('..')) return false;
614
+ if (relPath.startsWith('data/chat/')) return false;
614
615
  return relPath.startsWith('data/') || relPath.startsWith('logs/') || relPath.startsWith('docs/');
615
616
  }
616
617
 
@@ -625,13 +626,16 @@ async function copilotSearch(workspaceDir, query, opts = {}) {
625
626
  'Você é um buscador local de arquivos.',
626
627
  'Objetivo: encontrar registros relevantes para a consulta do usuário.',
627
628
  'Escopo: procure SOMENTE nos diretórios data/, logs/ e docs/ do workspace.',
629
+ 'Exclua data/chat/ (conversa), a menos que o usuário peça explicitamente por chat.',
628
630
  'Use ferramentas para ler/consultar arquivos, mas não modifique nada.',
629
631
  `Consulta do usuário: "${q}"`,
630
632
  '',
631
633
  'Responda APENAS com JSON válido (sem code fences) no formato:',
632
- '{"summary":"<1-2 frases humanas>","matches":[{"file":"<caminho relativo>","date":"YYYY-MM-DD ou vazio","snippet":"<trecho curto>"}]}',
634
+ '{"answer":"<resposta humana, clara e direta>","evidence":[{"file":"<caminho relativo>","date":"YYYY-MM-DD ou vazio","detail":"<frase curta e única com a evidência>"}],"matches":[{"file":"<caminho relativo>","date":"YYYY-MM-DD ou vazio","snippet":"<trecho curto>"}]}',
633
635
  `Limite de matches: ${limit}.`,
634
- 'O resumo deve soar humano e mencionar a quantidade de registros encontrados.',
636
+ 'A resposta deve soar humana, bem escrita, sem repetições, e mencionar a quantidade de registros encontrados.',
637
+ 'Priorize responder exatamente à pergunta (ex.: data e ID da última CHG).',
638
+ 'Na seção evidence, escreva evidências curtas e não repetidas (máx 5).',
635
639
  'A lista deve estar ordenada por relevância.'
636
640
  ].join('\n');
637
641
 
@@ -678,32 +682,60 @@ async function copilotSearch(workspaceDir, query, opts = {}) {
678
682
  .filter((m) => m.file && isAllowedChatSearchPath(m.file))
679
683
  .slice(0, limit);
680
684
 
681
- const summary = String(parsed.summary || '').trim();
682
- return { ok: true, summary, matches };
685
+ const evidenceRaw = Array.isArray(parsed.evidence) ? parsed.evidence : [];
686
+ const evidence = evidenceRaw
687
+ .map((m) => {
688
+ const fileRaw = String(m && m.file ? m.file : '').trim();
689
+ const dateRaw = String(m && m.date ? m.date : '').trim();
690
+ const detailRaw = String(m && m.detail ? m.detail : '').trim();
691
+ let rel = fileRaw;
692
+ if (fileRaw.startsWith(workspaceDir)) {
693
+ rel = path.relative(workspaceDir, fileRaw).replace(/\\/g, '/');
694
+ }
695
+ return { file: rel.replace(/\\/g, '/'), date: dateRaw, detail: detailRaw };
696
+ })
697
+ .filter((m) => m.file && m.detail && isAllowedChatSearchPath(m.file))
698
+ .slice(0, 5);
699
+
700
+ const answer = String(parsed.answer || '').trim();
701
+ return { ok: true, answer, matches, evidence };
683
702
  }
684
703
 
685
- function buildChatAnswer(query, matches, summary) {
704
+ function buildChatAnswer(query, matches, summary, evidence, answer) {
686
705
  const count = matches.length;
687
706
  let summaryText = String(summary || '').trim();
688
- if (!summaryText) {
689
- if (count === 0) {
690
- summaryText = `Não encontrei registros relacionados a "${query}".`;
691
- } else {
692
- summaryText = `Encontrei ${count} registro(s) relacionados a "${query}".`;
707
+ let answerText = String(answer || '').trim();
708
+ if (!answerText) {
709
+ if (!summaryText) {
710
+ if (count === 0) {
711
+ summaryText = `Não encontrei registros relacionados a "${query}".`;
712
+ } else {
713
+ summaryText = `Encontrei ${count} registro(s) relacionados a "${query}".`;
714
+ }
693
715
  }
716
+ answerText = summaryText;
694
717
  }
695
718
 
696
719
  const lines = [];
697
720
  lines.push(`Encontrei ${count} registro(s).`);
698
- lines.push(`Resumo (${count} registro(s)): ${summaryText}`);
721
+ lines.push(`Resumo: ${answerText}`);
722
+
723
+ const evidences = Array.isArray(evidence) && evidence.length
724
+ ? evidence
725
+ : matches.slice(0, 5).map((m) => ({ file: m.file, date: m.date, detail: m.snippet }));
726
+
727
+ if (!evidences.length) return lines.join('\n');
699
728
 
700
- for (const m of matches) {
729
+ lines.push('');
730
+ lines.push('Principais evidências:');
731
+ for (const m of evidences.slice(0, 5)) {
701
732
  const parts = [];
702
733
  if (m.date) parts.push(`**${m.date}**`);
703
734
  if (m.file) parts.push('`' + m.file + '`');
704
735
  const prefix = parts.length ? parts.join(' — ') + ':' : '';
705
- const snippet = m.snippet ? String(m.snippet).trim() : '';
706
- lines.push(`- ${prefix} ${snippet}`);
736
+ const detail = (m.detail || m.snippet || '').toString().trim();
737
+ if (!detail) continue;
738
+ lines.push(`- ${prefix} ${detail}`);
707
739
  }
708
740
 
709
741
  return lines.join('\n');
@@ -1727,7 +1759,13 @@ async function cmdWeb({ port, dir, open, dev }) {
1727
1759
  const copilotResult = await copilotSearch(workspaceDir, query, { limit: 8 });
1728
1760
  if (copilotResult.ok) {
1729
1761
  const matches = copilotResult.matches || [];
1730
- const answer = buildChatAnswer(query, matches, copilotResult.summary);
1762
+ const answer = buildChatAnswer(
1763
+ query,
1764
+ matches,
1765
+ copilotResult.summary,
1766
+ copilotResult.evidence,
1767
+ copilotResult.answer
1768
+ );
1731
1769
  return safeJson(res, 200, { ok: true, sessionId, answer, matches });
1732
1770
  }
1733
1771
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cccarv82/freya",
3
- "version": "1.0.49",
3
+ "version": "1.0.51",
4
4
  "description": "Personal AI Assistant with local-first persistence",
5
5
  "scripts": {
6
6
  "health": "node scripts/validate-data.js",