@withpica/mcp-sdk 3.1.1 → 3.3.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,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [3.3.0] - 2026-07-04
15
+
16
+ ### Added
17
+
18
+ - `agreements.createFromTemplate(params)` — render a template and create the
19
+ resulting agreement in `draft` status with `required_signers` set. The
20
+ only SDK method that can populate `required_signers` on create; follow
21
+ with `agreements.sendForSignature()` (ADR-289 — entry point of the
22
+ e-signature flow).
23
+
24
+ ## [3.2.0] - 2026-07-04
25
+
26
+ ### Added
27
+
28
+ - `agreements.sendForSignature(id, { expires_in_days })` — dispatch per-signer
29
+ signing-link emails for an agreement (ADR-289 Wave A).
30
+ - `BookingsResource` — query/detail/update for booking enquiries (ADR-289 Wave C).
31
+ - Project participant + multimedia management methods on `ProjectsResource`,
32
+ and work detach support (ADR-289 Wave C).
33
+ - Artist-projects and people-triangulate methods (ADR-289 Wave B).
34
+ - `agreements.getSignatureStatusWithSigners(id)` — per-signer signature status
35
+ (ADR-289 Wave B).
36
+ - Memory update, telegram notification config, and send-hub cancel methods
37
+ (ADR-289 Wave C).
38
+
39
+ ### Changed
40
+
41
+ - `Work` type declares the licensing fields (`training_rights`, `is_licensable`,
42
+ `available_for_licensing`, `licensing_terms`, `licensing_price_usd`,
43
+ `licensing_notes`); `Person` declares `name`. Types-only, additive.
44
+
14
45
  ## [3.1.1] - 2026-07-01
15
46
 
16
47
  ### Added
package/dist/index.d.ts CHANGED
@@ -306,11 +306,19 @@ interface Work {
306
306
  completeness_score?: number | null;
307
307
  ai_disclosure?: Record<string, unknown>;
308
308
  provenance_attestation?: Record<string, unknown>;
309
+ training_rights?: Record<string, unknown>;
310
+ is_licensable?: boolean | null;
311
+ available_for_licensing?: boolean | null;
312
+ licensing_terms?: string | null;
313
+ licensing_price_usd?: number | null;
314
+ licensing_notes?: string | null;
309
315
  created_at: string;
310
316
  updated_at: string;
311
317
  }
