issue-flow 0.7.5 → 0.7.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "issue-flow",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
4
4
  "description": "Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless",
5
5
  "type": "module",
6
6
  "bin": {
@@ -234,6 +234,93 @@ select {
234
234
  margin: 0 0 4px;
235
235
  }
236
236
 
237
+ /* ---- Resumo da issue ---- */
238
+
239
+ .issue-summary-title {
240
+ margin: 0 0 8px;
241
+ font-weight: 600;
242
+ }
243
+
244
+ .issue-summary-meta {
245
+ display: flex;
246
+ flex-wrap: wrap;
247
+ align-items: center;
248
+ gap: 10px;
249
+ margin-bottom: 8px;
250
+ }
251
+
252
+ .badge-row {
253
+ display: flex;
254
+ flex-wrap: wrap;
255
+ gap: 6px;
256
+ margin-bottom: 8px;
257
+ }
258
+
259
+ .label-badge {
260
+ background: var(--idle-bg);
261
+ color: var(--fg);
262
+ text-transform: none;
263
+ font-weight: 500;
264
+ letter-spacing: normal;
265
+ }
266
+
267
+ .state-open {
268
+ background: var(--run-bg);
269
+ color: var(--run);
270
+ }
271
+
272
+ .state-closed {
273
+ background: var(--ok-bg);
274
+ color: var(--ok);
275
+ }
276
+
277
+ .state-unknown {
278
+ background: var(--idle-bg);
279
+ color: var(--muted);
280
+ }
281
+
282
+ .issue-description {
283
+ margin: 0;
284
+ white-space: pre-wrap;
285
+ word-break: break-word;
286
+ max-height: 220px;
287
+ overflow-y: auto;
288
+ }
289
+
290
+ /* ---- User stories: status e dependências ---- */
291
+
292
+ .story-meta {
293
+ display: flex;
294
+ flex-wrap: wrap;
295
+ align-items: center;
296
+ gap: 8px;
297
+ margin-top: 4px;
298
+ }
299
+
300
+ .story-status-backlog {
301
+ background: var(--idle-bg);
302
+ color: var(--muted);
303
+ }
304
+
305
+ .story-status-in_progress {
306
+ background: var(--run-bg);
307
+ color: var(--run);
308
+ }
309
+
310
+ .story-status-in_review {
311
+ background: var(--warn-bg);
312
+ color: var(--warn);
313
+ }
314
+
315
+ .story-status-done {
316
+ background: var(--ok-bg);
317
+ color: var(--ok);
318
+ }
319
+
320
+ .story-deps {
321
+ font-size: 0.84rem;
322
+ }
323
+
237
324
  /* ---- Progresso ---- */
238
325
 
239
326
  .progress-row {
package/web/public/app.js CHANGED
@@ -25,6 +25,13 @@
25
25
  failed: '✗',
26
26
  };
27
27
 
28
+ const STORY_STATUS_LABELS = {
29
+ backlog: 'backlog',
30
+ in_progress: 'em andamento',
31
+ in_review: 'em revisão',
32
+ done: 'concluída',
33
+ };
34
+
28
35
  const els = {
29
36
  banner: document.getElementById('banner-disconnected'),
30
37
  issueLink: document.getElementById('issue-link'),
@@ -35,6 +42,8 @@
35
42
  refreshSelect: document.getElementById('refresh-select'),
36
43
  alerts: document.getElementById('alerts'),
37
44
  alertsBody: document.getElementById('alerts-body'),
45
+ issueSummary: document.getElementById('issue-summary'),
46
+ repository: document.getElementById('repository'),
38
47
  progressBar: document.getElementById('progress-bar'),
39
48
  progressPercent: document.getElementById('progress-percent'),
40
49
  progressCounters: document.getElementById('progress-counters'),
@@ -266,6 +275,8 @@
266
275
  if (!snapshot) return;
267
276
  renderHeader(snapshot);
268
277
  renderAlerts(snapshot);
278
+ renderIssueSummary(snapshot);
279
+ renderRepository(snapshot);
269
280
  renderProgress(snapshot);
270
281
  renderNow(snapshot);
271
282
  renderPhases(snapshot);
@@ -341,6 +352,61 @@
341
352
  }
342
353
  }
343
354
 
