@withpica/mcp-sdk 3.5.0 → 3.6.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.
package/dist/index.js CHANGED
@@ -203,6 +203,37 @@ class BaseResource {
203
203
  }
204
204
  return (data.data || data);
205
205
  }
206
+ /**
207
+ * Like `request`, but returns the FULL parsed envelope instead of
208
+ * narrowing to `.data`. Needed by the two spreadsheet-moment auto-twin
209
+ * routes (`POST /admin/works`, `POST /admin/recordings`), whose response
210
+ * carries `twin`/`twin_error` as siblings of `data` — `request()`'s
211
+ * `return data.data || data` would otherwise silently drop them before
212
+ * the MCP tool ever sees a twin was created.
213
+ */
214
+ async requestWithEnvelope(method, path, body) {
215
+ const url = `${this.baseUrl}${path}`;
216
+ const timeoutMs = getTimeoutForPath(path);
217
+ if (this.debug) {
218
+ console.error(`[PICA SDK] ${method} ${url} (timeout: ${timeoutMs}ms)`);
219
+ }
220
+ const response = await this.fetchWithRetry(url, {
221
+ method,
222
+ headers: {
223
+ Authorization: `Bearer ${this.apiKey}`,
224
+ "Content-Type": "application/json",
225
+ ...this.getBypassHeaders(),
226
+ },
227
+ body: body ? JSON.stringify(body) : undefined,
228
+ }, timeoutMs);
229
+ const json = await response.json();
230
+ // Same success:false guard as `request()` — see its comment above.
231
+ if (json && typeof json === "object" && json.success === false) {
232
+ const msg = typeof json.error === "string" ? json.error : "unspecified error";
233
+ throw new ApiError(`API returned success:false: ${msg}`, response.status, false);
234
+ }
235
+ return json;
236
+ }
206
237
  /**
207
238
  * Make a request whose SUCCESS body is raw text, not a JSON envelope —
208
239
  * for routes that stream a generated file (e.g. `text/csv`) rather than
@@ -353,7 +384,19 @@ class WorksResource extends BaseResource {
353
384
  return this.request("GET", `/admin/works/${id}`);
354
385
  }
355
386
  async create(data) {
356
- return this.request("POST", "/admin/works", data);
387
+ // Spreadsheet-moment auto-twin — the route response carries `twin` /
388
+ // `twin_error` as siblings of `data`, which the plain `request()`
389
+ // helper would drop (it narrows to `.data`). Fetch the full envelope
390
+ // and merge the twin fields onto the returned Work so callers (and the
391
+ // MCP tool executor) can see them.
392
+ const envelope = await this.requestWithEnvelope("POST", "/admin/works", data);
393
+ return {
394
+ ...envelope.data,
395
+ twin: envelope.twin ?? null,
396
+ ...(envelope.twin_error !== undefined && {
397
+ twin_error: envelope.twin_error,
398
+ }),
399
+ };
357
400
  }
358
401
  async update(id, updates) {
359
402
  return this.request("PATCH", `/admin/works/${id}`, updates);
@@ -704,6 +747,37 @@ class PicaScoreResource extends BaseResource {
704
747
  return this.request("GET", "/admin/pica-score");
705
748
  }
706
749
  }
750
+ class IntegrityResource extends BaseResource {
751
+ /**
752
+ * GET /admin/integrity/assess?entity_type=&entity_id= -> single-entity assessment.
753
+ * NOTE: for entity_type "release" this is a documented v1 no-op — no
754
+ * release-grain gap code exists yet, so `gaps` is always empty by design
755
+ * (see assessEntity's release branch in lib/services/integrity-floor.ts).
756
+ */
757
+ async assessEntity(entityType, entityId) {
758
+ const qp = new URLSearchParams({
759
+ entity_type: entityType,
760
+ entity_id: entityId,
761
+ });
762
+ return this.request("GET", `/admin/integrity/assess?${qp.toString()}`);
763
+ }
764
+ /** GET /admin/integrity/assess (no params) -> org-grain summary. */
765
+ async assessOrg() {
766
+ return this.request("GET", "/admin/integrity/assess");
767
+ }
768
+ /**
769
+ * POST /admin/integrity/waivers. Duplicate-active-waiver is a 409
770
+ * (`ConflictError` on the app side) — surfaces here as a non-retryable
771
+ * `ApiError` with `status === 409` (see `BaseResource.request`).
772
+ */
773
+ async waive(input) {
774
+ return this.request("POST", "/admin/integrity/waivers", input);
775
+ }
776
+ /** PATCH /admin/integrity/waivers { waiver_id, revoke: true }. No un-revoke path. */
777
+ async revokeWaiver(waiverId) {
778
+ await this.request("PATCH", "/admin/integrity/waivers", { waiver_id: waiverId, revoke: true });
779
+ }
780
+ }
707
781
  class AudioFilesResource extends BaseResource {
708
782
  async list(params) {
709
783
  const queryParams = new URLSearchParams();
@@ -1119,7 +1193,18 @@ class RecordingsResource extends BaseResource {
1119
1193
  return this.request("GET", `/admin/recordings/${id}`);
1120
1194
  }
1121
1195
  async create(data) {
1122
- return this.request("POST", "/admin/recordings", data);
1196
+ // Spreadsheet-moment auto-twin — mirrors WorksResource.create above:
1197
+ // fetch the full envelope so `twin`/`twin_error` survive onto the
1198
+ // returned Recording instead of being dropped by `request()`'s
1199
+ // `.data`-only narrowing.
1200
+ const envelope = await this.requestWithEnvelope("POST", "/admin/recordings", data);
1201
+ return {
1202
+ ...envelope.data,
1203
+ twin: envelope.twin ?? null,
1204
+ ...(envelope.twin_error !== undefined && {
1205
+ twin_error: envelope.twin_error,
1206
+ }),
1207
+ };
1123
1208
  }
1124
1209
  async update(id, updates) {
1125
1210
  return this.request("PATCH", `/admin/recordings/${id}`, updates);
@@ -3623,6 +3708,8 @@ export class PicaClient {
3623
3708
  shareSend;
3624
3709
  accessSimulate;
3625
3710
  approvals;
3711
+ // Registration Integrity Floor (spec 2026-07-09, Task 8).
3712
+ integrity;
3626
3713
  async catalogStats(params) {
3627
3714
  const baseUrl = this.works["baseUrl"];
3628
3715
  const apiKey = this.works["apiKey"];
@@ -3731,6 +3818,7 @@ export class PicaClient {
3731
3818
  this.shareSend = new ShareSendResource(baseUrl, config.apiKey, debug);
3732
3819
  this.accessSimulate = new AccessSimulateResource(baseUrl, config.apiKey, debug);
3733
3820
  this.approvals = new ApprovalsResource(baseUrl, config.apiKey, debug);
3821
+ this.integrity = new IntegrityResource(baseUrl, config.apiKey, debug);
3734
3822
  }
3735
3823
  }
3736
3824
  //# sourceMappingURL=index.js.map