@oss-autopilot/core 1.6.1 → 1.6.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.
@@ -139,6 +139,31 @@ export function openInBrowser(url) {
139
139
  }
140
140
  });
141
141
  }
142
+ /**
143
+ * Trigger a data refresh on a running dashboard server.
144
+ * Hits POST /api/refresh so the SPA picks up fresh data on its next poll.
145
+ * Non-fatal: errors are logged but don't propagate (#830).
146
+ */
147
+ async function triggerDashboardRefresh(port) {
148
+ try {
149
+ const res = await fetch(`http://127.0.0.1:${port}/api/refresh`, {
150
+ method: 'POST',
151
+ headers: { Origin: `http://oss.localhost:${port}` },
152
+ signal: AbortSignal.timeout(5000),
153
+ });
154
+ if (!res.ok) {
155
+ const body = await res.text().catch(() => '');
156
+ console.error(`[STARTUP] Dashboard refresh returned ${res.status}: ${body}`);
157
+ return false;
158
+ }
159
+ await res.text().catch(() => { });
160
+ return true;
161
+ }
162
+ catch (error) {
163
+ console.error(`[STARTUP] Could not trigger dashboard refresh: ${errorMessage(error)}`);
164
+ return false;
165
+ }
166
+ }
142
167
  /**
143
168
  * Run startup checks and return structured output.
144
169
  * Returns StartupOutput with one of three shapes:
@@ -184,14 +209,20 @@ export async function runStartup() {
184
209
  // 4. Launch interactive SPA dashboard
185
210
  // Skip opening on first run (0 PRs) — the welcome flow handles onboarding
186
211
  let dashboardUrl;
187
- let dashboardOpened = false;
212
+ let dashboardStatus;
188
213
  if (daily.digest.summary.totalActivePRs > 0) {
189
214
  try {
190
215
  const spaResult = await launchDashboardServer();
191
216
  if (spaResult) {
192
217
  dashboardUrl = spaResult.url;
193
- openInBrowser(spaResult.url);
194
- dashboardOpened = true;
218
+ if (spaResult.alreadyRunning) {
219
+ const refreshed = await triggerDashboardRefresh(spaResult.port);
220
+ dashboardStatus = refreshed ? 'refreshed' : 'running';
221
+ }
222
+ else {
223
+ openInBrowser(spaResult.url);
224
+ dashboardStatus = 'opened';
225
+ }
195
226
  }
196
227
  else {
197
228
  console.error('[STARTUP] Dashboard SPA assets not found. Build with: cd packages/dashboard && pnpm run build');
@@ -201,10 +232,16 @@ export async function runStartup() {
201
232
  console.error('[STARTUP] SPA dashboard launch failed:', errorMessage(error));
202
233
  }
203
234
  }
204
- // Append dashboard status to brief summary (only startup opens the browser, not daily)
205
- if (dashboardOpened) {
235
+ // Append dashboard status to brief summary
236
+ if (dashboardStatus === 'opened') {
206
237
  daily.briefSummary += ' | Dashboard opened in browser';
207
238
  }
239
+ else if (dashboardStatus === 'refreshed') {
240
+ daily.briefSummary += ' | Dashboard refreshed';
241
+ }
242
+ else if (dashboardStatus === 'running') {
243
+ daily.briefSummary += ' | Dashboard running';
244
+ }
208
245
  // 5. Detect issue list
209
246
  const issueList = detectIssueList();
210
247
  return {
@@ -47,6 +47,12 @@ export declare function isAllSelfReplies(reviewId: number, reviewComments: Revie
47
47
  * synthetic placeholders (#199).
48
48
  */
49
49
  export declare function getInlineCommentBody(reviewId: number, reviewComments: ReviewComment[]): string | undefined;
50
+ /**
51
+ * Check whether a review has any associated inline comments.
52
+ * Used to prevent the acknowledgment filter from discarding reviews
53
+ * that also posted inline comments (#829).
54
+ */
55
+ export declare function reviewHasInlineComments(reviewId: number, reviewComments: ReviewComment[]): boolean;
50
56
  /**
51
57
  * Check if there are unresponded comments from maintainers.
52
58
  * Combines issue comments and review comments into a timeline,
@@ -89,6 +89,14 @@ export function isAllSelfReplies(reviewId, reviewComments) {
89
89
  export function getInlineCommentBody(reviewId, reviewComments) {
90
90
  return reviewComments.find((c) => c.pull_request_review_id === reviewId && c.body?.trim())?.body?.trim();
91
91
  }
92
+ /**
93
+ * Check whether a review has any associated inline comments.
94
+ * Used to prevent the acknowledgment filter from discarding reviews
95
+ * that also posted inline comments (#829).
96
+ */
97
+ export function reviewHasInlineComments(reviewId, reviewComments) {
98
+ return reviewComments.some((c) => c.pull_request_review_id === reviewId);
99
+ }
92
100
  /**
93
101
  * Check if there are unresponded comments from maintainers.
94
102
  * Combines issue comments and review comments into a timeline,
@@ -136,6 +144,7 @@ export function checkUnrespondedComments(comments, reviews, reviewComments, user
136
144
  body: resolvedBody,
137
145
  createdAt: review.submitted_at,
138
146
  isUser: author.toLowerCase() === usernameLower,
147
+ reviewId: review.id,
139
148
  });
140
149
  }
141
150
  // Sort by date
@@ -149,6 +158,7 @@ export function checkUnrespondedComments(comments, reviews, reviewComments, user
149
158
  }
150
159
  // Find maintainer comments after the user's last comment
151
160
  let lastMaintainerComment;
161
+ let lastMaintainerReviewId;
152
162
  for (const item of timeline) {
153
163
  if (item.isUser)
154
164
  continue; // Skip user's own comments
@@ -163,10 +173,14 @@ export function checkUnrespondedComments(comments, reviews, reviewComments, user
163
173
  body: item.body.slice(0, 200) + (item.body.length > 200 ? '...' : ''),
164
174
  createdAt: item.createdAt,
165
175
  };
176
+ lastMaintainerReviewId = item.reviewId;
166
177
  }
167
178
  }
168
- // Filter out pure acknowledgment comments that don't require a response
169
- if (lastMaintainerComment && isAcknowledgmentComment(lastMaintainerComment.body)) {
179
+ // Filter out pure acknowledgment comments that don't require a response.
180
+ // Skip the filter when the review has inline comments — those indicate
181
+ // feedback beyond the summary body that likely needs a response (#829).
182
+ const lastReviewHasInlineComments = lastMaintainerReviewId != null && reviewHasInlineComments(lastMaintainerReviewId, reviewComments);
183
+ if (lastMaintainerComment && isAcknowledgmentComment(lastMaintainerComment.body) && !lastReviewHasInlineComments) {
170
184
  lastMaintainerComment = undefined;
171
185
  }
172
186
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-autopilot/core",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "CLI and core library for managing open source contributions",
5
5
  "type": "module",
6
6
  "bin": {