312
318
  interface Person {
313
319
  id: string;
320
+ /** Canonical display name (people.name — often a stage name). */
321
+ name?: string;
314
322
  first_name?: string;
315
323
  last_name?: string;
316
324
  email?: string;
@@ -464,6 +472,41 @@ interface AgreementWorkLink {
464
472
  royalty_split_percentage?: number;
465
473
  notes?: string;
466
474
  }
475
+ /** ADR-289 — why a required signer was NOT sent a ready-to-sign email. */
476
+ type AgreementSendForSignatureSkipReason = "no_email_on_file" | "already_signed" | "link_mint_failed" | "email_send_failed";
477
+ interface AgreementSendForSignatureSentEntry {
478
+ person_id: string;
479
+ name: string;
480
+ }
481
+ interface AgreementSendForSignatureSkippedEntry {
482
+ person_id: string;
483
+ name: string;
484
+ reason: AgreementSendForSignatureSkipReason;
485
+ }
486
+ /** ADR-289 — every required signer lands in exactly one of sent/skipped. */
487
+ interface AgreementSendForSignatureResult {
488
+ agreement_id: string;
489
+ status: string;
490
+ sent: AgreementSendForSignatureSentEntry[];
491
+ skipped: AgreementSendForSignatureSkippedEntry[];
492
+ }
493
+ /**
494
+ * ADR-289 — the ONLY request shape that can set `required_signers` on a
495
+ * draft agreement. Mirrors `CreateAgreementFromTemplateParams` in
496
+ * `lib/services/electronic-signature.ts` (camelCase body — the route reads
497
+ * `templateId`/`requiredSigners`/etc off the raw JSON, not snake_case).
498
+ */
499
+ interface CreateAgreementFromTemplateParams {
500
+ templateId: string;
501
+ title: string;
502
+ variables: Record<string, unknown>;
503
+ requiredSigners: string[];
504
+ agreementType: string;
505
+ description?: string;
506
+ expiresInDays?: number;
507
+ /** Derived from the first required signer's person record when omitted. */
508
+ otherPartyName?: string;
509
+ }
467
510
  type SyncPlacementStatus = "licensed" | "aired" | "expired" | "renewed" | "terminated";
468
511
  type SyncPlacementVerificationStatus = "unverified" | "self_attested" | "evidence_attached" | "operator_verified" | "disputed";
469
512
  type SyncPlacementConfidentialityLevel = "public" | "redacted_in_public_car" | "private";
@@ -671,6 +714,40 @@ interface LicenseEnquiry {
671
714
  created_at: string;
672
715
  updated_at: string;
673
716
  }
717
+ /**
718
+ * ADR-289 Wave C1 — ports the bespoke assistant's booking-enquiry tools
719
+ * (search_booking_inquiries / get_booking_enquiry_details /
720
+ * update_booking_enquiry_status / record_booking_response /
721
+ * set_booking_follow_up). Mirrors `lib/services/booking.ts`'s
722
+ * `BookingEnquiry` shape.
723
+ */
724
+ interface BookingEnquiry {
725
+ id: string;
726
+ created_at: string;
727
+ updated_at: string;
728
+ organisation_id: string;
729
+ name: string;
730
+ email: string;
731
+ phone: string | null;
732
+ enquiry_type: string;
733
+ service_id: string | null;
734
+ project_title: string | null;
735
+ project_description: string;
736
+ budget_range: string | null;
737
+ timeline: string | null;
738
+ deadline: string | null;
739
+ status: string;
740
+ priority: string;
741
+ response_sent_at: string | null;
742
+ response_content: string | null;
743
+ responded_by: string | null;
744
+ follow_up_required: boolean;
745
+ follow_up_date: string | null;
746
+ internal_notes: string | null;
747
+ source: string | null;
748
+ referrer: string | null;
749
+ metadata: Record<string, unknown> | null;
750
+ }
674
751
  export declare class ApiError extends Error {
675
752
  status: number;
676
753
  retryable: boolean;
@@ -731,6 +808,20 @@ declare class BaseResource {
731
808
  private fetchWithTimeout;
732
809
  private fetchWithRetry;
733
810
  protected request<T>(method: string, path: string, body?: any): Promise<T>;
811
+ /**
812
+ * Make a request whose SUCCESS body is raw text, not a JSON envelope —
813
+ * for routes that stream a generated file (e.g. `text/csv`) rather than
814
+ * `{success, data}`. `request()` unconditionally calls `response.json()`,
815
+ * which throws a SyntaxError parsing CSV text; every such route needs this
816
+ * method instead (see `ImportResource.getTemplate()` for the prior
817
+ * precedent this generalises).
818
+ *
819
+ * `fetchWithRetry` already throws `ApiError` for non-2xx responses (reading
820
+ * the body as text), so reaching here means `response.ok`. Still guard
821
+ * against a 2xx JSON error envelope (`{success:false}`) via content-type,
822
+ * since a route can commit to status 200 before a later validation step.
823
+ */
824
+ protected requestText(method: string, path: string): Promise<string>;
734
825
  /**
735
826
  * Make a request and return paginated result with metadata
736
827
  */
@@ -878,6 +969,40 @@ declare class PeopleResource extends BaseResource {
878
969
  enrichFromISNI(id: string, isni: string): Promise<Person>;
879
970
  enrichFromMusicBrainz(id: string, musicbrainz_id: string): Promise<Person>;
880
971
  bulkDelete(ids: string[]): Promise<unknown>;
972
+ /**
973
+ * List a person's artist projects — per-stage-name Spotify/YouTube
974
+ * identity + enrichment status (ADR-289 Wave B2 item 4, ports the
975
+ * bespoke assistant's `get_person_artist_projects`).
976
+ */
977
+ listArtistProjects(personId: string): Promise<{
978
+ projects: unknown[];
979
+ total: number;
980
+ }>;
981
+ /**
982
+ * Trigger enrichment for every stage name on a person — matches each
983
+ * against Spotify/YouTube artist identity, auto-applying confident
984
+ * matches and flagging ambiguous ones for disambiguation (ADR-289
985
+ * Wave B2 item 4, ports `enrich_artist_projects`).
986
+ */
987
+ enrichArtistProjects(personId: string): Promise<Record<string, unknown>>;
988
+ /**
989
+ * Mark one of a person's artist projects as primary (unsets any other
990
+ * primary project for the same person server-side) (ADR-289 Wave B2
991
+ * item 4, ports `set_primary_artist_project`).
992
+ */
993
+ setPrimaryArtistProject(artistProjectId: string): Promise<Record<string, unknown>>;
994
+ /**
995
+ * Check whether an external artist name already matches an existing
996
+ * person — exact MusicBrainz-id match, then ISNI-via-MusicBrainz, then
997
+ * a fuzzy name fallback. Read-only (ADR-289 Wave B2 item 5, ports the
998
+ * bespoke assistant's `triangulate_artist` — verdict: NOT subsumed by
999
+ * `pica_resolve_person`, which requires an existing person_id and
1000
+ * writes identifiers rather than searching for a match by bare name).
1001
+ */
1002
+ triangulate(params: {
1003
+ artist_name: string;
1004
+ musicbrainz_id?: string;
1005
+ }): Promise<Record<string, unknown>>;
881
1006
  }
882
1007
  declare class LicensingResource extends BaseResource {
883
1008
  /**
@@ -907,6 +1032,48 @@ declare class LicensingResource extends BaseResource {
907
1032
  * Update a license enquiry status
908
1033
  */
909
1034
  updateEnquiryStatus(id: string, status: string, notes?: string): Promise<LicenseEnquiry>;
1035
+ /**
1036
+ * Set a counter offer on a license enquiry (ADR-289 Wave B1 item 6 —
1037
+ * counter-offer fields on `pica_update_license_enquiry_status`, ports
1038
+ * the bespoke assistant's `set_license_counter_offer`). Setting a counter
1039
+ * offer also moves the enquiry to status "quoted" server-side.
1040
+ */
1041
+ setLicenseEnquiryCounterOffer(id: string, counterOffer: number, notes?: string): Promise<LicenseEnquiry>;
1042
+ }
1043
+ /**
1044
+ * ADR-289 Wave C1 — booking enquiries (internal-team session/production
1045
+ * bookings, distinct from `LicensingResource`'s sync-license enquiries).
1046
+ * Wraps `/admin/bookings` + `/admin/bookings/[id]`.
1047
+ */
1048
+ declare class BookingsResource extends BaseResource {
1049
+ /**
1050
+ * List/search booking enquiries. `GET /admin/bookings` returns the raw
1051
+ * array (not `{data, count}`) — `request()` unwraps to that array.
1052
+ */
1053
+ list(params?: {
1054
+ status?: string;
1055
+ priority?: string;
1056
+ query?: string;
1057
+ enquiry_type?: string;
1058
+ follow_up_required?: boolean;
1059
+ limit?: number;
1060
+ offset?: number;
1061
+ }): Promise<BookingEnquiry[]>;
1062
+ get(id: string): Promise<BookingEnquiry>;
1063
+ /**
1064
+ * `PATCH /admin/bookings/[id]` only processes ONE update mode per call
1065
+ * (status, OR responseContent+respondedBy, OR followUp — the route
1066
+ * returns on the first matching branch). Callers needing multiple
1067
+ * independent updates in one tool invocation must call this once per
1068
+ * mode (mirrors the bespoke assistant's three separate handlers).
1069
+ */
1070
+ update(id: string, data: {
1071
+ status?: string;
1072
+ responseContent?: string;
1073
+ respondedBy?: "pica" | "manual";
1074
+ followUp?: boolean;
1075
+ followUpDate?: string;
1076
+ }): Promise<BookingEnquiry>;
910
1077
  }
911
1078
  export interface WorkCreditAtomicAddInput {
912
1079
  person_id: string;
@@ -1099,6 +1266,14 @@ declare class AgreementsResource extends BaseResource {
1099
1266
  status?: string;
1100
1267
  party_name?: string;
1101
1268
  includeWorkCounts?: boolean;
1269
+ /**
1270
+ * ADR-289 Wave B1 item 4 — filter to agreements in `pending_signature`
1271
+ * or `partially_signed` (ports the bespoke assistant's
1272
+ * `list_pending_signatures`). Maps to `?awaiting_signature=true` on the
1273
+ * route, which already had multi-status filtering (`statuses[]`) under
1274
+ * the hood.
1275
+ */
1276
+ awaiting_signature?: boolean;
1102
1277
  limit?: number;
1103
1278
  offset?: number;
1104
1279
  }): Promise<Agreement[]>;
@@ -1108,6 +1283,15 @@ declare class AgreementsResource extends BaseResource {
1108
1283
  linkedWorks: unknown[];
1109
1284
  }>;
1110
1285
  create(data: Partial<Agreement>): Promise<Agreement>;
1286
+ /**
1287
+ * ADR-289 — the entry point of the e-signature flow. Renders the named
1288
+ * template against `variables` server-side and creates the resulting
1289
+ * agreement in `draft` status with `required_signers` set — the ONLY
1290
+ * route that can populate `required_signers` on create (plain `create()`
1291
+ * above has no such field). Follow with `sendForSignature()` to email the
1292
+ * signing links.
1293
+ */
1294
+ createFromTemplate(params: CreateAgreementFromTemplateParams): Promise<Agreement>;
1111
1295
  update(id: string, updates: Partial<Agreement>): Promise<Agreement>;
1112
1296
  delete(id: string): Promise<void>;
1113
1297
  getWorks(id: string): Promise<AgreementWorkLink[]>;
@@ -1116,11 +1300,46 @@ declare class AgreementsResource extends BaseResource {
1116
1300
  royalty_split_percentage?: number;
1117
1301
  notes?: string;
1118
1302
  }): Promise<AgreementWorkLink>;
1303
+ /**
1304
+ * Unlink (detach) a work from an agreement (ADR-289 Wave B1 item 5 —
1305
+ * `detach` mode on `pica_agreements_link_work`, ports the bespoke
1306
+ * assistant's `unlink_agreement_from_work`).
1307
+ */
1308
+ unlinkWork(id: string, workId: string): Promise<void>;
1309
+ /**
1310
+ * Per-signer signature status: name, signed/pending, signed_at
1311
+ * (ADR-289 Wave B1 item 3 — backs the `signatures` section on
1312
+ * `pica_agreements_inspect`, ports the bespoke assistant's
1313
+ * `get_agreement_signature_status`).
1314
+ */
1315
+ getSignatureStatusWithSigners(id: string): Promise<{
1316
+ agreementId: string;
1317
+ status: string;
1318
+ requiredSignatureCount: number;
1319
+ signatureCount: number;
1320
+ isFullySigned: boolean;
1321
+ expiresAt: string | null;
1322
+ daysUntilExpiry: number | null;
1323
+ signers: Array<{
1324
+ person_id: string;
1325
+ name: string | null;
1326
+ status: "signed" | "pending";
1327
+ signed_at: string | null;
1328
+ }>;
1329
+ }>;
1119
1330
  sourceAgreementSplits(workId: string, agreementId: string, extractedSplits: Array<{
1120
1331
  person_id?: string;
1121
1332
  name?: string;
1122
1333
  percentage: number;
1123
1334
  }>, confidence: number, confirm?: boolean): Promise<any>;
1335
+ /**
1336
+ * ADR-289 — mint a per-signer `/sign/<token>` link and email every required
1337
+ * signer of a draft agreement. Every signer lands in exactly one of
1338
+ * `sent`/`skipped` (with a reason) — never silently half-done.
1339
+ */
1340
+ sendForSignature(id: string, params?: {
1341
+ expires_in_days?: number;
1342
+ }): Promise<AgreementSendForSignatureResult>;
1124
1343
  }
1125
1344
  declare class SyncPlacementsResource extends BaseResource {
1126
1345
  list(params?: SyncPlacementQueryParams): Promise<PaginatedResult<SyncPlacement>>;
@@ -1226,6 +1445,9 @@ declare class MemoryResource extends BaseResource {
1226
1445
  type?: string;
1227
1446
  }): Promise<any>;
1228
1447
  delete(id: string): Promise<void>;
1448
+ update(id: string, params: {
1449
+ content: string;
1450
+ }): Promise<any>;
1229
1451
  }
