@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/CHANGELOG.md CHANGED
@@ -11,6 +11,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [3.6.0] - 2026-07-09
15
+
16
+ ### Added
17
+
18
+ - `SocietyAffiliation` gains `affiliation_kind?: "member" | "origin"` and
19
+ `Person` gains `origin_countries?: string[]` (ADR-292), mirroring the same
20
+ fields on the `pica_people_create` / `pica_people_update` write surface.
21
+
22
+ - **`IntegrityResource`** (`client.integrity`) — the SDK surface for the
23
+ registration integrity floor (PR #1595): `assessEntity` (work/recording/
24
+ release grains; release is a documented v1 no-op), `assessOrg`, and the
25
+ `waive` / `revokeWaiver` write pair backing `pica_integrity_waive`.
26
+
27
+ - **`requestWithEnvelope()`** on `BaseResource` — like `request()` but
28
+ returns the FULL parsed `{data, twin?, twin_error?}` envelope instead of
29
+ narrowing to `.data`. `WorksResource.create` / `RecordingsResource.create`
30
+ now use it, so the auto-twin routes' `twin`/`twin_error` sibling fields
31
+ reach callers — `Work`/`Recording` create responses carry `twin` and
32
+ `twin_error` merged onto the returned entity (commit 689298e3c).
33
+
14
34
  ## [3.5.0] - 2026-07-07
15
35
 
16
36
  ### Added
