@bbradar/mcp 0.3.2 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Release notes
2
2
 
3
+ ## 0.3.3 — confirmed program identities (2026-11-07)
4
+
5
+ - `get_program_brief`, `get_program_scope_summary` and `get_program_target_breakdown` keep an identity that the exact detail read confirmed. When only the target list is unavailable, as for a finished contest, they return its 404 with a message pointing to `get_program` instead of retrying a same-handle program on another platform as a stale ID. Stale-ID retries still apply when the detail read also finds nothing.
6
+
3
7
  ## 0.3.2 — new Activity data, contest awards and dependency security (2026-11-07)
4
8
 
5
9
  - `find_programs` and `find_hunt_targets` now report the sort direction the API actually applied in `ranking_scope.sort_direction` and `scan.sort_direction`. With no `sort_direction`, the API ranks `first_response` and `time_to_bounty` fastest first (ascending), and these fields previously said `desc`. When the API does not echo a direction, the same rule applies.
package/dist/server.js CHANGED
@@ -7,7 +7,7 @@ import { NumericCursorStore } from "./cursorStore.js";
7
7
  import { stableStringify, stripUndefined } from "./json.js";
8
8
  import { FixedWindowRateLimiter } from "./rateLimit.js";
9
9
  import { readArray, readBoolean, readNumber, readObject, readString, sanitizeJson, sanitizeProPayload, sanitizeChange, sanitizeProgram, sanitizeRepositoryChange, sanitizeTarget, sanitizeTargetsForExport } from "./sanitize.js";
10
- const SERVER_VERSION = "0.3.2";
10
+ const SERVER_VERSION = "0.3.3";
11
11
  const MAX_PROGRAMS_PER_SEARCH = 100;
12
12
  const MAX_TARGET_EXPORT = 500;
13
13
  const MAX_RECENT_CHANGES = 100;
@@ -2833,7 +2833,7 @@ async function runProgramIdTool(client, config, requestedProgramId, callback, in
2833
2833
  return withProgramIdFallbackMetadata(payload, cachedFallback);
2834
2834
  }
2835
2835
  catch (cachedFallbackError) {
2836
- if (!isProgramNotFoundError(cachedFallbackError) || !indexFallbackCallback) {
2836
+ if (!allowsProgramIdFallback(cachedFallbackError) || !indexFallbackCallback) {
2837
2837
  throw cachedFallbackError;
2838
2838
  }
2839
2839
  const indexFallback = createProgramIndexFallbackFromStaleResolution(cachedFallback, requestedProgramId, cachedFallbackError) ??
@@ -2855,7 +2855,7 @@ async function runProgramIdTool(client, config, requestedProgramId, callback, in
2855
2855
  return withProgramIdFallbackMetadata(payload, fallback);
2856
2856
  }
2857
2857
  catch (fallbackError) {
2858
- if (!isProgramNotFoundError(fallbackError) || !indexFallbackCallback) {
2858
+ if (!allowsProgramIdFallback(fallbackError) || !indexFallbackCallback) {
2859
2859
  throw fallbackError;
2860
2860
  }
2861
2861
  const indexFallback = createProgramIndexFallbackFromStaleResolution(fallback, requestedProgramId, fallbackError) ??
@@ -2883,7 +2883,7 @@ async function runProgramIdTool(client, config, requestedProgramId, callback, in
2883
2883
  return await callback(requestedProgramId);
2884
2884
  }
2885
2885
  catch (error) {
2886
- if (!isProgramNotFoundError(error)) {
2886
+ if (!allowsProgramIdFallback(error)) {
2887
2887
  throw error;
2888
2888
  }
2889
2889
  const fallback = await resolveStaleProgramId(client, config, requestedProgramId, error);
@@ -2905,7 +2905,7 @@ async function runProgramIdTool(client, config, requestedProgramId, callback, in
2905
2905
  return withProgramIdFallbackMetadata(payload, fallback);
2906
2906
  }
2907
2907
  catch (fallbackError) {
2908
- if (!isProgramNotFoundError(fallbackError) || !indexFallbackCallback) {
2908
+ if (!allowsProgramIdFallback(fallbackError) || !indexFallbackCallback) {
2909
2909
  throw fallbackError;
2910
2910
  }
2911
2911
  const indexFallback = createProgramIndexFallbackFromStaleResolution(fallback, requestedProgramId, fallbackError) ??
@@ -5157,7 +5157,20 @@ async function getProgramFromTargetsOnlyFallback(client, programId, programError
5157
5157
  async function fetchProgramDetailsAndTargets(client, config, programId) {
5158
5158
  const [programResult, targetsResult] = await Promise.allSettled([client.getProgram(programId), client.getProgramTargets(programId)]);
5159
5159
  if (targetsResult.status === "rejected") {
5160
- throw targetsResult.reason;
5160
+ const reason = targetsResult.reason;
5161
+ if (programResult.status === "fulfilled" && isProgramNotFoundError(reason)) {
5162
+ // Detail confirmed this exact program; only its target list is unavailable.
5163
+ throw new ConfirmedProgramTargetsError({
5164
+ message: `${programId} exists, but its target list is not available (${reason.message}). A finished contest keeps program detail only: read it with get_program.`,
5165
+ requestId: reason.requestId,
5166
+ upstreamRequestId: reason.upstreamRequestId,
5167
+ status: reason.status,
5168
+ detail: reason.detail,
5169
+ errors: reason.errors,
5170
+ cause: reason
5171
+ });
5172
+ }
5173
+ throw reason;
5161
5174
  }
5162
5175
  const targetsApi = targetsResult.value;
5163
5176
  const targetSourceRequest = {
@@ -8935,6 +8948,16 @@ function addUniqueWarning(warnings, warning) {
8935
8948
  function isProgramNotFoundError(error) {
8936
8949
  return error instanceof BBRadarApiError && error.status === 404;
8937
8950
  }
8951
+ /**
8952
+ * A target read failed for a program whose exact detail read succeeded. Detail confirmed
8953
+ * the identity, so the failure belongs to that program's targets (a finished contest keeps
8954
+ * detail only) and never makes its ID a stale-ID candidate for a same-handle program.
8955
+ */
8956
+ class ConfirmedProgramTargetsError extends BBRadarApiError {
8957
+ }
8958
+ function allowsProgramIdFallback(error) {
8959
+ return isProgramNotFoundError(error) && !(error instanceof ConfirmedProgramTargetsError);
8960
+ }
8938
8961
  function runImmediately(callback) {
8939
8962
  return callback();
8940
8963
  }