@cccarv82/freya 1.0.18 → 1.0.20
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 +86 -13
- package/package.json +1 -1
package/cli/web.js
CHANGED
|
@@ -182,6 +182,52 @@ function postTeamsWebhook(url, text) {
|
|
|
182
182
|
return postJson(url, { text });
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
function escapeJsonControlChars(jsonText) {
|
|
186
|
+
// Replace unescaped control chars inside JSON string literals with safe escapes.
|
|
187
|
+
// Handles Copilot outputs where newlines/tabs leak into string values.
|
|
188
|
+
const out = [];
|
|
189
|
+
let inString = false;
|
|
190
|
+
let esc = false;
|
|
191
|
+
|
|
192
|
+
for (let i = 0; i < jsonText.length; i++) {
|
|
193
|
+
const ch = jsonText[i];
|
|
194
|
+
const code = ch.charCodeAt(0);
|
|
195
|
+
|
|
196
|
+
if (esc) {
|
|
197
|
+
out.push(ch);
|
|
198
|
+
esc = false;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (ch === '\\') {
|
|
203
|
+
out.push(ch);
|
|
204
|
+
esc = true;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (ch === '"') {
|
|
209
|
+
out.push(ch);
|
|
210
|
+
inString = !inString;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (inString) {
|
|
215
|
+
if (code === 10) { out.push('\\n'); continue; }
|
|
216
|
+
if (code === 13) { out.push('\\r'); continue; }
|
|
217
|
+
if (code === 9) { out.push('\\t'); continue; }
|
|
218
|
+
if (code >= 0 && code < 32) {
|
|
219
|
+
const hex = code.toString(16).padStart(2, '0');
|
|
220
|
+
out.push('\\u00' + hex);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
out.push(ch);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return out.join('');
|
|
229
|
+
}
|
|
230
|
+
|
|
185
231
|
async function publishRobust(webhookUrl, text, opts = {}) {
|
|
186
232
|
const u = new URL(webhookUrl);
|
|
187
233
|
const isDiscord = u.hostname.includes('discord.com') || u.hostname.includes('discordapp.com');
|
|
@@ -353,12 +399,11 @@ function buildHtml(safeDefault) {
|
|
|
353
399
|
<div class="sideGroup">
|
|
354
400
|
<div class="sideTitle">Workspace</div>
|
|
355
401
|
<button class="btn sideBtn" onclick="pickDir()">Select workspace…</button>
|
|
356
|
-
<button class="btn
|
|
357
|
-
<button class="btn sideBtn" onclick="
|
|
358
|
-
<button class="btn sideBtn" onclick="doHealth()">Health</button>
|
|
359
|
-
<button class="btn sideBtn" onclick="doMigrate()">Migrate</button>
|
|
402
|
+
<button class="btn sideBtn" onclick="doUpdate()">Sync workspace</button>
|
|
403
|
+
<button class="btn sideBtn" onclick="doMigrate()">Migrate data</button>
|
|
360
404
|
<div style="height:10px"></div>
|
|
361
|
-
<div class="help">
|
|
405
|
+
<div class="help"><b>Sync workspace</b>: atualiza scripts/templates/agents na pasta <code>freya</code> sem sobrescrever <code>data/</code> e <code>logs/</code>.</div>
|
|
406
|
+
<div class="help"><b>Migrate data</b>: ajusta formatos/schemaVersion quando uma versão nova exige.</div>
|
|
362
407
|
</div>
|
|
363
408
|
|
|
364
409
|
<div class="sideGroup">
|
|
@@ -793,7 +838,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
793
838
|
]
|
|
794
839
|
};
|
|
795
840
|
|
|
796
|
-
const prompt = `Você é o planner do sistema F.R.E.Y.A.\n\nContexto: vamos receber um input bruto do usuário e propor ações estruturadas.\nRegras: siga os arquivos de regras abaixo.\nSaída: retorne APENAS JSON válido no formato: ${JSON.stringify(schema)}\n\nREGRAS:${rulesText}\n\nINPUT DO USUÁRIO:\n${text}\n`;
|
|
841
|
+
const prompt = `Você é o planner do sistema F.R.E.Y.A.\n\nContexto: vamos receber um input bruto do usuário e propor ações estruturadas.\nRegras: siga os arquivos de regras abaixo.\nSaída: retorne APENAS JSON válido no formato: ${JSON.stringify(schema)}\n\nRestrições:\n- NÃO use code fences (\`\`\`)\n- NÃO inclua texto extra antes/depois do JSON\n- NÃO use quebras de linha dentro de strings (transforme em uma frase única)\n\nREGRAS:${rulesText}\n\nINPUT DO USUÁRIO:\n${text}\n`;
|
|
797
842
|
|
|
798
843
|
// Prefer COPILOT_CMD if provided, otherwise try 'copilot'
|
|
799
844
|
const cmd = process.env.COPILOT_CMD || 'copilot';
|
|
@@ -836,7 +881,15 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
836
881
|
try {
|
|
837
882
|
plan = JSON.parse(jsonText);
|
|
838
883
|
} catch (e) {
|
|
839
|
-
|
|
884
|
+
try {
|
|
885
|
+
plan = JSON.parse(escapeJsonControlChars(jsonText));
|
|
886
|
+
} catch (e2) {
|
|
887
|
+
return safeJson(res, 400, {
|
|
888
|
+
error: 'Plan is not valid JSON',
|
|
889
|
+
details: (e2 && e2.message) ? e2.message : (e && e.message ? e.message : String(e)),
|
|
890
|
+
hint: 'O planner gerou caracteres de controle dentro de strings (ex.: quebra de linha). Reexecute o planner ou escape quebras de linha como \\n.'
|
|
891
|
+
});
|
|
892
|
+
}
|
|
840
893
|
}
|
|
841
894
|
|
|
842
895
|
const actions = Array.isArray(plan.actions) ? plan.actions : [];
|
|
@@ -914,15 +967,35 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
914
967
|
}
|
|
915
968
|
|
|
916
969
|
const jsonText = extractJson(planRaw) || planRaw;
|
|
970
|
+
|
|
971
|
+
function errorSnippet(text, pos) {
|
|
972
|
+
const p = Number.isFinite(pos) ? pos : 0;
|
|
973
|
+
const start = Math.max(0, p - 60);
|
|
974
|
+
const end = Math.min(text.length, p + 60);
|
|
975
|
+
const slice = text.slice(start, end);
|
|
976
|
+
const codes = Array.from(slice).map((ch) => ch.charCodeAt(0));
|
|
977
|
+
return { start, end, slice, codes };
|
|
978
|
+
}
|
|
979
|
+
|
|
917
980
|
let plan;
|
|
918
981
|
try {
|
|
919
982
|
plan = JSON.parse(jsonText);
|
|
920
983
|
} catch (e) {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
984
|
+
// Attempt repair for common control-character issues
|
|
985
|
+
try {
|
|
986
|
+
plan = JSON.parse(escapeJsonControlChars(jsonText));
|
|
987
|
+
} catch (e2) {
|
|
988
|
+
return safeJson(res, 400, {
|
|
989
|
+
error: 'Plan is not valid JSON',
|
|
990
|
+
details: (e2 && e2.message) ? e2.message : ((e && e.message) ? e.message : String(e)),
|
|
991
|
+
hint: 'O planner gerou caracteres de controle dentro de strings (ex.: quebra de linha literal). Reexecute o planner; ou escape quebras de linha como \\n.',
|
|
992
|
+
snippet: (() => {
|
|
993
|
+
const m2 = /position (\d+)/.exec(((e2 && e2.message) ? e2.message : ((e && e.message) ? e.message : '')));
|
|
994
|
+
const pos = m2 ? Number(m2[1]) : NaN;
|
|
995
|
+
return errorSnippet(jsonText, pos);
|
|
996
|
+
})()
|
|
997
|
+
});
|
|
998
|
+
}
|
|
926
999
|
}
|
|
927
1000
|
|
|
928
1001
|
const actions = Array.isArray(plan.actions) ? plan.actions : [];
|
|
@@ -942,7 +1015,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
942
1015
|
if (typeof blockerLog.schemaVersion !== 'number') blockerLog.schemaVersion = 1;
|
|
943
1016
|
|
|
944
1017
|
function normalizeTextForKey(t) {
|
|
945
|
-
return String(t || '').toLowerCase().replace(
|
|
1018
|
+
return String(t || '').toLowerCase().replace(/\s+/g, ' ').trim();
|
|
946
1019
|
}
|
|
947
1020
|
|
|
948
1021
|
function sha1(text) {
|