package/dist/index.d.ts CHANGED
@@ -277,6 +277,8 @@ export interface SocietyRegistration {
277
277
  export interface SocietyAffiliation {
278
278
  society_code: string;
279
279
  membership_number: string | null;
280
+ /** ADR-292: `member` (current, default) or `origin` (home-country society for that code). */
281
+ affiliation_kind?: "member" | "origin";
280
282
  }
281
283
  interface Work {
282
284
  id: string;
@@ -314,6 +316,11 @@ interface Work {
314
316
  licensing_notes?: string | null;
315
317
  created_at: string;
316
318
  updated_at: string;
319
+ twin?: {
320
+ id: string;
321
+ recording_title: string;
322
+ } | null;
323
+ twin_error?: string;
317
324
  }
318
325
  interface Person {
319
326
  id: string;
@@ -331,6 +338,8 @@ interface Person {
331
338
  outreach_state?: "ready" | "needs_email" | "needs_disambiguation" | "not_a_target" | "do_not_contact" | "previously_declined";
332
339
  /** Society affiliations (ADR-282: society-agnostic write shape). */
333
340
  society_affiliations?: SocietyAffiliation[];
341
+ /** ADR-292: heritage/origin countries (ISO 3166-1 alpha-2, text[] column on public.people). */
342
+ origin_countries?: string[];
334
343
  created_at: string;
335
344
  updated_at: string;
336
345
  }
@@ -344,6 +353,11 @@ interface Recording {
344
353
  society_registrations?: SocietyRegistration[];
345
354
  created_at: string;
346
355
  updated_at: string;
356
+ twin?: {
357
+ id: string;
358
+ title: string;
359
+ } | null;
360
+ twin_error?: string;
347
361
  }
348
362
  interface ProductionAssetLink {
349
363
  asset_id: string;
@@ -807,6 +821,19 @@ declare class BaseResource {
807
821
  private fetchWithTimeout;
808
822
  private fetchWithRetry;
809
823
  protected request<T>(method: string, path: string, body?: any): Promise<T>;
824
+ /**
825
+ * Like `request`, but returns the FULL parsed envelope instead of
826
+ * narrowing to `.data`. Needed by the two spreadsheet-moment auto-twin
827
+ * routes (`POST /admin/works`, `POST /admin/recordings`), whose response
828
+ * carries `twin`/`twin_error` as siblings of `data` — `request()`'s
829
+ * `return data.data || data` would otherwise silently drop them before
830
+ * the MCP tool ever sees a twin was created.
831
+ */
832
+ protected requestWithEnvelope<T>(method: string, path: string, body?: any): Promise<{
833
+ data: T;
834
+ twin?: unknown;
835
+ twin_error?: string;
836
+ }>;
810
837
  /**
811
838
  * Make a request whose SUCCESS body is raw text, not a JSON envelope —
812
839
  * for routes that stream a generated file (e.g. `text/csv`) rather than
@@ -890,7 +917,9 @@ declare class WorksResource extends BaseResource {
890
917
  has_publisher?: boolean;
891
918
  }): Promise<PaginatedResult<Work>>;
892
919
  get(id: string): Promise<Work>;
893
- create(data: Partial<Work>): Promise<Work>;
920
+ create(data: Partial<Work> & {
921
+ create_twin?: boolean;
922
+ }): Promise<Work>;
894
923
  update(id: string, updates: Partial<Work>): Promise<Work>;
895
924
  delete(id: string): Promise<DeletionResult>;
896
925
  verify(id: string): Promise<Work>;
@@ -1177,6 +1206,79 @@ declare class CreditsBalanceResource extends BaseResource {
1177
1206
  declare class PicaScoreResource extends BaseResource {
1178
1207
  get(): Promise<PicaScore>;
1179
1208
  }
1209
+ /**
1210
+ * Registration Integrity Floor (spec 2026-07-09, Task 8). SDK-local types —
1211
+ * duplicated field-for-field from `lib/services/integrity-floor.ts`'s
1212
+ * exported shapes (the SDK does not import from `lib/`, mcp<->lib
1213
+ * isolation). Keep in sync by hand if the service's exported types change.
1214
+ */
1215
+ export type IntegrityGapCode = "WORK_NO_RECORDING" | "RECORDING_NO_WORK" | "RECORDING_NO_RELEASE" | "WORK_NO_WRITER" | "RECORDING_NO_OWNER" | "COLLABORATOR_NOT_INVITED" | "COLLABORATOR_NOT_ATTESTED";
1216
+ export type IntegrityEntityType = "work" | "recording" | "release" | "person";
1217
+ export interface AttestationProposal {
1218
+ kind: "send_attestation_invites";
1219
+ people: Array<{
1220
+ person_id: string;
1221
+ name: string;
1222
+ has_email: boolean;
1223
+ }>;
1224
+ tool: "pica_collaborators_invite_bulk";
1225
+ note: string;
1226
+ }
1227
+ export interface IntegrityGap {
1228
+ code: IntegrityGapCode;
1229
+ entity: {
1230
+ type: IntegrityEntityType;
1231
+ id: string;
1232
+ label: string;
1233
+ };
1234
+ severity: "critical" | "important";
1235
+ label: string;
1236
+ action_hint: string;
1237
+ proposed_action?: AttestationProposal;
1238
+ waivable: true;
1239
+ }
1240
+ export interface EntityAssessment {
1241
+ entity: {
1242
+ type: IntegrityEntityType;
1243
+ id: string;
1244
+ };
1245
+ gaps: IntegrityGap[];
1246
+ waived_count: number;
1247
+ }
1248
+ export interface OrgIntegritySummary {
1249
+ total_gaps: number;
1250
+ critical_gaps: number;
1251
+ waived_gaps: number;
1252
+ top_gaps: IntegrityGap[];
1253
+ attestation_pending: number;
1254
+ is_empty_catalog: boolean;
1255
+ }
1256
+ declare class IntegrityResource extends BaseResource {
1257
+ /**
1258
+ * GET /admin/integrity/assess?entity_type=&entity_id= -> single-entity assessment.
1259
+ * NOTE: for entity_type "release" this is a documented v1 no-op — no
1260
+ * release-grain gap code exists yet, so `gaps` is always empty by design
1261
+ * (see assessEntity's release branch in lib/services/integrity-floor.ts).
1262
+ */
1263
+ assessEntity(entityType: "work" | "recording" | "release", entityId: string): Promise<EntityAssessment>;
1264
+ /** GET /admin/integrity/assess (no params) -> org-grain summary. */
1265
+ assessOrg(): Promise<OrgIntegritySummary>;
1266
+ /**
1267
+ * POST /admin/integrity/waivers. Duplicate-active-waiver is a 409
1268
+ * (`ConflictError` on the app side) — surfaces here as a non-retryable
1269
+ * `ApiError` with `status === 409` (see `BaseResource.request`).
1270
+ */
1271
+ waive(input: {
1272
+ gap_code: string;
1273
+ entity_type: string;
1274
+ entity_id: string;
1275
+ reason: string;
1276
+ }): Promise<{
1277
+ id: string;
1278
+ }>;
1279
+ /** PATCH /admin/integrity/waivers { waiver_id, revoke: true }. No un-revoke path. */
1280
+ revokeWaiver(waiverId: string): Promise<void>;
1281
+ }
1180
1282
  interface PresignedUploadResult {
1181
1283
  uploadUrl: string;
1182
1284
  uploadId: string;
@@ -1564,7 +1666,9 @@ declare class RecordingsResource extends BaseResource {
1564
1666
  created_to?: string;
1565
1667
  }): Promise<PaginatedResult<Recording>>;
1566
1668
  get(id: string): Promise<Recording>;
1567
- create(data: Partial<Recording>): Promise<Recording>;
1669
+ create(data: Partial<Recording> & {
1670
+ create_twin?: boolean;
1671
+ }): Promise<Recording>;
1568
1672
  update(id: string, updates: Partial<Recording>): Promise<Recording>;
1569
1673
  delete(id: string): Promise<DeletionResult>;
1570
1674
  getByWork(workId: string): Promise<Recording[]>;
@@ -4275,6 +4379,7 @@ export declare class PicaClient {
4275
4379
  shareSend: ShareSendResource;
4276
4380
  accessSimulate: AccessSimulateResource;
4277
4381
  approvals: ApprovalsResource;
4382
+ integrity: IntegrityResource;
4278
4383
  /**
4279
4384
  * Get accurate catalog stats via SQL counts (no pagination limits)
4280
4385
  */