1230
1452
  declare class NotesResource extends BaseResource {
1231
1453
  list(params?: {
@@ -2393,6 +2615,7 @@ declare class SendResource extends BaseResource {
2393
2615
  }>;
2394
2616
  listPending(): Promise<Array<Record<string, unknown>>>;
2395
2617
  resend(id: string): Promise<Record<string, unknown>>;
2618
+ cancel(id: string): Promise<Record<string, unknown>>;
2396
2619
  }
2397
2620
  declare class AssetsResource extends BaseResource {
2398
2621
  list(params?: {
@@ -2678,11 +2901,18 @@ declare class ImportResource extends BaseResource {
2678
2901
  selectedVideoIds?: string[];
2679
2902
  targetWorkId?: string;
2680
2903
  overrideVersionType?: string;
2904
+ /**
2905
+ * ADR-289 Wave B2 item 1 — when true, a video already linked to a
2906
+ * recording in this org has its stats re-fetched and updated
2907
+ * instead of being re-imported as a duplicate.
2908
+ */
2909
+ refresh?: boolean;
2681
2910
  }): Promise<{
2682
2911
  recordingsCreated: number;
2683
2912
  worksCreated: number;
2684
2913
  worksMatched: number;
2685
2914
  multimediaLinked: number;
2915
+ refreshed: number;
2686
2916
  workIds: string[];
2687
2917
  items: Array<{
2688
2918
  videoId: string;
@@ -2690,7 +2920,7 @@ declare class ImportResource extends BaseResource {
2690
2920
  recordingId: string | null;
2691
2921
  versionType: string;
2692
2922
  matched: boolean;
2693
- status: "created" | "skipped" | "error";
2923
+ status: "created" | "skipped" | "refreshed" | "error";
2694
2924
  error?: string;
2695
2925
  }>;
2696
2926
  }>;
@@ -3033,6 +3263,52 @@ declare class ProjectsResource extends BaseResource {
3033
3263
  project_day?: number | null;
3034
3264
  notes?: string | null;
3035
3265
  }): Promise<any>;
3266
+ /**
3267
+ * Detach (remove) a work from a project (ADR-289 Wave B2 item 2 —
3268
+ * `detach` mode on `pica_projects_attach_works`, ports the bespoke
3269
+ * assistant's `remove_work_from_project`). The work itself is not
3270
+ * deleted — only the `project_works` junction row.
3271
+ */
3272
+ detachWork(projectId: string, workId: string): Promise<void>;
3273
+ listParticipants(projectId: string): Promise<any>;
3274
+ addParticipant(projectId: string, data: {
3275
+ person_id: string;
3276
+ role?: string;
3277
+ notes?: string;
3278
+ }): Promise<any>;
3279
+ addParticipantsBulk(projectId: string, participants: Array<{
3280
+ person_id: string;
3281
+ role?: string;
3282
+ notes?: string;
3283
+ }>): Promise<any>;
3284
+ /** `participantId` is the `project_participants` row id. */
3285
+ updateParticipant(projectId: string, participantId: string, data: {
3286
+ role?: string | null;
3287
+ status?: string;
3288
+ notes?: string;
3289
+ }): Promise<any>;
3290
+ /** `personId` — the route's `[participantId]` segment is actually person_id here. */
3291
+ removeParticipant(projectId: string, personId: string): Promise<void>;
3292
+ listMultimedia(projectId: string, day?: number): Promise<any>;
3293
+ addMultimedia(projectId: string, data: {
3294
+ multimedia_id: string;
3295
+ project_day?: number;
3296
+ notes?: string;
3297
+ allow_download?: boolean;
3298
+ }): Promise<any>;
3299
+ addMultimediaBulk(projectId: string, multimediaIds: string[], options?: {
3300
+ project_day?: number;
3301
+ allow_download?: boolean;
3302
+ }): Promise<any>;
3303
+ /** `multimediaLinkId` is the `project_multimedia` join row's own id. */
3304
+ updateMultimediaLink(projectId: string, multimediaLinkId: string, data: {
3305
+ project_day?: number | null;
3306
+ notes?: string | null;
3307
+ display_order?: number;
3308
+ allow_download?: boolean;
3309
+ }): Promise<any>;
3310
+ /** `multimediaId` — the route's `[multimediaId]` segment on DELETE is the underlying multimedia_items id, not the join row id. */
3311
+ removeMultimediaLink(projectId: string, multimediaId: string): Promise<void>;
3036
3312
  }
3037
3313
  declare class SplitSheetsResource extends BaseResource {
3038
3314
  listForWork(workId: string): Promise<any>;
@@ -3754,6 +4030,14 @@ declare class TelegramResource extends BaseResource {
3754
4030
  getStatus(): Promise<any>;
3755
4031
  sendNotification(message: string): Promise<any>;
3756
4032
  getPreferences(): Promise<any>;
4033
+ setPreferences(params: {
4034
+ event_type?: string;
4035
+ is_enabled?: boolean;
4036
+ bulk_config?: Array<{
4037
+ event_type: string;
4038
+ is_enabled: boolean;
4039
+ }>;
4040
+ }): Promise<any>;
3757
4041
  connect(): Promise<any>;
3758
4042
  }
3759
4043
  declare class ImportDocumentsResource extends BaseResource {
@@ -3838,6 +4122,7 @@ export declare class PicaClient {
3838
4122
  people: PeopleResource;
3839
4123
  recordings: RecordingsResource;
3840
4124
  licensing: LicensingResource;
4125
+ bookings: BookingsResource;
3841
4126
  credits: CreditsResource;
3842
4127
  creditsBalance: CreditsBalanceResource;
3843
4128
  picaScore: PicaScoreResource;
@@ -3920,5 +4205,5 @@ export declare class PicaClient {
3920
4205
  catalogStats(): Promise<CatalogStats>;
3921
4206
  constructor(config: PicaClientConfig);
3922
4207
  }
3923
- export type { Work, Person, Recording, PaginatedResult, PicaClientConfig, SyncSearchParams, SyncTrack, SyncSearchResult, LicenseEnquiryInput, LicenseEnquiry, WorkCredit, WorkCreditsInput, PicaScore, PicaScorePillar, AudioFile, AudioAnalysisStatus, PresignedUploadResult, CompleteUploadResult, IdentifyResult, MultimediaItem, Agreement, AgreementWorkLink, SyncPlacement, SyncPlacementSource, SyncPlacementRecording, SyncPlacementWithRelations, SyncPlacementContactInput, SyncPlacementRecordingInput, SyncPlacementSourceInput, CreateSyncPlacementInput, UpdateSyncPlacementInput, SyncPlacementQueryParams, SyncPlacementStatus, SyncPlacementVerificationStatus, SyncPlacementConfidentialityLevel, SyncPlacementSourceKind, CatalogStats, NotificationsSummary, CreateUploadSessionInput, CreateUploadSessionResult, };
4208
+ export type { Work, Person, Recording, PaginatedResult, PicaClientConfig, SyncSearchParams, SyncTrack, SyncSearchResult, LicenseEnquiryInput, LicenseEnquiry, BookingEnquiry, WorkCredit, WorkCreditsInput, PicaScore, PicaScorePillar, AudioFile, AudioAnalysisStatus, PresignedUploadResult, CompleteUploadResult, IdentifyResult, MultimediaItem, Agreement, AgreementWorkLink, CreateAgreementFromTemplateParams, AgreementSendForSignatureResult, AgreementSendForSignatureSentEntry, AgreementSendForSignatureSkippedEntry, AgreementSendForSignatureSkipReason, SyncPlacement, SyncPlacementSource, SyncPlacementRecording, SyncPlacementWithRelations, SyncPlacementContactInput, SyncPlacementRecordingInput, SyncPlacementSourceInput, CreateSyncPlacementInput, UpdateSyncPlacementInput, SyncPlacementQueryParams, SyncPlacementStatus, SyncPlacementVerificationStatus, SyncPlacementConfidentialityLevel, SyncPlacementSourceKind, CatalogStats, NotificationsSummary, CreateUploadSessionInput, CreateUploadSessionResult, };
3924
4209
  //# sourceMappingURL=index.d.ts.map