@cccarv82/freya 2.13.1 → 2.13.3
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.css +3 -0
- package/cli/web-ui.js +164 -19
- package/cli/web.js +18 -3
- package/package.json +1 -1
package/cli/web-ui.css
CHANGED
|
@@ -134,6 +134,7 @@ body {
|
|
|
134
134
|
.shell {
|
|
135
135
|
display: grid;
|
|
136
136
|
grid-template-columns: 72px minmax(520px, 1fr);
|
|
137
|
+
grid-template-rows: 1fr;
|
|
137
138
|
height: 100vh;
|
|
138
139
|
min-height: 0;
|
|
139
140
|
}
|
|
@@ -360,6 +361,7 @@ body {
|
|
|
360
361
|
display: flex;
|
|
361
362
|
flex-direction: column;
|
|
362
363
|
min-height: 0;
|
|
364
|
+
overflow: hidden;
|
|
363
365
|
padding: 8px 0 18px;
|
|
364
366
|
}
|
|
365
367
|
|
|
@@ -588,6 +590,7 @@ body {
|
|
|
588
590
|
display: flex;
|
|
589
591
|
flex-direction: column;
|
|
590
592
|
gap: 18px;
|
|
593
|
+
flex: 1;
|
|
591
594
|
}
|
|
592
595
|
|
|
593
596
|
.promptShell {
|
package/cli/web-ui.js
CHANGED
|
@@ -162,6 +162,116 @@
|
|
|
162
162
|
return html;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
function formatPlanForDisplay(rawPlan) {
|
|
166
|
+
var text = String(rawPlan || '');
|
|
167
|
+
if (!text) return null;
|
|
168
|
+
|
|
169
|
+
// --- Strategy 1: try full JSON parse (works when copilot output is complete) ---
|
|
170
|
+
try {
|
|
171
|
+
var start = text.indexOf('{');
|
|
172
|
+
if (start !== -1) {
|
|
173
|
+
var depth = 0, inStr = false, esc = false, jsonStr = null;
|
|
174
|
+
for (var i = start; i < text.length; i++) {
|
|
175
|
+
var ch = text[i];
|
|
176
|
+
if (esc) { esc = false; continue; }
|
|
177
|
+
if (ch === '\\') { esc = true; continue; }
|
|
178
|
+
if (ch === '"') { inStr = !inStr; continue; }
|
|
179
|
+
if (inStr) continue;
|
|
180
|
+
if (ch === '{') depth++;
|
|
181
|
+
if (ch === '}') { depth--; if (depth === 0) { jsonStr = text.slice(start, i + 1); break; } }
|
|
182
|
+
}
|
|
183
|
+
if (jsonStr) {
|
|
184
|
+
var plan = JSON.parse(jsonStr);
|
|
185
|
+
var actions = Array.isArray(plan.actions) ? plan.actions : [];
|
|
186
|
+
if (actions.length > 0) {
|
|
187
|
+
return formatActions(actions);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch (e) { /* fall through to regex strategy */ }
|
|
192
|
+
|
|
193
|
+
// --- Strategy 2: regex fallback for truncated/malformed JSON ---
|
|
194
|
+
var lines = [];
|
|
195
|
+
var num = 0;
|
|
196
|
+
|
|
197
|
+
// Match append_daily_log / appenddailylog actions
|
|
198
|
+
var logRe = /"type"\s*:\s*"append_?daily_?log"\s*,\s*"text"\s*:\s*"([^"]{1,300})/gi;
|
|
199
|
+
var m;
|
|
200
|
+
while ((m = logRe.exec(text)) !== null) {
|
|
201
|
+
num++;
|
|
202
|
+
var t = m[1].slice(0, 140);
|
|
203
|
+
lines.push(num + '. \u{1F4DD} **Registrar no log:** ' + t + (m[1].length > 140 ? '...' : ''));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Match create_task actions
|
|
207
|
+
var taskRe = /"type"\s*:\s*"create_?task"\s*,\s*"description"\s*:\s*"([^"]{1,200})/gi;
|
|
208
|
+
while ((m = taskRe.exec(text)) !== null) {
|
|
209
|
+
num++;
|
|
210
|
+
var desc = m[1].slice(0, 120);
|
|
211
|
+
var priMatch = text.slice(m.index, m.index + 400).match(/"priority"\s*:\s*"(\w+)"/i);
|
|
212
|
+
var pri = priMatch ? ' (prioridade: **' + priMatch[1].toUpperCase() + '**)' : '';
|
|
213
|
+
lines.push(num + '. \u2705 **Criar tarefa:** ' + desc + pri);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Match create_blocker actions
|
|
217
|
+
var blockerRe = /"type"\s*:\s*"create_?blocker"\s*,\s*"title"\s*:\s*"([^"]{1,200})/gi;
|
|
218
|
+
while ((m = blockerRe.exec(text)) !== null) {
|
|
219
|
+
num++;
|
|
220
|
+
var title = m[1].slice(0, 120);
|
|
221
|
+
var sevMatch = text.slice(m.index, m.index + 400).match(/"severity"\s*:\s*"(\w+)"/i);
|
|
222
|
+
var sev = sevMatch ? ' (severidade: **' + sevMatch[1].toUpperCase() + '**)' : '';
|
|
223
|
+
lines.push(num + '. \u{1F6A7} **Registrar blocker:** ' + title + sev);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Match suggest_report actions
|
|
227
|
+
var repRe = /"type"\s*:\s*"suggest_?report"\s*,\s*"name"\s*:\s*"([^"]+)"/gi;
|
|
228
|
+
while ((m = repRe.exec(text)) !== null) {
|
|
229
|
+
num++;
|
|
230
|
+
lines.push(num + '. \u{1F4CA} **Sugerir relatorio:** ' + m[1]);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return lines.length > 0 ? lines.join('\n') : null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function formatActions(actions) {
|
|
237
|
+
var icons = {
|
|
238
|
+
appenddailylog: '\u{1F4DD}', createtask: '\u2705',
|
|
239
|
+
createblocker: '\u{1F6A7}', suggestreport: '\u{1F4CA}',
|
|
240
|
+
oraclequery: '\u{1F50D}'
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
var lines = actions.map(function(a, i) {
|
|
244
|
+
var type = String(a.type || '').trim().toLowerCase().replace(/_/g, '');
|
|
245
|
+
var icon = icons[type] || '\u2022';
|
|
246
|
+
var num = i + 1;
|
|
247
|
+
|
|
248
|
+
if (type === 'appenddailylog') {
|
|
249
|
+
var t = String(a.text || '').slice(0, 140);
|
|
250
|
+
return num + '. ' + icon + ' **Registrar no log:** ' + t + (String(a.text || '').length > 140 ? '...' : '');
|
|
251
|
+
}
|
|
252
|
+
if (type === 'createtask') {
|
|
253
|
+
var desc = String(a.description || '').slice(0, 120);
|
|
254
|
+
var pri = a.priority ? ' (prioridade: **' + String(a.priority).toUpperCase() + '**)' : '';
|
|
255
|
+
var cat = a.category ? ' [' + a.category + ']' : '';
|
|
256
|
+
return num + '. ' + icon + ' **Criar tarefa:** ' + desc + pri + cat;
|
|
257
|
+
}
|
|
258
|
+
if (type === 'createblocker') {
|
|
259
|
+
var title = String(a.title || a.description || '').slice(0, 120);
|
|
260
|
+
var sev = a.severity ? ' (severidade: **' + String(a.severity).toUpperCase() + '**)' : '';
|
|
261
|
+
return num + '. ' + icon + ' **Registrar blocker:** ' + title + sev;
|
|
262
|
+
}
|
|
263
|
+
if (type === 'suggestreport') {
|
|
264
|
+
return num + '. ' + icon + ' **Sugerir relatorio:** ' + String(a.name || a.reportType || '');
|
|
265
|
+
}
|
|
266
|
+
if (type === 'oraclequery') {
|
|
267
|
+
return num + '. ' + icon + ' **Consultar oracle:** ' + String(a.query || '').slice(0, 120);
|
|
268
|
+
}
|
|
269
|
+
return num + '. \u2022 **' + String(a.type || 'acao') + '**';
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return lines.join('\n');
|
|
273
|
+
}
|
|
274
|
+
|
|
165
275
|
function ensureChatSession() {
|
|
166
276
|
if (state.chatSessionId) return state.chatSessionId;
|
|
167
277
|
try {
|
|
@@ -1507,29 +1617,63 @@
|
|
|
1507
1617
|
+ (t.category ? ' · <span style="font-family:var(--mono);">' + escapeHtml(t.category) + '</span>' : '')
|
|
1508
1618
|
+ '</div>'
|
|
1509
1619
|
+ '</div></div>'
|
|
1510
|
-
+ '<div style="display:flex; gap:6px; flex-shrink:0;">'
|
|
1620
|
+
+ '<div class="task-actions" style="display:flex; gap:6px; flex-shrink:0; align-items:center;">'
|
|
1511
1621
|
+ '<button class="btn small complete-btn" type="button" style="padding:3px 10px; font-size:11px;" title="Marcar como concluída">✓ Concluir</button>'
|
|
1512
1622
|
+ '<button class="btn small edit-btn" type="button" style="padding:3px 8px; font-size:11px;">✎</button>'
|
|
1513
1623
|
+ '</div>';
|
|
1514
1624
|
row.querySelector('.edit-btn').onclick = () => editTask(t);
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1625
|
+
|
|
1626
|
+
var attachCompleteHandler = function() {
|
|
1627
|
+
var cBtn = row.querySelector('.complete-btn');
|
|
1628
|
+
if (!cBtn) return;
|
|
1629
|
+
cBtn.onclick = function() {
|
|
1630
|
+
var actionsDiv = row.querySelector('.task-actions');
|
|
1631
|
+
actionsDiv.innerHTML =
|
|
1632
|
+
'<input type="text" class="comment-input" placeholder="Comentario (opcional)" '
|
|
1633
|
+
+ 'style="font-size:11px; padding:3px 8px; background:var(--bg); border:1px solid var(--border); '
|
|
1634
|
+
+ 'color:var(--text); width:180px; outline:none; font-family:var(--mono);" />'
|
|
1635
|
+
+ '<button class="btn small confirm-btn" type="button" style="padding:3px 10px; font-size:11px; '
|
|
1636
|
+
+ 'background:var(--accent); color:#000; font-weight:700;">Confirmar</button>'
|
|
1637
|
+
+ '<button class="btn small cancel-btn" type="button" style="padding:3px 8px; font-size:11px; '
|
|
1638
|
+
+ 'color:var(--muted);">\u2715</button>';
|
|
1639
|
+
|
|
1640
|
+
var input = actionsDiv.querySelector('.comment-input');
|
|
1641
|
+
input.focus();
|
|
1642
|
+
|
|
1643
|
+
var doComplete = async function() {
|
|
1644
|
+
var comment = input.value.trim();
|
|
1645
|
+
actionsDiv.querySelector('.confirm-btn').disabled = true;
|
|
1646
|
+
actionsDiv.querySelector('.confirm-btn').textContent = '\u2026';
|
|
1647
|
+
try {
|
|
1648
|
+
setPill('run', 'concluindo\u2026');
|
|
1649
|
+
var body = { dir: dirOrDefault(), id: t.id };
|
|
1650
|
+
if (comment) body.comment = comment;
|
|
1651
|
+
await api('/api/tasks/complete', body);
|
|
1652
|
+
row.style.opacity = '0.4';
|
|
1653
|
+
row.style.pointerEvents = 'none';
|
|
1654
|
+
await refreshToday();
|
|
1655
|
+
setPill('ok', 'conclu\u00edda');
|
|
1656
|
+
setTimeout(function() { setPill('ok', 'pronto'); }, 800);
|
|
1657
|
+
} catch (e) {
|
|
1658
|
+
actionsDiv.querySelector('.confirm-btn').disabled = false;
|
|
1659
|
+
actionsDiv.querySelector('.confirm-btn').textContent = 'Confirmar';
|
|
1660
|
+
setPill('err', 'falhou');
|
|
1661
|
+
}
|
|
1662
|
+
};
|
|
1663
|
+
|
|
1664
|
+
actionsDiv.querySelector('.confirm-btn').onclick = doComplete;
|
|
1665
|
+
input.onkeydown = function(e) { if (e.key === 'Enter') doComplete(); };
|
|
1666
|
+
actionsDiv.querySelector('.cancel-btn').onclick = function() {
|
|
1667
|
+
actionsDiv.innerHTML =
|
|
1668
|
+
'<button class="btn small complete-btn" type="button" style="padding:3px 10px; font-size:11px;" '
|
|
1669
|
+
+ 'title="Marcar como conclu\u00edda">\u2713 Concluir</button>'
|
|
1670
|
+
+ '<button class="btn small edit-btn" type="button" style="padding:3px 8px; font-size:11px;">\u270E</button>';
|
|
1671
|
+
actionsDiv.querySelector('.edit-btn').onclick = function() { editTask(t); };
|
|
1672
|
+
attachCompleteHandler();
|
|
1673
|
+
};
|
|
1674
|
+
};
|
|
1532
1675
|
};
|
|
1676
|
+
attachCompleteHandler();
|
|
1533
1677
|
return row;
|
|
1534
1678
|
};
|
|
1535
1679
|
|
|
@@ -2328,7 +2472,8 @@
|
|
|
2328
2472
|
|
|
2329
2473
|
// Show plan output in Preview panel
|
|
2330
2474
|
const header = r.ok === false ? '## Agent Plan (planner unavailable)\n\n' : '## Agent Plan (draft)\n\n';
|
|
2331
|
-
const
|
|
2475
|
+
const formatted = r.ok !== false ? formatPlanForDisplay(r.plan) : null;
|
|
2476
|
+
const planOut = header + (formatted || r.plan || '');
|
|
2332
2477
|
setOut(planOut);
|
|
2333
2478
|
chatAppend('assistant', planOut, { markdown: true });
|
|
2334
2479
|
ta.value = '';
|
package/cli/web.js
CHANGED
|
@@ -3620,7 +3620,8 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3620
3620
|
completedAt: t.completed_at,
|
|
3621
3621
|
projectSlug: t.project_slug,
|
|
3622
3622
|
priority: meta.priority,
|
|
3623
|
-
streamSlug: meta.streamSlug
|
|
3623
|
+
streamSlug: meta.streamSlug,
|
|
3624
|
+
comments: Array.isArray(meta.comments) ? meta.comments : []
|
|
3624
3625
|
};
|
|
3625
3626
|
});
|
|
3626
3627
|
|
|
@@ -3631,10 +3632,24 @@ async function cmdWeb({ port, dir, open, dev }) {
|
|
|
3631
3632
|
const id = String(payload.id || '').trim();
|
|
3632
3633
|
if (!id) return safeJson(res, 400, { error: 'Missing id' });
|
|
3633
3634
|
|
|
3635
|
+
const comment = typeof payload.comment === 'string' ? payload.comment.trim() : '';
|
|
3634
3636
|
const now = new Date().toISOString();
|
|
3635
|
-
const info = dl.db.prepare(`UPDATE tasks SET status = 'COMPLETED', completed_at = ? WHERE id = ?`).run(now, id);
|
|
3636
3637
|
|
|
3637
|
-
if (
|
|
3638
|
+
if (comment) {
|
|
3639
|
+
const row = dl.db.prepare('SELECT metadata FROM tasks WHERE id = ?').get(id);
|
|
3640
|
+
if (!row) return safeJson(res, 404, { error: 'Task not found' });
|
|
3641
|
+
let meta = {};
|
|
3642
|
+
try { meta = row.metadata ? JSON.parse(row.metadata) : {}; } catch (_) { meta = {}; }
|
|
3643
|
+
if (!Array.isArray(meta.comments)) meta.comments = [];
|
|
3644
|
+
meta.comments.push({ text: comment, createdAt: now });
|
|
3645
|
+
const info = dl.db.prepare(`UPDATE tasks SET status = 'COMPLETED', completed_at = ?, metadata = ? WHERE id = ?`)
|
|
3646
|
+
.run(now, JSON.stringify(meta), id);
|
|
3647
|
+
if (info.changes === 0) return safeJson(res, 404, { error: 'Task not found' });
|
|
3648
|
+
} else {
|
|
3649
|
+
const info = dl.db.prepare(`UPDATE tasks SET status = 'COMPLETED', completed_at = ? WHERE id = ?`).run(now, id);
|
|
3650
|
+
if (info.changes === 0) return safeJson(res, 404, { error: 'Task not found' });
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3638
3653
|
return safeJson(res, 200, { ok: true, task: { id, status: 'COMPLETED', completedAt: now } });
|
|
3639
3654
|
}
|
|
3640
3655
|
|
package/package.json
CHANGED