vibe-squire 2.2.0 → 2.3.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.
@@ -1,7 +1,9 @@
1
+ import { PrismaService } from '../prisma/prisma.service';
1
2
  import { PollRunHistoryService } from '../sync/poll-run-history.service';
2
3
  export declare class ActivityApiController {
3
4
  private readonly pollRunHistory;
4
- constructor(pollRunHistory: PollRunHistoryService);
5
+ private readonly prisma;
6
+ constructor(pollRunHistory: PollRunHistoryService, prisma: PrismaService);
5
7
  runs(limitRaw?: string): Promise<{
6
8
  runs: {
7
9
  id: string;
@@ -23,17 +25,7 @@ export declare class ActivityApiController {
23
25
  skippedTriage: number | null;
24
26
  skippedDeclined: number | null;
25
27
  itemCount: number;
26
- items: Array<{
27
- prUrl: string;
28
- githubRepo: string;
29
- prNumber: number;
30
- prTitle: string;
31
- authorLogin: string | null;
32
- decision: string;
33
- decisionLabel: string;
34
- detail: string | null;
35
- kanbanIssueId: string | null;
36
- }>;
28
+ items: import("./ui-presenter").ActivityItem[];
37
29
  }[];
38
30
  }>;
39
31
  }
@@ -15,14 +15,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.ActivityApiController = void 0;
16
16
  const common_1 = require("@nestjs/common");
17
17
  const swagger_1 = require("@nestjs/swagger");
18
+ const prisma_service_1 = require("../prisma/prisma.service");
18
19
  const poll_run_history_service_1 = require("../sync/poll-run-history.service");
20
+ const triage_live_state_queries_1 = require("../sync/triage-live-state.queries");
19
21
  const ui_presenter_1 = require("./ui-presenter");
20
22
  const DEFAULT_LIMIT = 40;
21
23
  const MAX_LIMIT = 100;
22
24
  let ActivityApiController = class ActivityApiController {
23
25
  pollRunHistory;
24
- constructor(pollRunHistory) {
26
+ prisma;
27
+ constructor(pollRunHistory, prisma) {
25
28
  this.pollRunHistory = pollRunHistory;
29
+ this.prisma = prisma;
26
30
  }
27
31
  async runs(limitRaw) {
28
32
  let limit = DEFAULT_LIMIT;
@@ -33,7 +37,11 @@ let ActivityApiController = class ActivityApiController {
33
37
  }
34
38
  }
35
39
  const rows = await this.pollRunHistory.listRecentForUi(limit);
36
- return { runs: (0, ui_presenter_1.presentActivityRunsForView)(rows) };
40
+ const allPrUrls = new Set(rows.flatMap((r) => r.items.map((i) => i.prUrl)));
41
+ const live = await (0, triage_live_state_queries_1.fetchTriageLiveState)(this.prisma, allPrUrls);
42
+ return {
43
+ runs: (0, ui_presenter_1.presentActivityRunsForView)(rows, live),
44
+ };
37
45
  }
38
46
  };
39
47
  exports.ActivityApiController = ActivityApiController;
@@ -53,6 +61,7 @@ __decorate([
53
61
  exports.ActivityApiController = ActivityApiController = __decorate([
54
62
  (0, swagger_1.ApiTags)('activity'),
55
63
  (0, common_1.Controller)('api/activity'),
56
- __metadata("design:paramtypes", [poll_run_history_service_1.PollRunHistoryService])
64
+ __metadata("design:paramtypes", [poll_run_history_service_1.PollRunHistoryService,
65
+ prisma_service_1.PrismaService])
57
66
  ], ActivityApiController);
58
67
  //# sourceMappingURL=activity-api.controller.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"activity-api.controller.js","sourceRoot":"","sources":["../../src/ui/activity-api.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwD;AACxD,6CAAuE;AACvE,+EAAyE;AACzE,iDAA4D;AAE5D,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,GAAG,CAAC;AAIf,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IACH;IAA7B,YAA6B,cAAqC;QAArC,mBAAc,GAAd,cAAc,CAAuB;IAAG,CAAC;IAUhE,AAAN,KAAK,CAAC,IAAI,CAAiB,QAAiB;QAC1C,IAAI,KAAK,GAAG,aAAa,CAAC;QAC1B,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;YAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,IAAA,yCAA0B,EAAC,IAAI,CAAC,EAAE,CAAC;IACpD,CAAC;CACF,CAAA;AAtBY,sDAAqB;AAW1B;IARL,IAAA,YAAG,EAAC,MAAM,CAAC;IACX,IAAA,sBAAY,EAAC;QACZ,OAAO,EAAE,qDAAqD;KAC/D,CAAC;IACD,IAAA,uBAAa,EAAC;QACb,WAAW,EACT,6EAA6E;KAChF,CAAC;IACU,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;;;;iDAUzB;gCArBU,qBAAqB;IAFjC,IAAA,iBAAO,EAAC,UAAU,CAAC;IACnB,IAAA,mBAAU,EAAC,cAAc,CAAC;qCAEoB,gDAAqB;GADvD,qBAAqB,CAsBjC"}
1
+ {"version":3,"file":"activity-api.controller.js","sourceRoot":"","sources":["../../src/ui/activity-api.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAwD;AACxD,6CAAuE;AACvE,6DAAyD;AACzD,+EAAyE;AACzE,iFAAyE;AACzE,iDAA4D;AAE5D,MAAM,aAAa,GAAG,EAAE,CAAC;AACzB,MAAM,SAAS,GAAG,GAAG,CAAC;AAIf,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAEb;IACA;IAFnB,YACmB,cAAqC,EACrC,MAAqB;QADrB,mBAAc,GAAd,cAAc,CAAuB;QACrC,WAAM,GAAN,MAAM,CAAe;IACrC,CAAC;IAUE,AAAN,KAAK,CAAC,IAAI,CAAiB,QAAiB;QAC1C,IAAI,KAAK,GAAG,aAAa,CAAC;QAC1B,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;YAC9C,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACxC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAC9D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,MAAM,IAAA,gDAAoB,EAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAEhE,OAAO;YACL,IAAI,EAAE,IAAA,yCAA0B,EAAC,IAAI,EAAE,IAAI,CAAC;SAC7C,CAAC;IACJ,CAAC;CACF,CAAA;AA9BY,sDAAqB;AAc1B;IARL,IAAA,YAAG,EAAC,MAAM,CAAC;IACX,IAAA,sBAAY,EAAC;QACZ,OAAO,EAAE,qDAAqD;KAC/D,CAAC;IACD,IAAA,uBAAa,EAAC;QACb,WAAW,EACT,6EAA6E;KAChF,CAAC;IACU,WAAA,IAAA,cAAK,EAAC,OAAO,CAAC,CAAA;;;;iDAezB;gCA7BU,qBAAqB;IAFjC,IAAA,iBAAO,EAAC,UAAU,CAAC;IACnB,IAAA,mBAAU,EAAC,cAAc,CAAC;qCAGU,gDAAqB;QAC7B,8BAAa;GAH7B,qBAAqB,CA8BjC"}
@@ -18,13 +18,79 @@
18
18
  skipped_board_limit: true,
19
19
  };
20
20
 
21
+ var OPTIMISTIC_KEY = 'vs_triage_optimistic';
22
+
23
+ function loadOptimistic() {
24
+ try {
25
+ return JSON.parse(localStorage.getItem(OPTIMISTIC_KEY) || '{}');
26
+ } catch {
27
+ return {};
28
+ }
29
+ }
30
+
31
+ function saveOptimistic(map) {
32
+ try {
33
+ localStorage.setItem(OPTIMISTIC_KEY, JSON.stringify(map));
34
+ } catch {
35
+ /* quota exceeded — ignore */
36
+ }
37
+ }
38
+
39
+ function markOptimistic(prUrl, action) {
40
+ var map = loadOptimistic();
41
+ map[prUrl] = action;
42
+ saveOptimistic(map);
43
+ }
44
+
45
+ function clearOptimistic(prUrl) {
46
+ var map = loadOptimistic();
47
+ delete map[prUrl];
48
+ saveOptimistic(map);
49
+ }
50
+
51
+ function applyOptimistic(items) {
52
+ var map = loadOptimistic();
53
+ var dirty = false;
54
+ for (var i = 0; i < items.length; i++) {
55
+ var it = items[i];
56
+ var opt = map[it.prUrl];
57
+ if (!opt) continue;
58
+ var eff = it.effectiveDecision || it.decision;
59
+ if (opt === 'accept' && !isTriageable(eff)) {
60
+ delete map[it.prUrl];
61
+ dirty = true;
62
+ } else if (opt === 'decline' && eff === 'skipped_declined') {
63
+ delete map[it.prUrl];
64
+ dirty = true;
65
+ } else if (opt === 'reconsider' && isTriageable(eff)) {
66
+ delete map[it.prUrl];
67
+ dirty = true;
68
+ } else if (opt === 'accept') {
69
+ it.effectiveDecision = 'linked_existing';
70
+ it.decisionLabel = 'Accepted (pending refresh)';
71
+ } else if (opt === 'decline') {
72
+ it.effectiveDecision = 'skipped_declined';
73
+ it.decisionLabel = 'Declined (pending refresh)';
74
+ } else if (opt === 'reconsider') {
75
+ it.effectiveDecision = 'skipped_triage';
76
+ it.decisionLabel = 'Pending triage';
77
+ }
78
+ }
79
+ if (dirty) saveOptimistic(map);
80
+ }
81
+
21
82
  function isTriageable(decision) {
22
83
  return TRIAGEABLE_DECISIONS[decision] === true;
23
84
  }
24
85
 
86
+ function effectiveOf(it) {
87
+ return it.effectiveDecision || it.decision;
88
+ }
89
+
25
90
  function triageSortKey(it) {
26
- if (isTriageable(it.decision)) return 0;
27
- if (it.decision === 'skipped_declined') return 1;
91
+ var eff = effectiveOf(it);
92
+ if (isTriageable(eff)) return 0;
93
+ if (eff === 'skipped_declined') return 1;
28
94
  return 2;
29
95
  }
30
96
 
@@ -39,7 +105,8 @@
39
105
 
40
106
  function triageActionButtons(it) {
41
107
  var url = esc(it.prUrl);
42
- if (isTriageable(it.decision)) {
108
+ var eff = effectiveOf(it);
109
+ if (isTriageable(eff)) {
43
110
  return (
44
111
  '<div class="triage-actions" style="margin-top:0.3rem">' +
45
112
  '<button class="btn btn-sm primary js-triage-accept" data-pr-url="' +
@@ -51,7 +118,7 @@
51
118
  '</div>'
52
119
  );
53
120
  }
54
- if (it.decision === 'skipped_declined') {
121
+ if (eff === 'skipped_declined') {
55
122
  return (
56
123
  '<div class="triage-actions" style="margin-top:0.3rem">' +
57
124
  '<button class="btn btn-sm ghost js-triage-reconsider" data-pr-url="' +
@@ -65,7 +132,11 @@
65
132
 
66
133
  function renderItemsTable(items) {
67
134
  if (!items || !items.length) return '';
135
+ applyOptimistic(items);
68
136
  var sorted = sortItemsForTriage(items);
137
+ var hasTriageable = sorted.some(function (it) {
138
+ return isTriageable(effectiveOf(it));
139
+ });
69
140
  var rows = sorted
70
141
  .map(function (it) {
71
142
  var detailParts = [];
@@ -86,9 +157,10 @@
86
157
  '<div class="muted" style="font-size:0.8rem">@' +
87
158
  esc(it.authorLogin) +
88
159
  '</div>';
89
- var rowClass = isTriageable(it.decision)
160
+ var eff = effectiveOf(it);
161
+ var rowClass = isTriageable(eff)
90
162
  ? ' class="triage-pending-row"'
91
- : it.decision === 'skipped_declined'
163
+ : eff === 'skipped_declined'
92
164
  ? ' class="triage-declined-row"'
93
165
  : '';
94
166
  return (
@@ -121,10 +193,16 @@
121
193
  })
122
194
  .join('');
123
195
  return (
124
- '<details class="activity-details">' +
196
+ '<details class="activity-details"' +
197
+ (hasTriageable ? ' open' : '') +
198
+ '>' +
125
199
  '<summary class="activity-details-summary">PR details (' +
126
200
  items.length +
127
- ')</summary>' +
201
+ ')' +
202
+ (hasTriageable
203
+ ? ' · <span class="triage-attention-hint">needs attention</span>'
204
+ : '') +
205
+ '</summary>' +
128
206
  '<div class="table-wrap activity-items-wrap">' +
129
207
  '<table class="data-table activity-items-table">' +
130
208
  '<thead><tr><th>PR</th><th>Repo</th><th>Outcome</th><th>Detail</th></tr></thead>' +
@@ -209,6 +287,37 @@
209
287
  );
210
288
  }
211
289
 
290
+ function countUniqueTriageable(runs) {
291
+ var seen = {};
292
+ var count = 0;
293
+ for (var r = 0; r < runs.length; r++) {
294
+ var items = runs[r].items || [];
295
+ for (var i = 0; i < items.length; i++) {
296
+ var eff = items[i].effectiveDecision || items[i].decision;
297
+ if (isTriageable(eff) && !seen[items[i].prUrl]) {
298
+ seen[items[i].prUrl] = true;
299
+ count++;
300
+ }
301
+ }
302
+ }
303
+ return count;
304
+ }
305
+
306
+ function renderTriageBanner(runs) {
307
+ applyOptimistic((runs[0] && runs[0].items) || []);
308
+ var count = countUniqueTriageable(runs);
309
+ if (count === 0) return '';
310
+ return (
311
+ '<div class="banner banner-triage-attention">' +
312
+ '<strong>' +
313
+ count +
314
+ ' PR' +
315
+ (count === 1 ? '' : 's') +
316
+ '</strong> awaiting your review or decline decision.' +
317
+ '</div>'
318
+ );
319
+ }
320
+
212
321
  function renderRuns(runs) {
213
322
  if (!runs || !runs.length) {
214
323
  return (
@@ -217,7 +326,7 @@
217
326
  '</div>'
218
327
  );
219
328
  }
220
- return runs.map(renderRun).join('');
329
+ return renderTriageBanner(runs) + runs.map(renderRun).join('');
221
330
  }
222
331
 
223
332
  var pollTimer = null;
@@ -283,6 +392,8 @@
283
392
 
284
393
  function triageAction(endpoint, prUrl, btn) {
285
394
  btn.disabled = true;
395
+ markOptimistic(prUrl, endpoint);
396
+ void load();
286
397
  fetch('/api/pr/' + endpoint, {
287
398
  method: 'POST',
288
399
  headers: { 'Content-Type': 'application/json' },
@@ -293,7 +404,8 @@
293
404
  void load();
294
405
  })
295
406
  .catch(function () {
296
- btn.disabled = false;
407
+ clearOptimistic(prUrl);
408
+ void load();
297
409
  });
298
410
  }
299
411
 
@@ -4,6 +4,7 @@
4
4
  var SSE_EVENT =
5
5
  VS.STATUS_SNAPSHOT_EVENT || g.__VS_SSE_EVENT__ || 'vibesquire:status-snapshot';
6
6
  var stateEl = document.getElementById('nav-sse-state');
7
+ var badgeEl = document.getElementById('nav-triage-badge');
7
8
 
8
9
  function setSse(s) {
9
10
  if (!stateEl) return;
@@ -11,6 +12,48 @@
11
12
  stateEl.className = 'sse sse-' + s;
12
13
  }
13
14
 
15
+ /* ── Nav badge ── */
16
+
17
+ function updateTriageBadge(count) {
18
+ if (!badgeEl) return;
19
+ if (count > 0) {
20
+ badgeEl.textContent = String(count);
21
+ badgeEl.hidden = false;
22
+ } else {
23
+ badgeEl.textContent = '';
24
+ badgeEl.hidden = true;
25
+ }
26
+ }
27
+
28
+ /* ── Web Notifications ── */
29
+
30
+ var lastNotifiedTriageKey = '';
31
+
32
+ function requestNotificationPermission() {
33
+ if (!('Notification' in g)) return;
34
+ if (Notification.permission === 'default') {
35
+ Notification.requestPermission();
36
+ }
37
+ }
38
+
39
+ function maybeNotifyTriage(count) {
40
+ if (!('Notification' in g) || Notification.permission !== 'granted') return;
41
+ if (count <= 0) {
42
+ lastNotifiedTriageKey = '';
43
+ return;
44
+ }
45
+ var key = String(count);
46
+ if (key === lastNotifiedTriageKey) return;
47
+ lastNotifiedTriageKey = key;
48
+ new Notification('vibe-squire: PRs need triage', {
49
+ body: count + ' PR(s) awaiting your review or decline decision',
50
+ icon: '/ui/assets/favicon.svg',
51
+ tag: 'vs-triage',
52
+ });
53
+ }
54
+
55
+ /* ── Snapshot dispatch ── */
56
+
14
57
  function publishSnapshot(snap) {
15
58
  if (!snap || typeof snap !== 'object') return;
16
59
  try {
@@ -18,9 +61,17 @@
18
61
  } catch {
19
62
  /* ignore */
20
63
  }
64
+ var triageCount =
65
+ typeof snap.pending_triage_count === 'number'
66
+ ? snap.pending_triage_count
67
+ : 0;
68
+ updateTriageBadge(triageCount);
69
+ maybeNotifyTriage(triageCount);
21
70
  g.dispatchEvent(new CustomEvent(SSE_EVENT, { detail: snap }));
22
71
  }
23
72
 
73
+ /* ── SSE connection ── */
74
+
24
75
  var es = new EventSource('/api/status/stream');
25
76
  setSse('connecting');
26
77
  es.onopen = function () {
@@ -40,4 +91,6 @@
40
91
  /* ignore */
41
92
  }
42
93
  };
94
+
95
+ requestNotificationPermission();
43
96
  })();
@@ -145,6 +145,23 @@ code {
145
145
  color: var(--accent);
146
146
  }
147
147
 
148
+ .nav-badge {
149
+ display: inline-flex;
150
+ align-items: center;
151
+ justify-content: center;
152
+ min-width: 1.25rem;
153
+ height: 1.25rem;
154
+ padding: 0 0.35rem;
155
+ border-radius: 999px;
156
+ background: var(--warn);
157
+ color: var(--bg);
158
+ font-size: 0.7rem;
159
+ font-weight: 700;
160
+ font-family: var(--mono);
161
+ margin-left: 0.4rem;
162
+ vertical-align: middle;
163
+ }
164
+
148
165
  .nav-foot {
149
166
  margin-top: auto;
150
167
  font-size: 0.72rem;
@@ -707,7 +724,8 @@ textarea.input {
707
724
 
708
725
  /* Triage rows */
709
726
  .triage-pending-row {
710
- background: rgba(61, 159, 122, 0.06);
727
+ background: rgba(201, 162, 39, 0.09);
728
+ border-left: 3px solid var(--warn);
711
729
  }
712
730
 
713
731
  .triage-declined-row {
@@ -719,3 +737,21 @@ textarea.input {
719
737
  gap: 0.35rem;
720
738
  flex-wrap: wrap;
721
739
  }
740
+
741
+ .triage-attention-hint {
742
+ color: var(--warn);
743
+ font-weight: 600;
744
+ font-size: 0.82rem;
745
+ }
746
+
747
+ /* Triage attention banner */
748
+ .banner-triage-attention {
749
+ background: rgba(201, 162, 39, 0.12);
750
+ border: 1px solid rgba(201, 162, 39, 0.3);
751
+ border-left: 3px solid var(--warn);
752
+ color: var(--text-strong);
753
+ padding: 0.65rem 1rem;
754
+ border-radius: 6px;
755
+ font-size: 0.9rem;
756
+ margin-bottom: 1rem;
757
+ }
@@ -1,8 +1,22 @@
1
1
  import type { SetupEvaluation } from '../setup/setup-evaluation.service';
2
2
  import type { PollRunHistoryService } from '../sync/poll-run-history.service';
3
3
  import type { UiNavEntry } from '../ports/ui-nav.types';
4
+ import type { TriageLiveState } from '../sync/triage-live-state.queries';
5
+ export type { TriageLiveState } from '../sync/triage-live-state.queries';
4
6
  export type PollRunRowForActivity = Awaited<ReturnType<PollRunHistoryService['listRecentForUi']>>[number];
5
- export declare function presentActivityRunsForView(rows: PollRunRowForActivity[]): Array<{
7
+ export type ActivityItem = {
8
+ prUrl: string;
9
+ githubRepo: string;
10
+ prNumber: number;
11
+ prTitle: string;
12
+ authorLogin: string | null;
13
+ decision: string;
14
+ effectiveDecision: string;
15
+ decisionLabel: string;
16
+ detail: string | null;
17
+ kanbanIssueId: string | null;
18
+ };
19
+ export declare function presentActivityRunsForView(rows: PollRunRowForActivity[], live?: TriageLiveState): Array<{
6
20
  id: string;
7
21
  startedAt: string;
8
22
  startedAtLabel: string;
@@ -22,17 +36,7 @@ export declare function presentActivityRunsForView(rows: PollRunRowForActivity[]
22
36
  skippedTriage: number | null;
23
37
  skippedDeclined: number | null;
24
38
  itemCount: number;
25
- items: Array<{
26
- prUrl: string;
27
- githubRepo: string;
28
- prNumber: number;
29
- prTitle: string;
30
- authorLogin: string | null;
31
- decision: string;
32
- decisionLabel: string;
33
- detail: string | null;
34
- kanbanIssueId: string | null;
35
- }>;
39
+ items: ActivityItem[];
36
40
  }>;
37
41
  export declare function escapeForPre(s: string): string;
38
42
  export declare function destinationTypeLabel(t: string): string;
@@ -11,6 +11,7 @@ exports.uiNavLocals = uiNavLocals;
11
11
  exports.githubNotSourceRedirectUrl = githubNotSourceRedirectUrl;
12
12
  exports.vibeKanbanNotDestinationRedirectUrl = vibeKanbanNotDestinationRedirectUrl;
13
13
  const poll_run_labels_1 = require("../sync/poll-run-labels");
14
+ const poll_run_decisions_1 = require("../sync/poll-run-decisions");
14
15
  function formatActivityRunTime(d) {
15
16
  const t = d.getTime();
16
17
  if (Number.isNaN(t)) {
@@ -18,7 +19,24 @@ function formatActivityRunTime(d) {
18
19
  }
19
20
  return d.toLocaleString();
20
21
  }
21
- function presentActivityRunsForView(rows) {
22
+ const TRIAGE_DECISIONS = new Set([
23
+ poll_run_decisions_1.POLL_RUN_ITEM_DECISION.skippedTriage,
24
+ poll_run_decisions_1.POLL_RUN_ITEM_DECISION.skippedBoardLimit,
25
+ ]);
26
+ const EMPTY_LIVE_STATE = {
27
+ acceptedPrUrls: new Set(),
28
+ declinedPrUrls: new Set(),
29
+ };
30
+ function resolveEffectiveDecision(decision, prUrl, live) {
31
+ if (!TRIAGE_DECISIONS.has(decision))
32
+ return decision;
33
+ if (live.acceptedPrUrls.has(prUrl))
34
+ return poll_run_decisions_1.POLL_RUN_ITEM_DECISION.linkedExisting;
35
+ if (live.declinedPrUrls.has(prUrl))
36
+ return poll_run_decisions_1.POLL_RUN_ITEM_DECISION.skippedDeclined;
37
+ return decision;
38
+ }
39
+ function presentActivityRunsForView(rows, live = EMPTY_LIVE_STATE) {
22
40
  return rows.map((r) => ({
23
41
  id: r.id,
24
42
  startedAt: r.startedAt.toISOString(),
@@ -39,17 +57,21 @@ function presentActivityRunsForView(rows) {
39
57
  skippedTriage: r.skippedTriage,
40
58
  skippedDeclined: r.skippedDeclined,
41
59
  itemCount: r.items.length,
42
- items: r.items.map((i) => ({
43
- prUrl: i.prUrl,
44
- githubRepo: i.githubRepo,
45
- prNumber: i.prNumber,
46
- prTitle: i.prTitle,
47
- authorLogin: i.authorLogin,
48
- decision: i.decision,
49
- decisionLabel: (0, poll_run_labels_1.pollDecisionLabel)(i.decision),
50
- detail: i.detail,
51
- kanbanIssueId: i.kanbanIssueId,
52
- })),
60
+ items: r.items.map((i) => {
61
+ const eff = resolveEffectiveDecision(i.decision, i.prUrl, live);
62
+ return {
63
+ prUrl: i.prUrl,
64
+ githubRepo: i.githubRepo,
65
+ prNumber: i.prNumber,
66
+ prTitle: i.prTitle,
67
+ authorLogin: i.authorLogin,
68
+ decision: i.decision,
69
+ effectiveDecision: eff,
70
+ decisionLabel: (0, poll_run_labels_1.pollDecisionLabel)(eff),
71
+ detail: i.detail,
72
+ kanbanIssueId: i.kanbanIssueId,
73
+ };
74
+ }),
53
75
  }));
54
76
  }
55
77
  function escapeForPre(s) {
@@ -1 +1 @@
1
- {"version":3,"file":"ui-presenter.js","sourceRoot":"","sources":["../../src/ui/ui-presenter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui-presenter.js","sourceRoot":"","sources":["../../src/ui/ui-presenter.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@
16
16
  <a
17
17
  href="/ui/activity"
18
18
  class="nav-link {{#if (eq active 'activity')}}active{{/if}}"
19
- >Activity</a>
19
+ >Activity<span id="nav-triage-badge" class="nav-badge" hidden></span></a>
20
20
  {{/unless}}
21
21
 
22
22
  <div class="nav-settings-group">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibe-squire",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Local orchestrator: GitHub PR review queue → Vibe Kanban via MCP",
5
5
  "author": "alexpialetski",
6
6
  "license": "MIT",