@cccarv82/freya 1.0.50 → 1.0.52
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.js +73 -19
- package/package.json +1 -1
package/cli/web.js
CHANGED
|
@@ -8,6 +8,28 @@ const { spawn } = require('child_process');
|
|
|
8
8
|
const { searchWorkspace } = require('../scripts/lib/search-utils');
|
|
9
9
|
const { searchIndex } = require('../scripts/lib/index-utils');
|
|
10
10
|
|
|
11
|
+
function readAppVersion() {
|
|
12
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
13
|
+
try {
|
|
14
|
+
const json = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
15
|
+
if (json && typeof json.version === 'string' && json.version.trim() !== '') return json.version.trim();
|
|
16
|
+
} catch {
|
|
17
|
+
// Fall back below.
|
|
18
|
+
}
|
|
19
|
+
return 'unknown';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function escapeHtml(str) {
|
|
23
|
+
return String(str)
|
|
24
|
+
.replace(/&/g, '&')
|
|
25
|
+
.replace(/</g, '<')
|
|
26
|
+
.replace(/>/g, '>')
|
|
27
|
+
.replace(/"/g, '"')
|
|
28
|
+
.replace(/'/g, ''');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const APP_VERSION = readAppVersion();
|
|
32
|
+
|
|
11
33
|
function guessNpmCmd() {
|
|
12
34
|
// We'll execute via cmd.exe on Windows for reliability.
|
|
13
35
|
return process.platform === 'win32' ? 'npm' : 'npm';
|
|
@@ -631,11 +653,11 @@ async function copilotSearch(workspaceDir, query, opts = {}) {
|
|
|
631
653
|
`Consulta do usuário: "${q}"`,
|
|
632
654
|
'',
|
|
633
655
|
'Responda APENAS com JSON válido (sem code fences) no formato:',
|
|
634
|
-
'{"
|
|
656
|
+
'{"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>"}]}',
|
|
635
657
|
`Limite de matches: ${limit}.`,
|
|
636
|
-
'
|
|
658
|
+
'A resposta deve soar humana, bem escrita, sem repetições, e mencionar a quantidade de registros encontrados.',
|
|
637
659
|
'Priorize responder exatamente à pergunta (ex.: data e ID da última CHG).',
|
|
638
|
-
'
|
|
660
|
+
'Na seção evidence, escreva evidências curtas e não repetidas (máx 5).',
|
|
639
661
|
'A lista deve estar ordenada por relevância.'
|
|
640
662
|
].join('\n');
|
|
641
663
|
|
|
@@ -682,36 +704,60 @@ async function copilotSearch(workspaceDir, query, opts = {}) {
|
|
|
682
704
|
.filter((m) => m.file && isAllowedChatSearchPath(m.file))
|
|
683
705
|
.slice(0, limit);
|
|
684
706
|
|
|
685
|
-
const
|
|
686
|
-
|
|
707
|
+
const evidenceRaw = Array.isArray(parsed.evidence) ? parsed.evidence : [];
|
|
708
|
+
const evidence = evidenceRaw
|
|
709
|
+
.map((m) => {
|
|
710
|
+
const fileRaw = String(m && m.file ? m.file : '').trim();
|
|
711
|
+
const dateRaw = String(m && m.date ? m.date : '').trim();
|
|
712
|
+
const detailRaw = String(m && m.detail ? m.detail : '').trim();
|
|
713
|
+
let rel = fileRaw;
|
|
714
|
+
if (fileRaw.startsWith(workspaceDir)) {
|
|
715
|
+
rel = path.relative(workspaceDir, fileRaw).replace(/\\/g, '/');
|
|
716
|
+
}
|
|
717
|
+
return { file: rel.replace(/\\/g, '/'), date: dateRaw, detail: detailRaw };
|
|
718
|
+
})
|
|
719
|
+
.filter((m) => m.file && m.detail && isAllowedChatSearchPath(m.file))
|
|
720
|
+
.slice(0, 5);
|
|
721
|
+
|
|
722
|
+
const answer = String(parsed.answer || '').trim();
|
|
723
|
+
return { ok: true, answer, matches, evidence };
|
|
687
724
|
}
|
|
688
725
|
|
|
689
|
-
function buildChatAnswer(query, matches, summary) {
|
|
726
|
+
function buildChatAnswer(query, matches, summary, evidence, answer) {
|
|
690
727
|
const count = matches.length;
|
|
691
728
|
let summaryText = String(summary || '').trim();
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
729
|
+
let answerText = String(answer || '').trim();
|
|
730
|
+
if (!answerText) {
|
|
731
|
+
if (!summaryText) {
|
|
732
|
+
if (count === 0) {
|
|
733
|
+
summaryText = `Não encontrei registros relacionados a "${query}".`;
|
|
734
|
+
} else {
|
|
735
|
+
summaryText = `Encontrei ${count} registro(s) relacionados a "${query}".`;
|
|
736
|
+
}
|
|
697
737
|
}
|
|
738
|
+
answerText = summaryText;
|
|
698
739
|
}
|
|
699
740
|
|
|
700
741
|
const lines = [];
|
|
701
742
|
lines.push(`Encontrei ${count} registro(s).`);
|
|
702
|
-
lines.push(`Resumo: ${
|
|
743
|
+
lines.push(`Resumo: ${answerText}`);
|
|
744
|
+
|
|
745
|
+
const evidences = Array.isArray(evidence) && evidence.length
|
|
746
|
+
? evidence
|
|
747
|
+
: matches.slice(0, 5).map((m) => ({ file: m.file, date: m.date, detail: m.snippet }));
|
|
703
748
|
|
|
704
|
-
if (!
|
|
749
|
+
if (!evidences.length) return lines.join('\n');
|
|
705
750
|
|
|
706
751
|
lines.push('');
|
|
707
752
|
lines.push('Principais evidências:');
|
|
708
|
-
for (const m of
|
|
753
|
+
for (const m of evidences.slice(0, 5)) {
|
|
709
754
|
const parts = [];
|
|
710
755
|
if (m.date) parts.push(`**${m.date}**`);
|
|
711
756
|
if (m.file) parts.push('`' + m.file + '`');
|
|
712
757
|
const prefix = parts.length ? parts.join(' — ') + ':' : '';
|
|
713
|
-
const
|
|
714
|
-
|
|
758
|
+
const detail = (m.detail || m.snippet || '').toString().trim();
|
|
759
|
+
if (!detail) continue;
|
|
760
|
+
lines.push(`- ${prefix} ${detail}`);
|
|
715
761
|
}
|
|
716
762
|
|
|
717
763
|
return lines.join('\n');
|
|
@@ -771,10 +817,11 @@ async function pickDirectoryNative() {
|
|
|
771
817
|
function html(defaultDir) {
|
|
772
818
|
// Aesthetic: “clean workstation” — light-first UI inspired by modern productivity apps.
|
|
773
819
|
const safeDefault = String(defaultDir || './freya').replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
774
|
-
return buildHtml(safeDefault);
|
|
820
|
+
return buildHtml(safeDefault, APP_VERSION);
|
|
775
821
|
}
|
|
776
822
|
|
|
777
|
-
function buildHtml(safeDefault) {
|
|
823
|
+
function buildHtml(safeDefault, appVersion) {
|
|
824
|
+
const safeVersion = escapeHtml(appVersion || 'unknown');
|
|
778
825
|
return `<!doctype html>
|
|
779
826
|
<html>
|
|
780
827
|
<head>
|
|
@@ -837,6 +884,7 @@ function buildHtml(safeDefault) {
|
|
|
837
884
|
<div class="topbar">
|
|
838
885
|
<div class="brand"><span class="spark"></span> Assistente de status local-first</div>
|
|
839
886
|
<div class="actions">
|
|
887
|
+
<span class="chip" id="chipVersion">v${safeVersion}</span>
|
|
840
888
|
<span class="chip" id="chipPort">127.0.0.1:3872</span>
|
|
841
889
|
<button class="toggle" id="themeToggle" onclick="toggleTheme()">Escuro</button>
|
|
842
890
|
</div>
|
|
@@ -1735,7 +1783,13 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
1735
1783
|
const copilotResult = await copilotSearch(workspaceDir, query, { limit: 8 });
|
|
1736
1784
|
if (copilotResult.ok) {
|
|
1737
1785
|
const matches = copilotResult.matches || [];
|
|
1738
|
-
const answer = buildChatAnswer(
|
|
1786
|
+
const answer = buildChatAnswer(
|
|
1787
|
+
query,
|
|
1788
|
+
matches,
|
|
1789
|
+
copilotResult.summary,
|
|
1790
|
+
copilotResult.evidence,
|
|
1791
|
+
copilotResult.answer
|
|
1792
|
+
);
|
|
1739
1793
|
return safeJson(res, 200, { ok: true, sessionId, answer, matches });
|
|
1740
1794
|
}
|
|
1741
1795
|
|