@cccarv82/freya 3.3.0 → 3.4.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/cli/web-ui.css CHANGED
@@ -1803,43 +1803,56 @@ body:not([data-page="kanban"]) .kanban-col-body {
1803
1803
  min-width: 180px;
1804
1804
  }
1805
1805
 
1806
- /* Kanban blockers strip */
1807
- .kanban-blockers-list {
1806
+ /* Blocker Kanban Board */
1807
+ .blocker-kanban-board {
1808
+ display: grid;
1809
+ grid-template-columns: repeat(3, 1fr);
1810
+ gap: 12px;
1811
+ min-height: 120px;
1812
+ }
1813
+
1814
+ @media (max-width: 900px) {
1815
+ .blocker-kanban-board { grid-template-columns: 1fr; }
1816
+ }
1817
+
1818
+ .blocker-kanban-col {
1808
1819
  display: flex;
1809
- flex-wrap: wrap;
1810
- gap: 8px;
1820
+ flex-direction: column;
1821
+ background: var(--bg);
1822
+ border: 1px solid var(--line2);
1823
+ min-height: 80px;
1811
1824
  }
1812
1825
 
1813
- .kanban-blocker-card {
1826
+ .blocker-kanban-col-body {
1827
+ flex: 1;
1828
+ padding: 8px;
1814
1829
  display: flex;
1815
- align-items: center;
1830
+ flex-direction: column;
1816
1831
  gap: 8px;
1817
- padding: 8px 12px;
1818
- background: rgba(239, 68, 68, 0.04);
1819
- border: 1px solid rgba(239, 68, 68, 0.15);
1820
- border-left: 3px solid #ef4444;
1821
- flex: 1 1 300px;
1822
- max-width: 500px;
1832
+ overflow-y: auto;
1833
+ max-height: 300px;
1834
+ min-height: 50px;
1835
+ transition: background 0.15s;
1823
1836
  }
1824
1837
 
1825
- .kanban-blocker-sev {
1826
- font-size: 9px;
1827
- font-weight: 800;
1828
- letter-spacing: 0.5px;
1829
- padding: 2px 6px;
1830
- border: 1px solid;
1831
- flex-shrink: 0;
1838
+ .blocker-kanban-col-body.drag-over {
1839
+ background: rgba(239, 68, 68, 0.06);
1832
1840
  }
1833
1841
 
1834
- .kanban-blocker-title {
1835
- font-size: 12px;
1836
- font-weight: 600;
1837
- color: var(--text);
1838
- flex: 1;
1839
- min-width: 0;
1840
- overflow: hidden;
1841
- text-overflow: ellipsis;
1842
- white-space: nowrap;
1842
+ /* Blocker column header colors */
1843
+ .kanban-col-head.blocker-open { border-bottom-color: #ef4444; }
1844
+ .kanban-col-head.blocker-open .kanban-col-title { color: #ef4444; }
1845
+ .kanban-col-head.blocker-open .kanban-col-count { background: #ef444422; color: #ef4444; }
1846
+ .kanban-col-head.blocker-mitigating { border-bottom-color: #f59e0b; }
1847
+ .kanban-col-head.blocker-mitigating .kanban-col-title { color: #f59e0b; }
1848
+ .kanban-col-head.blocker-mitigating .kanban-col-count { background: #f59e0b22; color: #f59e0b; }
1849
+ .kanban-col-head.blocker-resolved { border-bottom-color: #22c55e; }
1850
+ .kanban-col-head.blocker-resolved .kanban-col-title { color: #22c55e; }
1851
+ .kanban-col-head.blocker-resolved .kanban-col-count { background: #22c55e22; color: #22c55e; }
1852
+
1853
+ /* Blocker card in kanban (reuses .kanban-card) */
1854
+ .kanban-card.blocker-card {
1855
+ border-left: 3px solid #ef4444;
1843
1856
  }
1844
1857
 
1845
1858
  /* ── Quick-Add Modal ── */
package/cli/web-ui.js CHANGED
@@ -3232,7 +3232,7 @@
3232
3232
  // Drag events
3233
3233
  if (cat !== 'COMPLETED') {
3234
3234
  card.addEventListener('dragstart', function(e) {
3235
- e.dataTransfer.setData('text/plain', t.id);
3235
+ e.dataTransfer.setData('text/task-id', t.id);
3236
3236
  e.dataTransfer.effectAllowed = 'move';
3237
3237
  card.classList.add('dragging');
3238
3238
  });
@@ -3252,34 +3252,10 @@
3252
3252
  };
3253
3253
  }
3254
3254
 
3255
- // Edit button - inline edit via prompt
3255
+ // Edit button - open full edit modal
3256
3256
  var editBtn = card.querySelector('.edit-btn');
3257
3257
  if (editBtn) {
3258
- editBtn.onclick = async function() {
3259
- var newCat = prompt('Categoria (DO_NOW|SCHEDULE|DELEGATE):', cat);
3260
- if (!newCat) return;
3261
- var newSlug = prompt('Projeto (slug):', t.projectSlug || '');
3262
- if (newSlug === null) return;
3263
- var currentDueBR = t.dueDate ? fmtDateBR(t.dueDate) : '';
3264
- var newDueBR = prompt('Due date (dd/mm/aaaa):', currentDueBR);
3265
- if (newDueBR === null) return;
3266
- // Convert dd/mm/aaaa back to YYYY-MM-DD for API
3267
- var newDue = '';
3268
- if (newDueBR && newDueBR.indexOf('/') > -1) {
3269
- var dp = newDueBR.split('/');
3270
- if (dp.length === 3) newDue = dp[2] + '-' + dp[1] + '-' + dp[0];
3271
- } else {
3272
- newDue = newDueBR; // fallback: accept YYYY-MM-DD too
3273
- }
3274
- try {
3275
- await api('/api/tasks/update', {
3276
- dir: dirOrDefault(), id: t.id,
3277
- patch: { category: newCat, projectSlug: newSlug, dueDate: newDue || null }
3278
- });
3279
- showToast('ok', 'Atualizada');
3280
- await loadKanban();
3281
- } catch { showToast('err', 'Falhou'); }
3282
- };
3258
+ editBtn.onclick = function() { openTaskEdit(t); };
3283
3259
  }
3284
3260
  }
3285
3261
 
@@ -3299,7 +3275,7 @@
3299
3275
  el.addEventListener('drop', async function(e) {
3300
3276
  e.preventDefault();
3301
3277
  el.classList.remove('drag-over');
3302
- var taskId = e.dataTransfer.getData('text/plain');
3278
+ var taskId = e.dataTransfer.getData('text/task-id');
3303
3279
  if (!taskId) return;
3304
3280
  try {
3305
3281
  await api('/api/tasks/update', {
@@ -3316,33 +3292,229 @@
3316
3292
 
3317
3293
  function renderKanbanBlockers() {
3318
3294
  var wrap = $('kanbanBlockers');
3319
- var list = $('kanbanBlockersList');
3320
- if (!wrap || !list) return;
3295
+ if (!wrap) return;
3321
3296
 
3322
3297
  var sel = $('kanbanFilterProject');
3323
3298
  var filter = sel ? sel.value : '';
3324
- var blockers = _kanbanData.blockers;
3299
+ var blockers = _kanbanData.blockers || [];
3325
3300
  if (filter) blockers = blockers.filter(function(b) { return b.projectSlug === filter; });
3326
3301
 
3327
3302
  if (blockers.length === 0) { wrap.style.display = 'none'; return; }
3328
3303
  wrap.style.display = 'block';
3329
- list.innerHTML = '';
3330
3304
 
3305
+ // Sort into columns
3306
+ var cols = { OPEN: [], MITIGATING: [], RESOLVED: [] };
3331
3307
  blockers.forEach(function(b) {
3332
- var card = document.createElement('div');
3333
- card.className = 'kanban-blocker-card';
3334
- var color = sevColor(b.severity);
3335
- card.innerHTML = '<span class="kanban-blocker-sev" style="background:' + color + '22; color:' + color + '; border-color:' + color + '44;">' + escapeHtml(b.severity || 'BLOCKER') + '</span>'
3336
- + '<span class="kanban-blocker-title">' + escapeHtml(b.title || '') + '</span>'
3337
- + (b.projectSlug ? '<span class="kanban-tag">' + escapeHtml(b.projectSlug) + '</span>' : '')
3338
- + (b.owner ? '<span class="kanban-owner">' + escapeHtml(b.owner) + '</span>' : '');
3339
- card.style.cursor = 'pointer';
3340
- card.addEventListener('click', function() { showDetailPanel(b, 'blocker'); });
3341
- list.appendChild(card);
3308
+ if (cols[b.status]) cols[b.status].push(b);
3309
+ });
3310
+
3311
+ var idMap = { OPEN: 'colBlockerOpen', MITIGATING: 'colBlockerMitigating', RESOLVED: 'colBlockerResolved' };
3312
+ var countMap = { OPEN: 'countBlockerOpen', MITIGATING: 'countBlockerMitigating', RESOLVED: 'countBlockerResolved' };
3313
+
3314
+ ['OPEN', 'MITIGATING', 'RESOLVED'].forEach(function(status) {
3315
+ var el = $(idMap[status]);
3316
+ var countEl = $(countMap[status]);
3317
+ if (!el) return;
3318
+ el.innerHTML = '';
3319
+ if (countEl) countEl.textContent = cols[status].length;
3320
+
3321
+ cols[status].forEach(function(b) {
3322
+ var card = document.createElement('div');
3323
+ card.className = 'kanban-card blocker-card';
3324
+ card.setAttribute('data-blocker-id', b.id);
3325
+ if (status !== 'RESOLVED') card.draggable = true;
3326
+
3327
+ var color = sevColor(b.severity);
3328
+ var html = '<div class="kanban-card-header">'
3329
+ + '<span class="kanban-priority-dot" style="background:' + color + ';" title="' + escapeHtml(b.severity) + '"></span>'
3330
+ + '<span class="kanban-card-desc">' + escapeHtml(b.title || '') + '</span>'
3331
+ + '</div>';
3332
+ html += '<div class="kanban-card-meta">';
3333
+ if (b.projectSlug) html += '<span class="kanban-tag">' + escapeHtml(b.projectSlug) + '</span>';
3334
+ if (b.owner) html += '<span class="kanban-tag" style="background:var(--chip);">' + escapeHtml(b.owner) + '</span>';
3335
+ html += '</div>';
3336
+ if (status !== 'RESOLVED') {
3337
+ html += '<div class="kanban-card-actions">'
3338
+ + '<button class="edit-btn" title="Editar">'
3339
+ + '<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>'
3340
+ + '</button></div>';
3341
+ }
3342
+ card.innerHTML = html;
3343
+
3344
+ // Click → detail panel (only if not dragging)
3345
+ var _bDragged = false;
3346
+ card.addEventListener('mousedown', function() { _bDragged = false; });
3347
+ card.addEventListener('mousemove', function() { _bDragged = true; });
3348
+ card.addEventListener('click', function(e) {
3349
+ if (_bDragged) return;
3350
+ if (e.target.closest('.kanban-card-actions')) return;
3351
+ showDetailPanel(b, 'blocker');
3352
+ });
3353
+
3354
+ // Drag events
3355
+ if (status !== 'RESOLVED') {
3356
+ card.addEventListener('dragstart', function(e) {
3357
+ e.dataTransfer.setData('text/blocker-id', b.id);
3358
+ e.dataTransfer.effectAllowed = 'move';
3359
+ card.classList.add('dragging');
3360
+ });
3361
+ card.addEventListener('dragend', function() {
3362
+ card.classList.remove('dragging');
3363
+ });
3364
+ }
3365
+
3366
+ // Edit button
3367
+ var editBtn = card.querySelector('.edit-btn');
3368
+ if (editBtn) {
3369
+ editBtn.onclick = function(e) { e.stopPropagation(); openBlockerEdit(b); };
3370
+ }
3371
+
3372
+ el.appendChild(card);
3373
+ });
3374
+
3375
+ // Drop zone
3376
+ el.addEventListener('dragover', function(e) {
3377
+ e.preventDefault();
3378
+ e.dataTransfer.dropEffect = 'move';
3379
+ el.classList.add('drag-over');
3380
+ });
3381
+ el.addEventListener('dragleave', function() {
3382
+ el.classList.remove('drag-over');
3383
+ });
3384
+ el.addEventListener('drop', async function(e) {
3385
+ e.preventDefault();
3386
+ el.classList.remove('drag-over');
3387
+ var blockerId = e.dataTransfer.getData('text/blocker-id');
3388
+ if (!blockerId) return;
3389
+ try {
3390
+ await api('/api/blockers/update', {
3391
+ dir: dirOrDefault(), id: blockerId,
3392
+ patch: { status: status }
3393
+ });
3394
+ showToast('ok', 'Blocker → ' + status);
3395
+ await loadKanban();
3396
+ } catch { showToast('err', 'Falhou'); }
3397
+ });
3342
3398
  });
3343
3399
  }
3344
3400
 
3401
+ // === Task Edit Modal ===
3402
+ function openTaskEdit(t) {
3403
+ var overlay = $('taskEditOverlay');
3404
+ if (!overlay) return;
3405
+ $('teTaskId').value = t.id;
3406
+ $('teDesc').value = t.description || '';
3407
+ $('teCat').value = t.category || 'DO_NOW';
3408
+ $('tePriority').value = t.priority || '';
3409
+ $('teSlug').value = t.projectSlug || '';
3410
+ $('teDue').value = t.dueDate ? fmtDateBR(t.dueDate) : '';
3411
+ var stream = $('teStream');
3412
+ if (stream) stream.value = t.streamSlug || '';
3413
+ overlay.style.display = 'flex';
3414
+ // Wire date picker sync
3415
+ var picker = $('teDuePicker');
3416
+ var txt = $('teDue');
3417
+ if (picker && txt) {
3418
+ picker.onchange = function() {
3419
+ if (!picker.value) return;
3420
+ var p = picker.value.split('-');
3421
+ if (p.length === 3) txt.value = p[2] + '/' + p[1] + '/' + p[0];
3422
+ };
3423
+ }
3424
+ $('teDesc').focus();
3425
+ }
3426
+
3427
+ function closeTaskEdit() {
3428
+ var overlay = $('taskEditOverlay');
3429
+ if (overlay) overlay.style.display = 'none';
3430
+ }
3431
+
3432
+ async function submitTaskEdit() {
3433
+ var id = $('teTaskId').value;
3434
+ if (!id) return;
3435
+ var desc = ($('teDesc').value || '').trim();
3436
+ var cat = $('teCat').value;
3437
+ var priority = $('tePriority').value;
3438
+ var slug = ($('teSlug').value || '').trim();
3439
+ var dueBR = ($('teDue').value || '').trim();
3440
+ var stream = ($('teStream') ? $('teStream').value : '').trim();
3441
+
3442
+ // Convert dd/mm/aaaa → YYYY-MM-DD
3443
+ var due = null;
3444
+ if (dueBR && dueBR.indexOf('/') > -1) {
3445
+ var dp = dueBR.split('/');
3446
+ if (dp.length === 3) due = dp[2] + '-' + dp[1] + '-' + dp[0];
3447
+ } else if (dueBR) {
3448
+ due = dueBR;
3449
+ }
3450
+
3451
+ try {
3452
+ await api('/api/tasks/update', {
3453
+ dir: dirOrDefault(), id: id,
3454
+ patch: { description: desc, category: cat, priority: priority, projectSlug: slug, dueDate: due, streamSlug: stream }
3455
+ });
3456
+ closeTaskEdit();
3457
+ showToast('ok', 'Task atualizada');
3458
+ await loadKanban();
3459
+ } catch { showToast('err', 'Falhou'); }
3460
+ }
3461
+
3462
+ // === Blocker Edit Modal ===
3463
+ function openBlockerEdit(b) {
3464
+ var overlay = $('blockerEditOverlay');
3465
+ if (!overlay) return;
3466
+ $('beBlockerId').value = b.id;
3467
+ $('beTitle').value = b.title || '';
3468
+ $('beSeverity').value = b.severity || 'MEDIUM';
3469
+ $('beStatus').value = b.status || 'OPEN';
3470
+ $('beSlug').value = b.projectSlug || '';
3471
+ $('beOwner').value = b.owner || '';
3472
+ $('beNextAction').value = b.nextAction || '';
3473
+ overlay.style.display = 'flex';
3474
+ $('beTitle').focus();
3475
+ }
3476
+
3477
+ function closeBlockerEdit() {
3478
+ var overlay = $('blockerEditOverlay');
3479
+ if (overlay) overlay.style.display = 'none';
3480
+ }
3481
+
3482
+ async function submitBlockerEdit() {
3483
+ var id = $('beBlockerId').value;
3484
+ if (!id) return;
3485
+ var title = ($('beTitle').value || '').trim();
3486
+ var severity = $('beSeverity').value;
3487
+ var status = $('beStatus').value;
3488
+ var slug = ($('beSlug').value || '').trim();
3489
+ var owner = ($('beOwner').value || '').trim();
3490
+ var nextAction = ($('beNextAction').value || '').trim();
3491
+
3492
+ try {
3493
+ await api('/api/blockers/update', {
3494
+ dir: dirOrDefault(), id: id,
3495
+ patch: { title: title, severity: severity, status: status, projectSlug: slug, owner: owner, nextAction: nextAction }
3496
+ });
3497
+ closeBlockerEdit();
3498
+ showToast('ok', 'Blocker atualizado');
3499
+ await loadKanban();
3500
+ } catch { showToast('err', 'Falhou'); }
3501
+ }
3502
+
3503
+ // Close modals on Escape
3504
+ document.addEventListener('keydown', function(e) {
3505
+ if (e.key === 'Escape') {
3506
+ if ($('taskEditOverlay') && $('taskEditOverlay').style.display !== 'none') closeTaskEdit();
3507
+ if ($('blockerEditOverlay') && $('blockerEditOverlay').style.display !== 'none') closeBlockerEdit();
3508
+ }
3509
+ });
3510
+
3345
3511
  window.loadKanban = loadKanban;
3346
3512
  window.filterKanban = filterKanban;
3347
3513
  window.loadDelta = loadDelta;
3514
+ window.openTaskEdit = openTaskEdit;
3515
+ window.closeTaskEdit = closeTaskEdit;
3516
+ window.submitTaskEdit = submitTaskEdit;
3517
+ window.openBlockerEdit = openBlockerEdit;
3518
+ window.closeBlockerEdit = closeBlockerEdit;
3519
+ window.submitBlockerEdit = submitBlockerEdit;
3348
3520
  })();
package/cli/web.js CHANGED
@@ -1110,6 +1110,79 @@ function buildDocsHtml(safeDefault, appVersion) {
1110
1110
  </div>
1111
1111
  </div>
1112
1112
 
1113
+ <!-- Task Edit Modal -->
1114
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
1115
+ <div class="qa-modal" style="width:520px;">
1116
+ <div class="qa-header">
1117
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
1118
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
1119
+ </div>
1120
+ <input type="hidden" id="teTaskId" />
1121
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
1122
+ <div class="qa-row">
1123
+ <select id="teCat" class="qa-select">
1124
+ <option value="DO_NOW">DO_NOW</option>
1125
+ <option value="SCHEDULE">SCHEDULE</option>
1126
+ <option value="DELEGATE">DELEGATE</option>
1127
+ </select>
1128
+ <select id="tePriority" class="qa-select">
1129
+ <option value="">Prioridade</option>
1130
+ <option value="critical">Cr\u00edtica</option>
1131
+ <option value="high">Alta</option>
1132
+ <option value="medium">M\u00e9dia</option>
1133
+ <option value="low">Baixa</option>
1134
+ </select>
1135
+ </div>
1136
+ <div class="qa-row">
1137
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1138
+ <div class="qa-date-wrap">
1139
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
1140
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
1141
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
1142
+ </div>
1143
+ </div>
1144
+ <div class="qa-row">
1145
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
1146
+ </div>
1147
+ <div class="qa-row" style="justify-content:flex-end;">
1148
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
1149
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
1150
+ </div>
1151
+ </div>
1152
+ </div>
1153
+ <!-- Blocker Edit Modal -->
1154
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
1155
+ <div class="qa-modal" style="width:520px;">
1156
+ <div class="qa-header">
1157
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
1158
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
1159
+ </div>
1160
+ <input type="hidden" id="beBlockerId" />
1161
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
1162
+ <div class="qa-row">
1163
+ <select id="beSeverity" class="qa-select">
1164
+ <option value="CRITICAL">Critical</option>
1165
+ <option value="HIGH">High</option>
1166
+ <option value="MEDIUM">Medium</option>
1167
+ <option value="LOW">Low</option>
1168
+ </select>
1169
+ <select id="beStatus" class="qa-select">
1170
+ <option value="OPEN">Open</option>
1171
+ <option value="MITIGATING">Mitigating</option>
1172
+ <option value="RESOLVED">Resolved</option>
1173
+ </select>
1174
+ </div>
1175
+ <div class="qa-row">
1176
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1177
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
1178
+ </div>
1179
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
1180
+ <div class="qa-row" style="justify-content:flex-end;">
1181
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
1182
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
1183
+ </div>
1184
+ </div>
1185
+ </div>
1113
1186
  <script>
1114
1187
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
1115
1188
  </script>
@@ -1289,13 +1362,35 @@ function buildHtml(safeDefault, appVersion) {
1289
1362
  </div>
1290
1363
  </div>
1291
1364
 
1292
- <!-- Blockers strip below kanban -->
1365
+ <!-- Blocker Kanban Board -->
1293
1366
  <div id="kanbanBlockers" style="margin-top:20px; display:none;">
1294
1367
  <div style="font-size:13px; font-weight:700; color:var(--text); margin-bottom:8px; display:flex; align-items:center; gap:6px;">
1295
1368
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
1296
- Blockers Ativos
1369
+ Blockers
1370
+ </div>
1371
+ <div id="blockerKanbanBoard" class="blocker-kanban-board">
1372
+ <div class="blocker-kanban-col" data-blocker-status="OPEN">
1373
+ <div class="kanban-col-head blocker-open">
1374
+ <span class="kanban-col-title">OPEN</span>
1375
+ <span class="kanban-col-count" id="countBlockerOpen">0</span>
1376
+ </div>
1377
+ <div class="blocker-kanban-col-body" id="colBlockerOpen"></div>
1378
+ </div>
1379
+ <div class="blocker-kanban-col" data-blocker-status="MITIGATING">
1380
+ <div class="kanban-col-head blocker-mitigating">
1381
+ <span class="kanban-col-title">MITIGATING</span>
1382
+ <span class="kanban-col-count" id="countBlockerMitigating">0</span>
1383
+ </div>
1384
+ <div class="blocker-kanban-col-body" id="colBlockerMitigating"></div>
1385
+ </div>
1386
+ <div class="blocker-kanban-col" data-blocker-status="RESOLVED">
1387
+ <div class="kanban-col-head blocker-resolved">
1388
+ <span class="kanban-col-title">RESOLVED (7d)</span>
1389
+ <span class="kanban-col-count" id="countBlockerResolved">0</span>
1390
+ </div>
1391
+ <div class="blocker-kanban-col-body" id="colBlockerResolved"></div>
1392
+ </div>
1297
1393
  </div>
1298
- <div id="kanbanBlockersList" class="kanban-blockers-list"></div>
1299
1394
  </div>
1300
1395
 
1301
1396
  <!-- Insights de bloqueios -->
@@ -1353,6 +1448,79 @@ function buildHtml(safeDefault, appVersion) {
1353
1448
  </div>
1354
1449
  </div>
1355
1450
 
1451
+ <!-- Task Edit Modal -->
1452
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
1453
+ <div class="qa-modal" style="width:520px;">
1454
+ <div class="qa-header">
1455
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
1456
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
1457
+ </div>
1458
+ <input type="hidden" id="teTaskId" />
1459
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
1460
+ <div class="qa-row">
1461
+ <select id="teCat" class="qa-select">
1462
+ <option value="DO_NOW">DO_NOW</option>
1463
+ <option value="SCHEDULE">SCHEDULE</option>
1464
+ <option value="DELEGATE">DELEGATE</option>
1465
+ </select>
1466
+ <select id="tePriority" class="qa-select">
1467
+ <option value="">Prioridade</option>
1468
+ <option value="critical">Cr\u00edtica</option>
1469
+ <option value="high">Alta</option>
1470
+ <option value="medium">M\u00e9dia</option>
1471
+ <option value="low">Baixa</option>
1472
+ </select>
1473
+ </div>
1474
+ <div class="qa-row">
1475
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1476
+ <div class="qa-date-wrap">
1477
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
1478
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
1479
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
1480
+ </div>
1481
+ </div>
1482
+ <div class="qa-row">
1483
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
1484
+ </div>
1485
+ <div class="qa-row" style="justify-content:flex-end;">
1486
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
1487
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
1488
+ </div>
1489
+ </div>
1490
+ </div>
1491
+ <!-- Blocker Edit Modal -->
1492
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
1493
+ <div class="qa-modal" style="width:520px;">
1494
+ <div class="qa-header">
1495
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
1496
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
1497
+ </div>
1498
+ <input type="hidden" id="beBlockerId" />
1499
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
1500
+ <div class="qa-row">
1501
+ <select id="beSeverity" class="qa-select">
1502
+ <option value="CRITICAL">Critical</option>
1503
+ <option value="HIGH">High</option>
1504
+ <option value="MEDIUM">Medium</option>
1505
+ <option value="LOW">Low</option>
1506
+ </select>
1507
+ <select id="beStatus" class="qa-select">
1508
+ <option value="OPEN">Open</option>
1509
+ <option value="MITIGATING">Mitigating</option>
1510
+ <option value="RESOLVED">Resolved</option>
1511
+ </select>
1512
+ </div>
1513
+ <div class="qa-row">
1514
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1515
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
1516
+ </div>
1517
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
1518
+ <div class="qa-row" style="justify-content:flex-end;">
1519
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
1520
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
1521
+ </div>
1522
+ </div>
1523
+ </div>
1356
1524
  <script>
1357
1525
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
1358
1526
  </script>
@@ -1469,6 +1637,79 @@ function buildReportsHtml(safeDefault, appVersion) {
1469
1637
  </div>
1470
1638
  </div>
1471
1639
 
1640
+ <!-- Task Edit Modal -->
1641
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
1642
+ <div class="qa-modal" style="width:520px;">
1643
+ <div class="qa-header">
1644
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
1645
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
1646
+ </div>
1647
+ <input type="hidden" id="teTaskId" />
1648
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
1649
+ <div class="qa-row">
1650
+ <select id="teCat" class="qa-select">
1651
+ <option value="DO_NOW">DO_NOW</option>
1652
+ <option value="SCHEDULE">SCHEDULE</option>
1653
+ <option value="DELEGATE">DELEGATE</option>
1654
+ </select>
1655
+ <select id="tePriority" class="qa-select">
1656
+ <option value="">Prioridade</option>
1657
+ <option value="critical">Cr\u00edtica</option>
1658
+ <option value="high">Alta</option>
1659
+ <option value="medium">M\u00e9dia</option>
1660
+ <option value="low">Baixa</option>
1661
+ </select>
1662
+ </div>
1663
+ <div class="qa-row">
1664
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1665
+ <div class="qa-date-wrap">
1666
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
1667
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
1668
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
1669
+ </div>
1670
+ </div>
1671
+ <div class="qa-row">
1672
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
1673
+ </div>
1674
+ <div class="qa-row" style="justify-content:flex-end;">
1675
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
1676
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
1677
+ </div>
1678
+ </div>
1679
+ </div>
1680
+ <!-- Blocker Edit Modal -->
1681
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
1682
+ <div class="qa-modal" style="width:520px;">
1683
+ <div class="qa-header">
1684
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
1685
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
1686
+ </div>
1687
+ <input type="hidden" id="beBlockerId" />
1688
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
1689
+ <div class="qa-row">
1690
+ <select id="beSeverity" class="qa-select">
1691
+ <option value="CRITICAL">Critical</option>
1692
+ <option value="HIGH">High</option>
1693
+ <option value="MEDIUM">Medium</option>
1694
+ <option value="LOW">Low</option>
1695
+ </select>
1696
+ <select id="beStatus" class="qa-select">
1697
+ <option value="OPEN">Open</option>
1698
+ <option value="MITIGATING">Mitigating</option>
1699
+ <option value="RESOLVED">Resolved</option>
1700
+ </select>
1701
+ </div>
1702
+ <div class="qa-row">
1703
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1704
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
1705
+ </div>
1706
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
1707
+ <div class="qa-row" style="justify-content:flex-end;">
1708
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
1709
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
1710
+ </div>
1711
+ </div>
1712
+ </div>
1472
1713
  <script>
1473
1714
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
1474
1715
  </script>
@@ -1565,6 +1806,79 @@ function buildProjectsHtml(safeDefault, appVersion) {
1565
1806
  </div>
1566
1807
  </div>
1567
1808
 
1809
+ <!-- Task Edit Modal -->
1810
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
1811
+ <div class="qa-modal" style="width:520px;">
1812
+ <div class="qa-header">
1813
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
1814
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
1815
+ </div>
1816
+ <input type="hidden" id="teTaskId" />
1817
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
1818
+ <div class="qa-row">
1819
+ <select id="teCat" class="qa-select">
1820
+ <option value="DO_NOW">DO_NOW</option>
1821
+ <option value="SCHEDULE">SCHEDULE</option>
1822
+ <option value="DELEGATE">DELEGATE</option>
1823
+ </select>
1824
+ <select id="tePriority" class="qa-select">
1825
+ <option value="">Prioridade</option>
1826
+ <option value="critical">Cr\u00edtica</option>
1827
+ <option value="high">Alta</option>
1828
+ <option value="medium">M\u00e9dia</option>
1829
+ <option value="low">Baixa</option>
1830
+ </select>
1831
+ </div>
1832
+ <div class="qa-row">
1833
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1834
+ <div class="qa-date-wrap">
1835
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
1836
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
1837
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
1838
+ </div>
1839
+ </div>
1840
+ <div class="qa-row">
1841
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
1842
+ </div>
1843
+ <div class="qa-row" style="justify-content:flex-end;">
1844
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
1845
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
1846
+ </div>
1847
+ </div>
1848
+ </div>
1849
+ <!-- Blocker Edit Modal -->
1850
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
1851
+ <div class="qa-modal" style="width:520px;">
1852
+ <div class="qa-header">
1853
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
1854
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
1855
+ </div>
1856
+ <input type="hidden" id="beBlockerId" />
1857
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
1858
+ <div class="qa-row">
1859
+ <select id="beSeverity" class="qa-select">
1860
+ <option value="CRITICAL">Critical</option>
1861
+ <option value="HIGH">High</option>
1862
+ <option value="MEDIUM">Medium</option>
1863
+ <option value="LOW">Low</option>
1864
+ </select>
1865
+ <select id="beStatus" class="qa-select">
1866
+ <option value="OPEN">Open</option>
1867
+ <option value="MITIGATING">Mitigating</option>
1868
+ <option value="RESOLVED">Resolved</option>
1869
+ </select>
1870
+ </div>
1871
+ <div class="qa-row">
1872
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
1873
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
1874
+ </div>
1875
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
1876
+ <div class="qa-row" style="justify-content:flex-end;">
1877
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
1878
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
1879
+ </div>
1880
+ </div>
1881
+ </div>
1568
1882
  <script>
1569
1883
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
1570
1884
  </script>
@@ -1771,6 +2085,79 @@ function buildGraphHtml(safeDefault, appVersion) {
1771
2085
  </div>
1772
2086
  </div>
1773
2087
 
2088
+ <!-- Task Edit Modal -->
2089
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
2090
+ <div class="qa-modal" style="width:520px;">
2091
+ <div class="qa-header">
2092
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
2093
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
2094
+ </div>
2095
+ <input type="hidden" id="teTaskId" />
2096
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
2097
+ <div class="qa-row">
2098
+ <select id="teCat" class="qa-select">
2099
+ <option value="DO_NOW">DO_NOW</option>
2100
+ <option value="SCHEDULE">SCHEDULE</option>
2101
+ <option value="DELEGATE">DELEGATE</option>
2102
+ </select>
2103
+ <select id="tePriority" class="qa-select">
2104
+ <option value="">Prioridade</option>
2105
+ <option value="critical">Cr\u00edtica</option>
2106
+ <option value="high">Alta</option>
2107
+ <option value="medium">M\u00e9dia</option>
2108
+ <option value="low">Baixa</option>
2109
+ </select>
2110
+ </div>
2111
+ <div class="qa-row">
2112
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
2113
+ <div class="qa-date-wrap">
2114
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
2115
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
2116
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
2117
+ </div>
2118
+ </div>
2119
+ <div class="qa-row">
2120
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
2121
+ </div>
2122
+ <div class="qa-row" style="justify-content:flex-end;">
2123
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
2124
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
2125
+ </div>
2126
+ </div>
2127
+ </div>
2128
+ <!-- Blocker Edit Modal -->
2129
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
2130
+ <div class="qa-modal" style="width:520px;">
2131
+ <div class="qa-header">
2132
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
2133
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
2134
+ </div>
2135
+ <input type="hidden" id="beBlockerId" />
2136
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
2137
+ <div class="qa-row">
2138
+ <select id="beSeverity" class="qa-select">
2139
+ <option value="CRITICAL">Critical</option>
2140
+ <option value="HIGH">High</option>
2141
+ <option value="MEDIUM">Medium</option>
2142
+ <option value="LOW">Low</option>
2143
+ </select>
2144
+ <select id="beStatus" class="qa-select">
2145
+ <option value="OPEN">Open</option>
2146
+ <option value="MITIGATING">Mitigating</option>
2147
+ <option value="RESOLVED">Resolved</option>
2148
+ </select>
2149
+ </div>
2150
+ <div class="qa-row">
2151
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
2152
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
2153
+ </div>
2154
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
2155
+ <div class="qa-row" style="justify-content:flex-end;">
2156
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
2157
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
2158
+ </div>
2159
+ </div>
2160
+ </div>
1774
2161
  <script>
1775
2162
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
1776
2163
  </script>
@@ -1907,6 +2294,79 @@ function buildCompanionHtml(safeDefault, appVersion) {
1907
2294
  </div>
1908
2295
  </div>
1909
2296
 
2297
+ <!-- Task Edit Modal -->
2298
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
2299
+ <div class="qa-modal" style="width:520px;">
2300
+ <div class="qa-header">
2301
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
2302
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
2303
+ </div>
2304
+ <input type="hidden" id="teTaskId" />
2305
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
2306
+ <div class="qa-row">
2307
+ <select id="teCat" class="qa-select">
2308
+ <option value="DO_NOW">DO_NOW</option>
2309
+ <option value="SCHEDULE">SCHEDULE</option>
2310
+ <option value="DELEGATE">DELEGATE</option>
2311
+ </select>
2312
+ <select id="tePriority" class="qa-select">
2313
+ <option value="">Prioridade</option>
2314
+ <option value="critical">Cr\u00edtica</option>
2315
+ <option value="high">Alta</option>
2316
+ <option value="medium">M\u00e9dia</option>
2317
+ <option value="low">Baixa</option>
2318
+ </select>
2319
+ </div>
2320
+ <div class="qa-row">
2321
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
2322
+ <div class="qa-date-wrap">
2323
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
2324
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
2325
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
2326
+ </div>
2327
+ </div>
2328
+ <div class="qa-row">
2329
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
2330
+ </div>
2331
+ <div class="qa-row" style="justify-content:flex-end;">
2332
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
2333
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
2334
+ </div>
2335
+ </div>
2336
+ </div>
2337
+ <!-- Blocker Edit Modal -->
2338
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
2339
+ <div class="qa-modal" style="width:520px;">
2340
+ <div class="qa-header">
2341
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
2342
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
2343
+ </div>
2344
+ <input type="hidden" id="beBlockerId" />
2345
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
2346
+ <div class="qa-row">
2347
+ <select id="beSeverity" class="qa-select">
2348
+ <option value="CRITICAL">Critical</option>
2349
+ <option value="HIGH">High</option>
2350
+ <option value="MEDIUM">Medium</option>
2351
+ <option value="LOW">Low</option>
2352
+ </select>
2353
+ <select id="beStatus" class="qa-select">
2354
+ <option value="OPEN">Open</option>
2355
+ <option value="MITIGATING">Mitigating</option>
2356
+ <option value="RESOLVED">Resolved</option>
2357
+ </select>
2358
+ </div>
2359
+ <div class="qa-row">
2360
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
2361
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
2362
+ </div>
2363
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
2364
+ <div class="qa-row" style="justify-content:flex-end;">
2365
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
2366
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
2367
+ </div>
2368
+ </div>
2369
+ </div>
1910
2370
  <script>
1911
2371
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
1912
2372
  </script>
@@ -3322,20 +3782,21 @@ async function cmdWeb({ port, dir, open, dev }) {
3322
3782
  ]
3323
3783
  };
3324
3784
 
3325
- 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)${planImageContext}\n\nREGRAS:${rulesText}\n\nINPUT DO USUÁRIO:\n${text}\n`;
3785
+ // Build the system instructions (small, always fits in -p)
3786
+ const sysInstructions = `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)${planImageContext}`;
3326
3787
 
3327
3788
  // Prefer COPILOT_CMD if provided, otherwise try 'copilot'
3328
3789
  const cmd = process.env.COPILOT_CMD || 'copilot';
3329
3790
 
3330
- // Best-effort: if Copilot CLI isn't available, return 200 with an explanatory plan
3331
- // so the UI can show actionable next steps instead of hard-failing.
3332
3791
  // BUG-48: pass FREYA_WORKSPACE_DIR so the Copilot subprocess uses correct DB
3333
3792
  const agentEnv = { FREYA_WORKSPACE_DIR: workspaceDir };
3334
3793
 
3335
- // ENAMETOOLONG fix: when prompt exceeds safe CLI arg length,
3336
- // write to temp file and pipe via stdin instead of -p argument.
3337
- const SAFE_ARG_LEN = 24000; // ~24KB safe threshold (Windows CreateProcess limit is 32KB)
3338
- const useTempFile = prompt.length > SAFE_ARG_LEN;
3794
+ // ENAMETOOLONG fix: when user text is large, write it to a temp file
3795
+ // and reference it in the prompt. System instructions stay in -p (small).
3796
+ // The user text is the large part; rules are moderate (~10KB).
3797
+ const fullPrompt = `${sysInstructions}\n\nREGRAS:${rulesText}\n\nINPUT DO USUÁRIO:\n${text}\n`;
3798
+ const SAFE_ARG_LEN = 24000; // ~24KB safe for Windows CreateProcess
3799
+ const needsFile = fullPrompt.length > SAFE_ARG_LEN;
3339
3800
  let tmpFile = null;
3340
3801
 
3341
3802
  try {
@@ -3343,13 +3804,27 @@ async function cmdWeb({ port, dir, open, dev }) {
3343
3804
  const baseArgs = ['-s', '--no-color', '--stream', 'off'];
3344
3805
  if (planImageDir) baseArgs.push('--add-dir', planImageDir);
3345
3806
 
3346
- if (useTempFile) {
3347
- tmpFile = path.join(os.tmpdir(), `freya-prompt-${Date.now()}.txt`);
3348
- fs.writeFileSync(tmpFile, prompt, 'utf8');
3349
- // Use -p with short hint + pipe full prompt via stdin
3350
- r = await run(cmd, [...baseArgs, '-p', `Read the full prompt from the file: ${tmpFile}`, '--allow-all-tools'], workspaceDir, agentEnv, prompt);
3807
+ if (needsFile) {
3808
+ // Write ONLY the user text to a temp file; keep instructions in -p
3809
+ tmpFile = path.join(os.tmpdir(), `freya-input-${Date.now()}.txt`);
3810
+ fs.writeFileSync(tmpFile, text, 'utf8');
3811
+ // -p contains: system instructions + rules + reference to the file
3812
+ const filePrompt = `${sysInstructions}\n\nREGRAS:${rulesText}\n\nINPUT DO USUÁRIO:\nO texto do usuário é MUITO GRANDE e foi salvo no arquivo abaixo. Você DEVE ler o conteúdo completo deste arquivo usando suas ferramentas de leitura de arquivo e processar TODO o conteúdo como input do usuário.\nARQUIVO: ${tmpFile}\n\nIMPORTANTE: NÃO descreva o arquivo. LEIA o conteúdo e processe-o gerando as ações JSON conforme as regras acima.\n`;
3813
+ // If even the filePrompt (instructions + rules + file ref) is too large,
3814
+ // also write rules to a separate file
3815
+ if (filePrompt.length > SAFE_ARG_LEN) {
3816
+ const rulesTmpFile = path.join(os.tmpdir(), `freya-rules-${Date.now()}.txt`);
3817
+ fs.writeFileSync(rulesTmpFile, rulesText, 'utf8');
3818
+ const minPrompt = `${sysInstructions}\n\nREGRAS: Leia as regras do arquivo: ${rulesTmpFile}\n\nINPUT DO USUÁRIO:\nO texto do usuário é MUITO GRANDE e foi salvo no arquivo abaixo. Você DEVE ler o conteúdo completo deste arquivo e processar TODO o conteúdo como input do usuário.\nARQUIVO: ${tmpFile}\n\nIMPORTANTE: NÃO descreva os arquivos. LEIA os conteúdos e processe-os gerando as ações JSON conforme as regras.\n`;
3819
+ baseArgs.push('--add-dir', os.tmpdir());
3820
+ r = await run(cmd, [...baseArgs, '-p', minPrompt, '--allow-all-tools'], workspaceDir, agentEnv);
3821
+ try { fs.unlinkSync(rulesTmpFile); } catch (_) { /* ignore */ }
3822
+ } else {
3823
+ baseArgs.push('--add-dir', os.tmpdir());
3824
+ r = await run(cmd, [...baseArgs, '-p', filePrompt, '--allow-all-tools'], workspaceDir, agentEnv);
3825
+ }
3351
3826
  } else {
3352
- r = await run(cmd, [...baseArgs, '-p', prompt, '--allow-all-tools'], workspaceDir, agentEnv);
3827
+ r = await run(cmd, [...baseArgs, '-p', fullPrompt, '--allow-all-tools'], workspaceDir, agentEnv);
3353
3828
  }
3354
3829
  const out = (r.stdout + r.stderr).trim();
3355
3830
  if (r.code !== 0) {
@@ -3820,7 +4295,8 @@ async function cmdWeb({ port, dir, open, dev }) {
3820
4295
  }
3821
4296
  }
3822
4297
 
3823
- 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}${imageContext}\n\nREGRAS:${rulesText}\n\nCONSULTA DO USUÁRIO:\n${query}\n`;
4298
+ // System instructions (small, always fits in -p)
4299
+ const oracleSysInstr = `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}${imageContext}`;
3824
4300
 
3825
4301
  const cmd = process.env.COPILOT_CMD || 'copilot';
3826
4302
 
@@ -3835,21 +4311,21 @@ async function cmdWeb({ port, dir, open, dev }) {
3835
4311
  copilotArgs.push('--add-dir', path.dirname(absImg));
3836
4312
  }
3837
4313
  }
3838
- copilotArgs.push('--allow-all-tools', '-p', prompt);
3839
4314
 
3840
- // ENAMETOOLONG fix: use stdin for large prompts
4315
+ // ENAMETOOLONG fix: when prompt is large, write user query to temp file
4316
+ const fullOraclePrompt = `${oracleSysInstr}\n\nREGRAS:${rulesText}\n\nCONSULTA DO USUÁRIO:\n${query}\n`;
3841
4317
  const SAFE_ARG_LEN = 24000;
3842
4318
  let oracleTmpFile = null;
3843
4319
  let r;
3844
- if (prompt.length > SAFE_ARG_LEN) {
3845
- oracleTmpFile = path.join(os.tmpdir(), `freya-oracle-${Date.now()}.txt`);
3846
- fs.writeFileSync(oracleTmpFile, prompt, 'utf8');
3847
- // Replace -p with short hint; pipe full prompt via stdin
3848
- const idx = copilotArgs.indexOf('-p');
3849
- if (idx !== -1) copilotArgs.splice(idx, 2); // remove -p and prompt
3850
- copilotArgs.push('-p', `Read the full prompt from: ${oracleTmpFile}`);
3851
- r = await run(cmd, copilotArgs, workspaceDir, oracleEnv, prompt);
4320
+ if (fullOraclePrompt.length > SAFE_ARG_LEN) {
4321
+ oracleTmpFile = path.join(os.tmpdir(), `freya-oracle-input-${Date.now()}.txt`);
4322
+ fs.writeFileSync(oracleTmpFile, query, 'utf8');
4323
+ const filePrompt = `${oracleSysInstr}\n\nREGRAS:${rulesText}\n\nCONSULTA DO USUÁRIO:\nA consulta do usuário é grande e foi salva no arquivo abaixo. LEIA o conteúdo completo do arquivo e responda com base nele.\nARQUIVO: ${oracleTmpFile}\n\nIMPORTANTE: NÃO descreva o arquivo. LEIA e RESPONDA à consulta.\n`;
4324
+ copilotArgs.push('--add-dir', os.tmpdir());
4325
+ copilotArgs.push('--allow-all-tools', '-p', filePrompt);
4326
+ r = await run(cmd, copilotArgs, workspaceDir, oracleEnv);
3852
4327
  } else {
4328
+ copilotArgs.push('--allow-all-tools', '-p', fullOraclePrompt);
3853
4329
  r = await run(cmd, copilotArgs, workspaceDir, oracleEnv);
3854
4330
  }
3855
4331
  if (oracleTmpFile) { try { fs.unlinkSync(oracleTmpFile); } catch (_) { /* ignore */ } }
@@ -4064,11 +4540,14 @@ async function cmdWeb({ port, dir, open, dev }) {
4064
4540
  queryUpdates.push('description = ?');
4065
4541
  params.push(patch.description.trim());
4066
4542
  }
4067
- if (typeof patch.priority === 'string') {
4543
+ // Handle all metadata fields in one read-modify-write
4544
+ const hasMetaPatch = typeof patch.priority === 'string' || typeof patch.streamSlug === 'string';
4545
+ if (hasMetaPatch) {
4068
4546
  const row = dl.db.prepare('SELECT metadata FROM tasks WHERE id = ?').get(id);
4069
4547
  let meta = {};
4070
4548
  try { meta = row && row.metadata ? JSON.parse(row.metadata) : {}; } catch { meta = {}; }
4071
- meta.priority = patch.priority.trim().toLowerCase();
4549
+ if (typeof patch.priority === 'string') meta.priority = patch.priority.trim().toLowerCase() || undefined;
4550
+ if (typeof patch.streamSlug === 'string') meta.streamSlug = patch.streamSlug.trim() || undefined;
4072
4551
  queryUpdates.push('metadata = ?');
4073
4552
  params.push(JSON.stringify(meta));
4074
4553
  }
@@ -4327,12 +4806,15 @@ async function cmdWeb({ port, dir, open, dev }) {
4327
4806
  };
4328
4807
  });
4329
4808
 
4809
+ const sevenDaysAgo = new Date(Date.now() - 7 * 86400000).toISOString();
4330
4810
  const openBlockers = dl.db.prepare(`
4331
4811
  SELECT * FROM blockers WHERE status IN ('OPEN', 'MITIGATING')
4812
+ OR (status = 'RESOLVED' AND resolved_at >= ?)
4332
4813
  ORDER BY
4814
+ CASE status WHEN 'OPEN' THEN 0 WHEN 'MITIGATING' THEN 1 WHEN 'RESOLVED' THEN 2 ELSE 9 END ASC,
4333
4815
  CASE severity WHEN 'CRITICAL' THEN 0 WHEN 'HIGH' THEN 1 WHEN 'MEDIUM' THEN 2 WHEN 'LOW' THEN 3 ELSE 9 END ASC,
4334
4816
  created_at ASC
4335
- `).all().map(b => {
4817
+ `).all(sevenDaysAgo).map(b => {
4336
4818
  let meta = {};
4337
4819
  try { meta = b.metadata ? JSON.parse(b.metadata) : {}; } catch { meta = {}; }
4338
4820
  return {
@@ -4589,6 +5071,79 @@ function buildSettingsHtml(safeDefault, appVersion) {
4589
5071
  </div>
4590
5072
  </div>
4591
5073
 
5074
+ <!-- Task Edit Modal -->
5075
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
5076
+ <div class="qa-modal" style="width:520px;">
5077
+ <div class="qa-header">
5078
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
5079
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
5080
+ </div>
5081
+ <input type="hidden" id="teTaskId" />
5082
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
5083
+ <div class="qa-row">
5084
+ <select id="teCat" class="qa-select">
5085
+ <option value="DO_NOW">DO_NOW</option>
5086
+ <option value="SCHEDULE">SCHEDULE</option>
5087
+ <option value="DELEGATE">DELEGATE</option>
5088
+ </select>
5089
+ <select id="tePriority" class="qa-select">
5090
+ <option value="">Prioridade</option>
5091
+ <option value="critical">Cr\u00edtica</option>
5092
+ <option value="high">Alta</option>
5093
+ <option value="medium">M\u00e9dia</option>
5094
+ <option value="low">Baixa</option>
5095
+ </select>
5096
+ </div>
5097
+ <div class="qa-row">
5098
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
5099
+ <div class="qa-date-wrap">
5100
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
5101
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
5102
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
5103
+ </div>
5104
+ </div>
5105
+ <div class="qa-row">
5106
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
5107
+ </div>
5108
+ <div class="qa-row" style="justify-content:flex-end;">
5109
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
5110
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
5111
+ </div>
5112
+ </div>
5113
+ </div>
5114
+ <!-- Blocker Edit Modal -->
5115
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
5116
+ <div class="qa-modal" style="width:520px;">
5117
+ <div class="qa-header">
5118
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
5119
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
5120
+ </div>
5121
+ <input type="hidden" id="beBlockerId" />
5122
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
5123
+ <div class="qa-row">
5124
+ <select id="beSeverity" class="qa-select">
5125
+ <option value="CRITICAL">Critical</option>
5126
+ <option value="HIGH">High</option>
5127
+ <option value="MEDIUM">Medium</option>
5128
+ <option value="LOW">Low</option>
5129
+ </select>
5130
+ <select id="beStatus" class="qa-select">
5131
+ <option value="OPEN">Open</option>
5132
+ <option value="MITIGATING">Mitigating</option>
5133
+ <option value="RESOLVED">Resolved</option>
5134
+ </select>
5135
+ </div>
5136
+ <div class="qa-row">
5137
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
5138
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
5139
+ </div>
5140
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
5141
+ <div class="qa-row" style="justify-content:flex-end;">
5142
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
5143
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
5144
+ </div>
5145
+ </div>
5146
+ </div>
4592
5147
  <script>
4593
5148
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
4594
5149
  </script>
@@ -4712,13 +5267,35 @@ function buildKanbanHtml(safeDefault, appVersion) {
4712
5267
  </div>
4713
5268
  </div>
4714
5269
 
4715
- <!-- Blockers strip below kanban -->
5270
+ <!-- Blocker Kanban Board -->
4716
5271
  <div id="kanbanBlockers" style="margin-top:20px; display:none;">
4717
5272
  <div style="font-size:13px; font-weight:700; color:var(--text); margin-bottom:8px; display:flex; align-items:center; gap:6px;">
4718
5273
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
4719
- Blockers Ativos
5274
+ Blockers
5275
+ </div>
5276
+ <div id="blockerKanbanBoard" class="blocker-kanban-board">
5277
+ <div class="blocker-kanban-col" data-blocker-status="OPEN">
5278
+ <div class="kanban-col-head blocker-open">
5279
+ <span class="kanban-col-title">OPEN</span>
5280
+ <span class="kanban-col-count" id="countBlockerOpen">0</span>
5281
+ </div>
5282
+ <div class="blocker-kanban-col-body" id="colBlockerOpen"></div>
5283
+ </div>
5284
+ <div class="blocker-kanban-col" data-blocker-status="MITIGATING">
5285
+ <div class="kanban-col-head blocker-mitigating">
5286
+ <span class="kanban-col-title">MITIGATING</span>
5287
+ <span class="kanban-col-count" id="countBlockerMitigating">0</span>
5288
+ </div>
5289
+ <div class="blocker-kanban-col-body" id="colBlockerMitigating"></div>
5290
+ </div>
5291
+ <div class="blocker-kanban-col" data-blocker-status="RESOLVED">
5292
+ <div class="kanban-col-head blocker-resolved">
5293
+ <span class="kanban-col-title">RESOLVED (7d)</span>
5294
+ <span class="kanban-col-count" id="countBlockerResolved">0</span>
5295
+ </div>
5296
+ <div class="blocker-kanban-col-body" id="colBlockerResolved"></div>
5297
+ </div>
4720
5298
  </div>
4721
- <div id="kanbanBlockersList" class="kanban-blockers-list"></div>
4722
5299
  </div>
4723
5300
  </div>
4724
5301
  </main>
@@ -4763,6 +5340,79 @@ function buildKanbanHtml(safeDefault, appVersion) {
4763
5340
  </div>
4764
5341
  </div>
4765
5342
 
5343
+ <!-- Task Edit Modal -->
5344
+ <div id="taskEditOverlay" class="qa-overlay" style="display:none;">
5345
+ <div class="qa-modal" style="width:520px;">
5346
+ <div class="qa-header">
5347
+ <span style="font-weight:700; font-size:14px;">Editar Task</span>
5348
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()" style="padding:2px 8px;">&times;</button>
5349
+ </div>
5350
+ <input type="hidden" id="teTaskId" />
5351
+ <textarea id="teDesc" class="qa-input" placeholder="Descri\u00e7\u00e3o da task..." rows="3"></textarea>
5352
+ <div class="qa-row">
5353
+ <select id="teCat" class="qa-select">
5354
+ <option value="DO_NOW">DO_NOW</option>
5355
+ <option value="SCHEDULE">SCHEDULE</option>
5356
+ <option value="DELEGATE">DELEGATE</option>
5357
+ </select>
5358
+ <select id="tePriority" class="qa-select">
5359
+ <option value="">Prioridade</option>
5360
+ <option value="critical">Cr\u00edtica</option>
5361
+ <option value="high">Alta</option>
5362
+ <option value="medium">M\u00e9dia</option>
5363
+ <option value="low">Baixa</option>
5364
+ </select>
5365
+ </div>
5366
+ <div class="qa-row">
5367
+ <input id="teSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
5368
+ <div class="qa-date-wrap">
5369
+ <input id="teDue" type="text" class="qa-input qa-date-text" placeholder="dd/mm/aaaa" maxlength="10" />
5370
+ <input id="teDuePicker" type="date" class="qa-date-hidden" tabindex="-1" />
5371
+ <button type="button" class="qa-date-btn" onclick="var p=document.getElementById('teDuePicker'); p.showPicker ? p.showPicker() : p.click();" title="Abrir calendario">&#128197;</button>
5372
+ </div>
5373
+ </div>
5374
+ <div class="qa-row">
5375
+ <input id="teStream" class="qa-input" placeholder="Stream / frente (opcional)" style="flex:1;" />
5376
+ </div>
5377
+ <div class="qa-row" style="justify-content:flex-end;">
5378
+ <button class="btn small" type="button" onclick="window.closeTaskEdit()">Cancelar</button>
5379
+ <button class="btn primary small" type="button" onclick="window.submitTaskEdit()">Salvar</button>
5380
+ </div>
5381
+ </div>
5382
+ </div>
5383
+ <!-- Blocker Edit Modal -->
5384
+ <div id="blockerEditOverlay" class="qa-overlay" style="display:none;">
5385
+ <div class="qa-modal" style="width:520px;">
5386
+ <div class="qa-header">
5387
+ <span style="font-weight:700; font-size:14px;">Editar Blocker</span>
5388
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()" style="padding:2px 8px;">&times;</button>
5389
+ </div>
5390
+ <input type="hidden" id="beBlockerId" />
5391
+ <textarea id="beTitle" class="qa-input" placeholder="T\u00edtulo do blocker..." rows="2"></textarea>
5392
+ <div class="qa-row">
5393
+ <select id="beSeverity" class="qa-select">
5394
+ <option value="CRITICAL">Critical</option>
5395
+ <option value="HIGH">High</option>
5396
+ <option value="MEDIUM">Medium</option>
5397
+ <option value="LOW">Low</option>
5398
+ </select>
5399
+ <select id="beStatus" class="qa-select">
5400
+ <option value="OPEN">Open</option>
5401
+ <option value="MITIGATING">Mitigating</option>
5402
+ <option value="RESOLVED">Resolved</option>
5403
+ </select>
5404
+ </div>
5405
+ <div class="qa-row">
5406
+ <input id="beSlug" class="qa-input" placeholder="Projeto (slug)" style="flex:1;" />
5407
+ <input id="beOwner" class="qa-input" placeholder="Respons\u00e1vel" style="flex:1;" />
5408
+ </div>
5409
+ <textarea id="beNextAction" class="qa-input" placeholder="Pr\u00f3xima a\u00e7\u00e3o..." rows="2"></textarea>
5410
+ <div class="qa-row" style="justify-content:flex-end;">
5411
+ <button class="btn small" type="button" onclick="window.closeBlockerEdit()">Cancelar</button>
5412
+ <button class="btn primary small" type="button" onclick="window.submitBlockerEdit()">Salvar</button>
5413
+ </div>
5414
+ </div>
5415
+ </div>
4766
5416
  <script>
4767
5417
  window.__FREYA_DEFAULT_DIR = "${safeDefault}";
4768
5418
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cccarv82/freya",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "Personal AI Assistant with local-first persistence",
5
5
  "scripts": {
6
6
  "health": "node scripts/validate-data.js && node scripts/validate-structure.js",