355
+ // snapshot.issue vem sempre como objeto (schema não o torna nulável); só os
356
+ // campos individuais podem ser null/undefined — session.json antigo, issue
357
+ // local sem remote, etc. Cada leitura abaixo trata isso individualmente.
358
+ function renderIssueSummary(snapshot) {
359
+ clear(els.issueSummary);
360
+ const issue = snapshot.issue || {};
361
+
362
+ const heading = el('p', 'issue-summary-title');
363
+ heading.appendChild(
364
+ el('span', 'mono', issue.number !== null && issue.number !== undefined ? '#' + issue.number : '—'),
365
+ );
366
+ heading.appendChild(document.createTextNode(' ' + (issue.title || 'Sem título')));
367
+ els.issueSummary.appendChild(heading);
368
+
369
+ const meta = el('div', 'issue-summary-meta');
370
+ const state = issue.state || null;
371
+ const stateClass = state === 'open' ? 'state-open' : state === 'closed' ? 'state-closed' : 'state-unknown';
372
+ meta.appendChild(el('span', 'badge ' + stateClass, state || 'estado desconhecido'));
373
+ meta.appendChild(el('span', 'muted', 'Prioridade: Não definida'));
374
+ els.issueSummary.appendChild(meta);
375
+
376
+ const labels = issue.labels || [];
377
+ if (labels.length > 0) {
378
+ const labelRow = el('div', 'badge-row');
379
+ for (const label of labels) {
380
+ labelRow.appendChild(el('span', 'badge label-badge', label));
381
+ }
382
+ els.issueSummary.appendChild(labelRow);
383
+ }
384
+
385
+ els.issueSummary.appendChild(el('p', 'issue-description', issue.description || 'Sem descrição.'));
386
+ }
387
+
388
+ function metaRow(grid, label, value, className) {
389
+ grid.appendChild(el('dt', null, label));
390
+ const dd = el('dd', className, value);
391
+ grid.appendChild(dd);
392
+ return dd;
393
+ }
394
+
395
+ // snapshot.repository é coletado de forma tolerante a falhas (sem remote,
396
+ // sem commits, git ausente): cada campo pode ser null independentemente dos
397
+ // demais, nunca o objeto inteiro.
398
+ function renderRepository(snapshot) {
399
+ clear(els.repository);
400
+ const repo = snapshot.repository || {};
401
+ const grid = el('dl', 'now-grid');
402
+ metaRow(grid, 'Repositório', repo.name || '—');
403
+ metaRow(grid, 'Branch', repo.branch || '—', 'mono');
404
+ metaRow(grid, 'Commit', repo.headCommit || '—', 'mono');
405
+ const rootDd = metaRow(grid, 'Diretório', repo.root || '—', 'mono');
406
+ if (repo.root) rootDd.title = repo.root;
407
+ els.repository.appendChild(grid);
408
+ }
409
+
344
410
  function renderProgress(snapshot) {
345
411
  const progress = snapshot.progress;
346
412
  els.progressBar.value = progress.percent;
@@ -452,6 +518,20 @@
452
518
  title.appendChild(el('span', 'story-id', story.id));
453
519
  title.appendChild(document.createTextNode(story.title));
454
520
  main.appendChild(title);
521
+
522
+ // status/dependencies vêm com default no schema (backlog/[]), mas
523
+ // session.json gravado antes de #29 pode chegar sem eles.
524
+ const storyStatus = story.status !== null && story.status !== undefined ? story.status : 'backlog';
525
+ const meta = el('div', 'story-meta');
526
+ meta.appendChild(
527
+ el('span', 'badge story-status-' + storyStatus, STORY_STATUS_LABELS[storyStatus] || storyStatus),
528
+ );
529
+ const dependencies = story.dependencies || [];
530
+ if (dependencies.length > 0) {
531
+ meta.appendChild(el('span', 'muted story-deps', 'depende de: ' + dependencies.join(', ')));
532
+ }
533
+ main.appendChild(meta);
534
+
455
535
  item.appendChild(main);
456
536
  const duration = metric(story.durationSeconds);
457
537
  const side = itemSideText([
@@ -41,6 +41,17 @@
41
41
  <div id="alerts-body"></div>
42
42
  </section>
43
43
 
44
+ <div class="columns">
45
+ <section class="card">
46
+ <h2>Resumo da issue</h2>
47
+ <div id="issue-summary"></div>
48
+ </section>
49
+ <section class="card">
50
+ <h2>Repositório</h2>
51
+ <div id="repository"></div>
52
+ </section>
53
+ </div>
54
+
44
55
  <section class="card" aria-live="polite">
45
56
  <h2>Progresso</h2>
46
57
  <div class="progress-row">