@oss-scout/core 1.2.1 → 1.2.2

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.
@@ -281,6 +281,21 @@ export interface SearchOptions {
281
281
  * `interPhaseDelayMs` for the rationale (#143).
282
282
  */
283
283
  broadPhaseDelayMs?: number;
284
+ /**
285
+ * Exclude issues already surfaced by a recent search so consecutive
286
+ * searches rotate to fresh candidates instead of returning the same set
287
+ * (#249). A result counts as "recently surfaced" when its `lastSeenAt`
288
+ * (recorded by `saveResults`) is within `recentlySurfacedTtlDays`.
289
+ * Defaults to `true`. Pass `false` to force-resurface (e.g. an explicit
290
+ * "search the same pool again" request).
291
+ */
292
+ excludeRecentlySurfaced?: boolean;
293
+ /**
294
+ * TTL in days for the `excludeRecentlySurfaced` rotation window (#249).
295
+ * Results last surfaced more than this many days ago are eligible to
296
+ * resurface. Defaults to 7.
297
+ */
298
+ recentlySurfacedTtlDays?: number;
284
299
  }
285
300
  /** Result of a search operation. */
286
301
  export interface SearchResult {
package/dist/scout.js CHANGED
@@ -170,6 +170,18 @@ export class OssScout {
170
170
  // Auto-cull expired skips before searching
171
171
  this.cullExpiredSkips();
172
172
  const skippedUrls = new Set((this.state.skippedIssues ?? []).map((s) => s.url));
173
+ // Rotation (#249): also exclude issues surfaced by a recent search so
174
+ // consecutive searches return fresh candidates instead of the same set.
175
+ // Folded into the same exclusion set the issue filter already honors.
176
+ if (options?.excludeRecentlySurfaced ?? true) {
177
+ const ttlDays = options?.recentlySurfacedTtlDays ?? 7;
178
+ const cutoff = Date.now() - ttlDays * 24 * 60 * 60 * 1000;
179
+ for (const r of this.state.savedResults ?? []) {
180
+ const seen = Date.parse(r.lastSeenAt);
181
+ if (!Number.isNaN(seen) && seen >= cutoff)
182
+ skippedUrls.add(r.issueUrl);
183
+ }
184
+ }
173
185
  const discovery = new IssueDiscovery(this.githubToken, this.state.preferences, this);
174
186
  // Per-call flags override the persisted personalization defaults (#168).
175
187
  // An empty preference array reads as "no boost" just like an absent flag.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oss-scout/core",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Personalized GitHub issue finder with multi-strategy search, deep vetting, and viability scoring — CLI, library, MCP server, and Claude Code plugin",
5
5
  "type": "module",
6
6
  "bin": {