@cccarv82/freya 2.20.0 → 3.1.0
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/.agent/rules/freya/agents/analytics-agent.mdc +161 -0
- package/.agent/rules/freya/agents/coach.mdc +94 -62
- package/.agent/rules/freya/agents/ingestor.mdc +99 -101
- package/.agent/rules/freya/agents/master.mdc +140 -67
- package/.agent/rules/freya/agents/oracle.mdc +111 -99
- package/.agent/rules/freya/agents/sm-agent.mdc +133 -0
- package/.agent/rules/freya/freya.mdc +78 -32
- package/cli/web-ui.css +0 -132
- package/cli/web-ui.js +156 -211
- package/cli/web.js +52 -93
- package/package.json +1 -1
- package/templates/base/.agent/rules/freya/agents/analytics-agent.mdc +161 -0
- package/templates/base/.agent/rules/freya/agents/coach.mdc +94 -62
- package/templates/base/.agent/rules/freya/agents/ingestor.mdc +99 -101
- package/templates/base/.agent/rules/freya/agents/master.mdc +140 -67
- package/templates/base/.agent/rules/freya/agents/oracle.mdc +111 -99
- package/templates/base/.agent/rules/freya/agents/sm-agent.mdc +133 -0
- package/templates/base/.agent/rules/freya/freya.mdc +78 -32
package/cli/web.js
CHANGED
|
@@ -1192,14 +1192,9 @@ function buildHtml(safeDefault, appVersion) {
|
|
|
1192
1192
|
</div>
|
|
1193
1193
|
|
|
1194
1194
|
<!-- Textarea -->
|
|
1195
|
-
<textarea id="inboxText" aria-label="Entrada de texto para processar ou perguntar" placeholder="Cole updates, decisões, blockers... ou faça uma pergunta à Freya. ▸ Salvar & Processar → extrai tarefas e blockers do texto ▸ Perguntar → consulta o histórico via busca semântica (RAG)
|
|
1195
|
+
<textarea id="inboxText" aria-label="Entrada de texto para processar ou perguntar" placeholder="Cole updates, decisões, blockers... ou faça uma pergunta à Freya. ▸ Salvar & Processar → extrai tarefas e blockers do texto ▸ Perguntar → consulta o histórico via busca semântica (RAG)" style="resize:none; min-height: 200px; flex: 1; border-radius: 0; border-left: none; border-right: none; border-top: none; border-bottom: 1px solid var(--border); padding: 14px 16px; font-size: 13px; line-height: 1.6;"
|
|
1196
1196
|
onkeydown="if((event.metaKey||event.ctrlKey)&&event.key==='Enter'){event.preventDefault();window.saveAndPlan();}"></textarea>
|
|
1197
1197
|
|
|
1198
|
-
<!-- Image paste preview strip -->
|
|
1199
|
-
<div id="pastePreview" style="display:none; padding: 8px 14px; border-bottom: 1px solid var(--border); background: rgba(0,0,0,0.05); flex-shrink:0;">
|
|
1200
|
-
<div style="display:flex; align-items:center; gap:8px; flex-wrap:wrap;" id="pastePreviewInner"></div>
|
|
1201
|
-
</div>
|
|
1202
|
-
|
|
1203
1198
|
<!-- Actions bar -->
|
|
1204
1199
|
<div style="padding: 10px 14px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; flex-shrink:0;">
|
|
1205
1200
|
<div style="display:flex; gap:8px; flex-wrap:wrap;">
|
|
@@ -1351,13 +1346,6 @@ function buildHtml(safeDefault, appVersion) {
|
|
|
1351
1346
|
</div>
|
|
1352
1347
|
</div>
|
|
1353
1348
|
|
|
1354
|
-
<!-- Image lightbox modal -->
|
|
1355
|
-
<div id="imgLightbox" class="img-lightbox" onclick="window.closeLightbox(event)">
|
|
1356
|
-
<button class="img-lightbox-close" onclick="window.closeLightbox(event)" title="Fechar (Esc)">×</button>
|
|
1357
|
-
<img id="imgLightboxImg" src="" alt="preview" onclick="event.stopPropagation()" />
|
|
1358
|
-
<div id="imgLightboxName" class="img-lightbox-name"></div>
|
|
1359
|
-
</div>
|
|
1360
|
-
|
|
1361
1349
|
<script>
|
|
1362
1350
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
1363
1351
|
</script>
|
|
@@ -2408,26 +2396,25 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
2408
2396
|
return;
|
|
2409
2397
|
}
|
|
2410
2398
|
|
|
2411
|
-
// Serve attachment images
|
|
2399
|
+
// Serve attachment images from workspace data/attachments/
|
|
2412
2400
|
if (req.method === 'GET' && req.url.startsWith('/attachments/')) {
|
|
2413
|
-
const
|
|
2401
|
+
const fname = decodeURIComponent(req.url.slice('/attachments/'.length)).replace(/[\/\\]/g, '');
|
|
2414
2402
|
const requestedDir = dir || './freya';
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
if (!filePath
|
|
2419
|
-
res.writeHead(
|
|
2420
|
-
|
|
2421
|
-
if (exists(filePath)) {
|
|
2422
|
-
const ext = path.extname(filePath).toLowerCase();
|
|
2423
|
-
const mimeMap = { '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp', '.bmp': 'image/bmp' };
|
|
2424
|
-
const mime = mimeMap[ext] || 'application/octet-stream';
|
|
2425
|
-
const data = fs.readFileSync(filePath);
|
|
2426
|
-
res.writeHead(200, { 'Content-Type': mime, 'Cache-Control': 'public, max-age=86400' });
|
|
2427
|
-
res.end(data);
|
|
2403
|
+
let wsDir;
|
|
2404
|
+
try { wsDir = normalizeWorkspaceDir(requestedDir); } catch { wsDir = path.resolve(process.cwd(), requestedDir); }
|
|
2405
|
+
const filePath = path.join(wsDir, 'data', 'attachments', fname);
|
|
2406
|
+
if (!exists(filePath)) {
|
|
2407
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
2408
|
+
res.end('Not found');
|
|
2428
2409
|
return;
|
|
2429
2410
|
}
|
|
2430
|
-
|
|
2411
|
+
const ext = path.extname(fname).toLowerCase();
|
|
2412
|
+
const mimeMap = { '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp', '.bmp': 'image/bmp', '.svg': 'image/svg+xml' };
|
|
2413
|
+
const mime = mimeMap[ext] || 'application/octet-stream';
|
|
2414
|
+
const data = fs.readFileSync(filePath);
|
|
2415
|
+
res.writeHead(200, { 'Content-Type': mime, 'Cache-Control': 'max-age=86400' });
|
|
2416
|
+
res.end(data);
|
|
2417
|
+
return;
|
|
2431
2418
|
}
|
|
2432
2419
|
|
|
2433
2420
|
if (req.url.startsWith('/api/')) {
|
|
@@ -3240,30 +3227,9 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3240
3227
|
}
|
|
3241
3228
|
}
|
|
3242
3229
|
|
|
3243
|
-
// ── Upload attachment (image paste) ──────────────────────────
|
|
3244
|
-
if (req.url === '/api/attachments/upload') {
|
|
3245
|
-
const data = String(payload.data || '').trim();
|
|
3246
|
-
const fname = String(payload.filename || '').trim();
|
|
3247
|
-
if (!data || !fname) return safeJson(res, 400, { error: 'Missing data or filename' });
|
|
3248
|
-
|
|
3249
|
-
const d = isoDate();
|
|
3250
|
-
const attDir = path.join(workspaceDir, 'data', 'attachments', d);
|
|
3251
|
-
ensureDir(attDir);
|
|
3252
|
-
|
|
3253
|
-
// data is base64 (may have data:image/... prefix)
|
|
3254
|
-
const base64 = data.replace(/^data:image\/[^;]+;base64,/, '');
|
|
3255
|
-
const buf = Buffer.from(base64, 'base64');
|
|
3256
|
-
const filePath = path.join(attDir, fname);
|
|
3257
|
-
fs.writeFileSync(filePath, buf);
|
|
3258
|
-
|
|
3259
|
-
const relPath = `data/attachments/${d}/${fname}`;
|
|
3260
|
-
return safeJson(res, 200, { ok: true, path: relPath });
|
|
3261
|
-
}
|
|
3262
|
-
|
|
3263
3230
|
if (req.url === '/api/inbox/add') {
|
|
3264
3231
|
const text = String(payload.text || '').trim();
|
|
3265
|
-
|
|
3266
|
-
if (!text && !attachments.length) return safeJson(res, 400, { error: 'Missing text' });
|
|
3232
|
+
if (!text) return safeJson(res, 400, { error: 'Missing text' });
|
|
3267
3233
|
|
|
3268
3234
|
const d = isoDate();
|
|
3269
3235
|
const file = path.join(workspaceDir, 'logs', 'daily', `${d}.md`);
|
|
@@ -3277,13 +3243,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3277
3243
|
const linksText = linkInfo && linkInfo.linksText ? linkInfo.linksText : '';
|
|
3278
3244
|
const slugs = linkInfo && Array.isArray(linkInfo.slugs) ? linkInfo.slugs : [];
|
|
3279
3245
|
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
if (attachments.length) {
|
|
3283
|
-
attachBlock = '\n\n**Anexos:**\n' + attachments.map(a => ``).join('\n');
|
|
3284
|
-
}
|
|
3285
|
-
|
|
3286
|
-
const block = `\n\n## [${hh}:${mm}] Raw Input\n${text}${linksText}${attachBlock}\n`;
|
|
3246
|
+
const imgRef = payload.imagePath ? `\n` : '';
|
|
3247
|
+
const block = `\n\n## [${hh}:${mm}] Raw Input\n${text}${imgRef}${linksText}\n`;
|
|
3287
3248
|
fs.appendFileSync(file, block, 'utf8');
|
|
3288
3249
|
|
|
3289
3250
|
if (slugs.length) {
|
|
@@ -3342,16 +3303,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3342
3303
|
]
|
|
3343
3304
|
};
|
|
3344
3305
|
|
|
3345
|
-
|
|
3346
|
-
const attachments = Array.isArray(payload.attachments) ? payload.attachments : [];
|
|
3347
|
-
let imageContext = '';
|
|
3348
|
-
if (attachments.length) {
|
|
3349
|
-
imageContext = '\n\nIMAGENS ANEXADAS (use @caminho para analisar):\n' +
|
|
3350
|
-
attachments.map(a => `- @${path.join(workspaceDir, a.path)} (${a.name})`).join('\n') + '\n' +
|
|
3351
|
-
'Analise as imagens anexadas e inclua as informações visuais no plano.\n';
|
|
3352
|
-
}
|
|
3353
|
-
|
|
3354
|
-
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}${imageContext}\n\nINPUT DO USUÁRIO:\n${text}\n`;
|
|
3306
|
+
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`;
|
|
3355
3307
|
|
|
3356
3308
|
// Prefer COPILOT_CMD if provided, otherwise try 'copilot'
|
|
3357
3309
|
const cmd = process.env.COPILOT_CMD || 'copilot';
|
|
@@ -3361,7 +3313,7 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3361
3313
|
// BUG-48: pass FREYA_WORKSPACE_DIR so the Copilot subprocess uses correct DB
|
|
3362
3314
|
const agentEnv = { FREYA_WORKSPACE_DIR: workspaceDir };
|
|
3363
3315
|
try {
|
|
3364
|
-
const r = await run(cmd, ['-s', '--no-color', '--stream', 'off', '-p', prompt, '--allow-all-tools'
|
|
3316
|
+
const r = await run(cmd, ['-s', '--no-color', '--stream', 'off', '-p', prompt, '--allow-all-tools'], workspaceDir, agentEnv);
|
|
3365
3317
|
const out = (r.stdout + r.stderr).trim();
|
|
3366
3318
|
if (r.code !== 0) {
|
|
3367
3319
|
return safeJson(res, 200, {
|
|
@@ -3707,9 +3659,25 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3707
3659
|
return safeJson(res, r.code === 0 ? 200 : 400, r.code === 0 ? { ok: true, output: out } : { error: out || 'index rebuild failed', output: out });
|
|
3708
3660
|
}
|
|
3709
3661
|
|
|
3662
|
+
// Upload attachment (base64 image from clipboard paste)
|
|
3663
|
+
if (req.url === '/api/attachments/upload') {
|
|
3664
|
+
const base64 = String(payload.data || '').trim();
|
|
3665
|
+
const mimeType = String(payload.mimeType || 'image/png').trim();
|
|
3666
|
+
if (!base64) return safeJson(res, 400, { error: 'Missing data' });
|
|
3667
|
+
const ext = mimeType === 'image/jpeg' ? '.jpg' : mimeType === 'image/gif' ? '.gif' : mimeType === 'image/webp' ? '.webp' : '.png';
|
|
3668
|
+
const fname = 'paste-' + Date.now() + ext;
|
|
3669
|
+
const attachDir = path.join(workspaceDir, 'data', 'attachments');
|
|
3670
|
+
if (!exists(attachDir)) fs.mkdirSync(attachDir, { recursive: true });
|
|
3671
|
+
const filePath = path.join(attachDir, fname);
|
|
3672
|
+
const buf = Buffer.from(base64, 'base64');
|
|
3673
|
+
fs.writeFileSync(filePath, buf);
|
|
3674
|
+
return safeJson(res, 200, { ok: true, filename: fname, url: '/attachments/' + fname });
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3710
3677
|
if (req.url === '/api/chat/ask') {
|
|
3711
3678
|
const sessionId = String(payload.sessionId || '').trim();
|
|
3712
3679
|
const query = String(payload.query || '').trim();
|
|
3680
|
+
const imagePath = payload.imagePath ? String(payload.imagePath).trim() : null;
|
|
3713
3681
|
if (!query) return safeJson(res, 400, { error: 'Missing query' });
|
|
3714
3682
|
|
|
3715
3683
|
const workspaceRulesBase = path.join(workspaceDir, '.agent', 'rules', 'freya');
|
|
@@ -3742,27 +3710,23 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3742
3710
|
console.error('[oracle] RAG search failed (embedder/sharp unavailable), continuing without context:', ragErr.message);
|
|
3743
3711
|
}
|
|
3744
3712
|
|
|
3745
|
-
|
|
3746
|
-
const askAttachments = Array.isArray(payload.attachments) ? payload.attachments : [];
|
|
3747
|
-
let askImageContext = '';
|
|
3748
|
-
const askHasImages = askAttachments.length > 0;
|
|
3749
|
-
if (askHasImages) {
|
|
3750
|
-
askImageContext = '\n\nIMAGENS ANEXADAS (use @caminho para analisar):\n' +
|
|
3751
|
-
askAttachments.map(a => `- @${path.join(workspaceDir, a.path)} (${a.name})`).join('\n') + '\n' +
|
|
3752
|
-
'Analise as imagens anexadas e use-as como contexto para responder à consulta.\n';
|
|
3753
|
-
}
|
|
3754
|
-
|
|
3755
|
-
const prompt = `Você é o agente Oracle do sistema F.R.E.Y.A.\n\nSiga estritamente os arquivos de regras abaixo.\nResponda de forma analítica e consultiva.\n${ragContext}${askImageContext}\n\nREGRAS:${rulesText}\n\nCONSULTA DO USUÁRIO:\n${query}\n`;
|
|
3713
|
+
const prompt = `Você é o agente Oracle do sistema F.R.E.Y.A.\n\nSiga estritamente os arquivos de regras abaixo.\nResponda de forma analítica e consultiva.\n${ragContext}\n\nREGRAS:${rulesText}\n\nCONSULTA DO USUÁRIO:\n${query}\n`;
|
|
3756
3714
|
|
|
3757
3715
|
const cmd = process.env.COPILOT_CMD || 'copilot';
|
|
3758
3716
|
|
|
3759
3717
|
// BUG-48: pass FREYA_WORKSPACE_DIR so the Copilot subprocess uses correct DB
|
|
3760
3718
|
const oracleEnv = { FREYA_WORKSPACE_DIR: workspaceDir };
|
|
3761
3719
|
try {
|
|
3762
|
-
//
|
|
3763
|
-
const
|
|
3764
|
-
if (
|
|
3765
|
-
|
|
3720
|
+
// Build copilot args; add image if user pasted a screenshot
|
|
3721
|
+
const copilotArgs = ['-s', '--no-color', '--stream', 'off'];
|
|
3722
|
+
if (imagePath) {
|
|
3723
|
+
const absImg = path.isAbsolute(imagePath) ? imagePath : path.join(workspaceDir, imagePath);
|
|
3724
|
+
if (exists(absImg)) {
|
|
3725
|
+
copilotArgs.push('--add-image', absImg);
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
copilotArgs.push('-p', prompt);
|
|
3729
|
+
const r = await run(cmd, copilotArgs, workspaceDir, oracleEnv);
|
|
3766
3730
|
const out = (r.stdout + r.stderr).trim();
|
|
3767
3731
|
if (r.code !== 0) {
|
|
3768
3732
|
return safeJson(res, 200, { ok: false, answer: 'Falha na busca do agente Oracle:\n' + (out || 'Exit code != 0'), sessionId });
|
|
@@ -3893,7 +3857,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3893
3857
|
|
|
3894
3858
|
const rawTasks = dl.db.prepare(query).all(...params);
|
|
3895
3859
|
const tasks = rawTasks.map(t => {
|
|
3896
|
-
|
|
3860
|
+
let meta = {};
|
|
3861
|
+
try { meta = t.metadata ? JSON.parse(t.metadata) : {}; } catch (_) {}
|
|
3897
3862
|
return {
|
|
3898
3863
|
id: t.id,
|
|
3899
3864
|
description: t.description,
|
|
@@ -4091,7 +4056,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
4091
4056
|
|
|
4092
4057
|
const rawBlockers = dl.db.prepare(query).all(...params);
|
|
4093
4058
|
const blockers = rawBlockers.map(b => {
|
|
4094
|
-
|
|
4059
|
+
let meta = {};
|
|
4060
|
+
try { meta = b.metadata ? JSON.parse(b.metadata) : {}; } catch (_) {}
|
|
4095
4061
|
return {
|
|
4096
4062
|
id: b.id,
|
|
4097
4063
|
title: b.title,
|
|
@@ -4671,13 +4637,6 @@ function buildKanbanHtml(safeDefault, appVersion) {
|
|
|
4671
4637
|
</div>
|
|
4672
4638
|
</div>
|
|
4673
4639
|
|
|
4674
|
-
<!-- Image lightbox modal -->
|
|
4675
|
-
<div id="imgLightbox" class="img-lightbox" onclick="window.closeLightbox(event)">
|
|
4676
|
-
<button class="img-lightbox-close" onclick="window.closeLightbox(event)" title="Fechar (Esc)">×</button>
|
|
4677
|
-
<img id="imgLightboxImg" src="" alt="preview" onclick="event.stopPropagation()" />
|
|
4678
|
-
<div id="imgLightboxName" class="img-lightbox-name"></div>
|
|
4679
|
-
</div>
|
|
4680
|
-
|
|
4681
4640
|
<script>
|
|
4682
4641
|
window.__FREYA_DEFAULT_DIR = "${safeDefault}";
|
|
4683
4642
|
</script>
|
package/package.json
CHANGED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: F.R.E.Y.A. Analytics Super Agent
|
|
3
|
+
globs:
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Analytics Agent — Super Agent (FREYA)
|
|
8
|
+
|
|
9
|
+
You are the **Analytics Super Agent** — responsible for generating insights, detecting patterns, and providing intelligence augmentation. You receive instructions from the Orchestrator and coordinate Utility Agents (Oracle, Coach) to deliver actionable intelligence.
|
|
10
|
+
|
|
11
|
+
## Role & Responsibilities
|
|
12
|
+
|
|
13
|
+
- **Cross-cutting analysis**: Combine data from multiple projects, time ranges, and domains
|
|
14
|
+
- **Pattern detection**: Identify recurring blockers, velocity trends, risk patterns
|
|
15
|
+
- **Career intelligence**: Coordinate with Coach for career-related analysis
|
|
16
|
+
- **Proactive insights**: Surface information the user didn't explicitly ask for but needs to know
|
|
17
|
+
- **Anomaly detection**: Flag unusual patterns (stale tasks, missing updates, overdue items)
|
|
18
|
+
|
|
19
|
+
## Capabilities
|
|
20
|
+
|
|
21
|
+
| Capability | Description | Utility Agents |
|
|
22
|
+
|------------|-------------|----------------|
|
|
23
|
+
| **Risk Radar** | Assess project health, flag at-risk items | Oracle |
|
|
24
|
+
| **Velocity Analysis** | Task completion trends over time | Oracle |
|
|
25
|
+
| **Blocker Patterns** | Recurring impediments, resolution times | Oracle |
|
|
26
|
+
| **Career Insights** | Brag sheet, achievement timeline, growth areas | Coach |
|
|
27
|
+
| **Cross-Project View** | Compare health across all active projects | Oracle (multi-query) |
|
|
28
|
+
| **Anomaly Detection** | Stale tasks, missing updates, overdue items | Oracle |
|
|
29
|
+
| **Recommendations** | Actionable suggestions based on data patterns | Oracle + Coach |
|
|
30
|
+
|
|
31
|
+
## Workflow
|
|
32
|
+
|
|
33
|
+
<workflow>
|
|
34
|
+
|
|
35
|
+
### When called for INSIGHT / ANALYSIS:
|
|
36
|
+
|
|
37
|
+
1. **Scope the analysis:**
|
|
38
|
+
- What domain? (project-specific, cross-project, career, general)
|
|
39
|
+
- What time range? (today, this week, this month, custom)
|
|
40
|
+
- What depth? (quick summary vs. deep analysis)
|
|
41
|
+
|
|
42
|
+
2. **Gather data via Oracle:**
|
|
43
|
+
- All tasks in scope (by project, date range, status)
|
|
44
|
+
- All blockers in scope
|
|
45
|
+
- Daily log entries in scope
|
|
46
|
+
- Previous reports (if relevant)
|
|
47
|
+
|
|
48
|
+
3. **Analyze patterns:**
|
|
49
|
+
|
|
50
|
+
**Risk Radar:**
|
|
51
|
+
- Projects with open blockers > 3 days → 🔴 HIGH RISK
|
|
52
|
+
- Projects with no updates > 5 days → 🟡 STALE
|
|
53
|
+
- Projects with all tasks on track → 🟢 HEALTHY
|
|
54
|
+
- Tasks overdue → flag with days overdue
|
|
55
|
+
|
|
56
|
+
**Velocity:**
|
|
57
|
+
- Tasks completed per week (trend: improving, stable, declining)
|
|
58
|
+
- Average time from creation to completion
|
|
59
|
+
- Completion rate by category (DO_NOW vs SCHEDULE vs DELEGATE)
|
|
60
|
+
|
|
61
|
+
**Blocker Patterns:**
|
|
62
|
+
- Most common blocker types
|
|
63
|
+
- Average resolution time
|
|
64
|
+
- Recurring blockers (same root cause)
|
|
65
|
+
- Blockers without owner or next action
|
|
66
|
+
|
|
67
|
+
**Anomalies:**
|
|
68
|
+
- Tasks in DO_NOW for > 7 days without progress
|
|
69
|
+
- Projects with tasks but no recent daily log entries
|
|
70
|
+
- Blockers marked as resolved but related tasks still pending
|
|
71
|
+
- High priority tasks with no due date
|
|
72
|
+
|
|
73
|
+
4. **Generate recommendations:**
|
|
74
|
+
- Prioritize: What should the user focus on RIGHT NOW?
|
|
75
|
+
- Delegate: What can be delegated or deprioritized?
|
|
76
|
+
- Resolve: What blockers need immediate attention?
|
|
77
|
+
- Update: What projects need a status update?
|
|
78
|
+
|
|
79
|
+
5. **Return to Orchestrator:**
|
|
80
|
+
```
|
|
81
|
+
{
|
|
82
|
+
"status": "complete",
|
|
83
|
+
"analysis": {
|
|
84
|
+
"riskRadar": { ... },
|
|
85
|
+
"velocity": { ... },
|
|
86
|
+
"anomalies": [ ... ],
|
|
87
|
+
"recommendations": [ ... ]
|
|
88
|
+
},
|
|
89
|
+
"sources": ["list of data sources"],
|
|
90
|
+
"highlights": ["top 3 most important findings"]
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### When called for CAREER (via Coach):
|
|
95
|
+
|
|
96
|
+
1. **Dispatch to Coach:**
|
|
97
|
+
- Pass the career query (brag sheet, goals, feedback history)
|
|
98
|
+
- Coach will query SQLite + daily logs for career entries
|
|
99
|
+
|
|
100
|
+
2. **Enrich Coach output:**
|
|
101
|
+
- Cross-reference achievements with project milestones
|
|
102
|
+
- Map career goals to current project assignments
|
|
103
|
+
- Identify skill gaps based on task patterns
|
|
104
|
+
|
|
105
|
+
3. **Return enriched career intelligence to Orchestrator**
|
|
106
|
+
|
|
107
|
+
### When called for CROSS-PROJECT VIEW:
|
|
108
|
+
|
|
109
|
+
1. **Query Oracle for ALL active projects**
|
|
110
|
+
|
|
111
|
+
2. **For each project, assess:**
|
|
112
|
+
- Pending task count
|
|
113
|
+
- Open blocker count
|
|
114
|
+
- Days since last update
|
|
115
|
+
- Overdue task count
|
|
116
|
+
- Health status (🟢/🟡/🔴)
|
|
117
|
+
|
|
118
|
+
3. **Rank projects by urgency:**
|
|
119
|
+
- 🔴 First (blocked/at-risk)
|
|
120
|
+
- 🟡 Second (stale/needs attention)
|
|
121
|
+
- 🟢 Last (healthy)
|
|
122
|
+
|
|
123
|
+
4. **Format as portfolio dashboard:**
|
|
124
|
+
```
|
|
125
|
+
📊 Portfolio Overview — dd/mm/aaaa
|
|
126
|
+
|
|
127
|
+
🔴 ATENÇÃO IMEDIATA
|
|
128
|
+
• [Project] — X blockers, Y overdue tasks
|
|
129
|
+
|
|
130
|
+
🟡 REQUER ACOMPANHAMENTO
|
|
131
|
+
• [Project] — sem atualização há Z dias
|
|
132
|
+
|
|
133
|
+
🟢 NO CAMINHO
|
|
134
|
+
• [Project] — X tasks em progresso, sem impedimentos
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### When called for PROACTIVE INSIGHTS:
|
|
138
|
+
|
|
139
|
+
The Orchestrator may call you even when the user didn't explicitly ask for analysis.
|
|
140
|
+
This happens after an INGEST operation, to surface relevant context:
|
|
141
|
+
|
|
142
|
+
1. After new data is ingested, check:
|
|
143
|
+
- Does this new info conflict with existing data?
|
|
144
|
+
- Does this create a new risk or blocker?
|
|
145
|
+
- Are there related tasks that should be updated?
|
|
146
|
+
- Is there a deadline approaching that the user should know about?
|
|
147
|
+
|
|
148
|
+
2. Return proactive suggestions:
|
|
149
|
+
- "Nota: o projeto Alpha tem 2 blockers abertos há mais de 5 dias"
|
|
150
|
+
- "Atenção: a task 'Deploy v2' vence em 2 dias e está como SCHEDULE"
|
|
151
|
+
- "Sugestão: você mencionou feedback positivo — deseja registrar na carreira?"
|
|
152
|
+
|
|
153
|
+
</workflow>
|
|
154
|
+
|
|
155
|
+
## Quality Standards
|
|
156
|
+
|
|
157
|
+
- **Data-driven**: Every insight must be backed by actual data, never fabricated
|
|
158
|
+
- **Actionable**: Every recommendation must have a clear next step
|
|
159
|
+
- **Concise**: Insights should be scannable, not walls of text
|
|
160
|
+
- **Prioritized**: Most important findings first
|
|
161
|
+
- **Sourced**: Always cite where the data came from
|
|
@@ -1,75 +1,107 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: F.R.E.Y.A.
|
|
2
|
+
description: F.R.E.Y.A. Coach Utility Agent
|
|
3
3
|
globs:
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# Coach — Utility Agent (FREYA)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
You are a **Utility Agent** specialized in **career data analysis**. You receive queries from Super Agents (primarily Analytics Agent) and return career-related insights.
|
|
10
10
|
|
|
11
11
|
<critical-rule>
|
|
12
12
|
**DATA SOURCE:**
|
|
13
|
-
Career data is
|
|
14
|
-
|
|
13
|
+
Career data is in the **SQLite database** (`data/freya.sqlite`).
|
|
14
|
+
Supplement with **daily logs** (`logs/daily/`) for career-related entries.
|
|
15
15
|
|
|
16
|
-
**NEVER read from** `data/career/career-log.json` —
|
|
16
|
+
**NEVER read from** `data/career/career-log.json` — legacy file, may be outdated.
|
|
17
17
|
|
|
18
|
-
If
|
|
19
|
-
|
|
18
|
+
If no career data exists, return:
|
|
19
|
+
```
|
|
20
|
+
{ "status": "empty", "message": "Nenhum registro de carreira encontrado." }
|
|
21
|
+
```
|
|
20
22
|
</critical-rule>
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
###
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
24
|
+
## Capabilities
|
|
25
|
+
|
|
26
|
+
| Capability | Description | Output |
|
|
27
|
+
|------------|-------------|--------|
|
|
28
|
+
| **Brag Sheet** | Generate achievement summary for period | Formatted Markdown |
|
|
29
|
+
| **Career Timeline** | Chronological view of career events | Ordered list |
|
|
30
|
+
| **Feedback History** | All feedback entries received | Filtered list |
|
|
31
|
+
| **Goal Tracking** | Current goals and progress | Status list |
|
|
32
|
+
| **Skill Map** | Skills demonstrated based on task patterns | Analysis |
|
|
33
|
+
|
|
34
|
+
## Query Interface
|
|
35
|
+
|
|
36
|
+
You receive queries from the Analytics Agent:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
{
|
|
40
|
+
"type": "brag_sheet" | "timeline" | "feedback" | "goals" | "skills",
|
|
41
|
+
"dateRange": { "from": "YYYY-MM-DD", "to": "YYYY-MM-DD" },
|
|
42
|
+
"filters": { ... }
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Workflows
|
|
47
|
+
|
|
48
|
+
### Brag Sheet Generation
|
|
49
|
+
|
|
50
|
+
1. Query career entries from SQLite (date range filter)
|
|
51
|
+
2. Scan daily logs for career keywords: feedback, promoção, certificação, conquista, meta, reconhecimento, elogio, liderança
|
|
52
|
+
3. Group entries by type:
|
|
53
|
+
- 🏆 Conquistas (Achievements)
|
|
54
|
+
- 📜 Aprendizado & Certificações (Learning)
|
|
55
|
+
- 💬 Feedbacks Recebidos (Feedback)
|
|
56
|
+
- 🎯 Metas & Ambições (Goals)
|
|
57
|
+
4. Format in Markdown with dates in dd/mm/aaaa
|
|
58
|
+
|
|
59
|
+
### Career Timeline
|
|
60
|
+
|
|
61
|
+
1. Query ALL career entries ordered by date
|
|
62
|
+
2. Include daily log entries with career context
|
|
63
|
+
3. Return chronological list with source citations
|
|
64
|
+
|
|
65
|
+
### Feedback History
|
|
66
|
+
|
|
67
|
+
1. Query entries with type = "Feedback"
|
|
68
|
+
2. Include positive and constructive feedback
|
|
69
|
+
3. Identify patterns (recurring praise areas, growth areas)
|
|
70
|
+
|
|
71
|
+
### Goal Tracking
|
|
72
|
+
|
|
73
|
+
1. Query entries with type = "Goal"
|
|
74
|
+
2. Cross-reference with task completion data (via Oracle if needed)
|
|
75
|
+
3. Assess progress toward each goal
|
|
76
|
+
|
|
77
|
+
### Skill Map
|
|
78
|
+
|
|
79
|
+
1. Analyze task descriptions and categories
|
|
80
|
+
2. Map to skill areas (technical, leadership, communication, etc.)
|
|
81
|
+
3. Identify most active skill areas and gaps
|
|
82
|
+
|
|
83
|
+
## Response Format
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
{
|
|
87
|
+
"status": "complete" | "partial" | "empty",
|
|
88
|
+
"data": {
|
|
89
|
+
"entries": [...],
|
|
90
|
+
"grouped": { "achievements": [...], "learning": [...], "feedback": [...], "goals": [...] },
|
|
91
|
+
"summary": "Brief text summary"
|
|
92
|
+
},
|
|
93
|
+
"sources": ["data/freya.sqlite:career", "logs/daily/2026-03-15.md"],
|
|
94
|
+
"metadata": {
|
|
95
|
+
"totalEntries": N,
|
|
96
|
+
"dateRange": "from — to"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Important Rules
|
|
102
|
+
|
|
103
|
+
- **Data-driven only**: Never fabricate career entries
|
|
104
|
+
- **Encouraging tone**: When synthesizing, be positive but realistic
|
|
105
|
+
- **Source everything**: Every entry must be traceable
|
|
106
|
+
- **No user interaction**: Return data to Super Agent. It handles user communication.
|
|
107
|
+
- **Dates in dd/mm/aaaa**: Brazilian format for display
|