@withpica/mcp-sdk 4.0.0 → 4.1.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,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [4.1.0] - 2026-10-29
15
+
16
+ ### Changed
17
+
18
+ - **A write that may have run is never sent twice** (#3391). A POST or PATCH is resent only on 429
19
+ or 503, refusals before the route runs. A timeout, a dropped connection, a 502 or a 504 now throws
20
+ `WriteOutcomeUnknownError` (`code: "WRITE_OUTCOME_UNKNOWN"`) instead of resending: a 94 s works
21
+ create on prod was resent at the 30 s timeout and answered `WORK_ALREADY_EXISTS` naming the song
22
+ its first attempt had made. GET, PUT and DELETE keep every retry.
23
+
24
+ - `credits.listCollaborators(workId)`: `verified` and `split_status` are each collaborator's own
25
+ confirmation (`split_status` is `attested`, `pending`, `disputed` or `declined`; `verified` is
26
+ true only when every one of their credits on the work is attested). Both used to say "verified"
27
+ for everyone.
28
+
29
+ ### Deprecated
30
+
31
+ - `is_owner` on `credits.listCollaborators(workId)` entries. The server no longer sends it, so a
32
+ reader gets `undefined`. It was `true` for every entry and did not reflect the credit (the same
33
+ field `pica_credits_list` dropped in mcp-server 2.107.0). The type keeps it optional, so 4.x code
34
+ that reads it still compiles; it is removed in the next major.
35
+
36
+ - `isrc_source` on `recordings.create` / `recordings.update` (and works writes): ignored by the
37
+ server, which records where an ISRC came from; the response's `warnings` says so.
38
+
39
+ ### Added
40
+
41
+ - `shareSend.send` takes `share_link_id` (email an existing link).
42
+ - `recordingCredits.bulkUpdate`: each credit takes `instrument`, applied on every target recording.
43
+ - `audioFiles.list({ cursor })` (#3392): start after a previous page's `pagination.next_cursor`
44
+ instead of at `offset`; a file uploaded during the walk no longer shifts the pages.
45
+
46
+ ### One bio per person
47
+
48
+ - `users.getMyProfile()` adds `bio_short`, `bio_confirmed`, `bio_choice: MyProfileBioChoice | null` and `set_aside_bios: MyProfileSetAsideBio[]`. `bio` is now the biography on the caller's own person record.
49
+ - `users.setBio()` returns `{ bio, person_id }`. New `users.chooseBio("current" | "earlier")`.
50
+ - `users.importBioFromPerson()` is **deprecated**. The server answers 410 RETIRED, and the method will be removed in the next major.
51
+
14
52
  ## [4.0.0] - 2026-10-23
15
53
 
16
54
  > **Major** for one breaking change, below. Publish this first, then `@withpica/mcp-utils` 2.0.1,
package/dist/index.d.ts CHANGED
@@ -398,8 +398,15 @@ interface WorkCredit {
398
398
  splits: number;
399
399
  person_name?: string;
400
400
  ipi?: string;
401
+ /** True only when every one of the person's credits on the work is attested. */
401
402
  verified?: boolean;
403
+ /** attested | pending | disputed | declined (work_collaborators.attestation_status). */
402
404
  split_status?: string;
405
+ /**
406
+ * @deprecated No longer sent: it was `true` for every entry and did not
407
+ * reflect the credit. Kept optional so 4.x readers still compile; removed in
408
+ * the next major.
409
+ */
403
410
  is_owner?: boolean;
404
411
  }
405
412
  /** One credit row on a work, from GET /admin/works/:id/credits?view=rows. */
@@ -987,6 +994,15 @@ export interface DeletionResult {
987
994
  export declare class EntityNotFoundError extends ApiError {
988
995
  constructor(message: string);
989
996
  }
997
+ /**
998
+ * A write whose outcome is unknown: it timed out, lost its connection, or got
999
+ * a 502/504, and was not resent because it may have been applied. Look before
1000
+ * trying again.
1001
+ */
1002
+ export declare class WriteOutcomeUnknownError extends ApiError {
1003
+ readonly code = "WRITE_OUTCOME_UNKNOWN";
1004
+ constructor(method: string, path: string, cause: string, status?: number);
1005
+ }
990
1006
  declare class BaseResource {
991
1007
  protected baseUrl: string;
992
1008
  protected apiKey: string;
@@ -1880,6 +1896,8 @@ declare class AudioFilesResource extends BaseResource {
1880
1896
  query?: string;
1881
1897
  limit?: number;
1882
1898
  offset?: number;
1899
+ /** Start after a previous page's `pagination.next_cursor`, instead of at offset. */
1900
+ cursor?: string;
1883
1901
  }): Promise<AudioFile[]>;
1884
1902
  get(id: string): Promise<AudioFile>;
1885
1903
  /**
@@ -2050,6 +2068,14 @@ declare class AgreementsResource extends BaseResource {
2050
2068
  agreement: Agreement;
2051
2069
  signatureStatus: unknown;
2052
2070
  linkedWorks: unknown[];
2071
+ /** Documents linked to the agreement; null when the server could not read them. */
2072
+ linkedDocuments?: Array<{
2073
+ id: string;
2074
+ title: string | null;
2075
+ filename: string | null;
2076
+ category: string | null;
2077
+ created_at: string | null;
2078
+ }> | null;
2053
2079
  }>;
2054
2080
  create(data: Partial<Agreement>): Promise<Agreement>;
2055
2081
  /**
@@ -2270,8 +2296,12 @@ declare class ShareSendResource extends BaseResource {
2270
2296
  scope?: "view" | "view+download";
2271
2297
  confirm_first_external_send?: boolean;
2272
2298
  included_file_ids?: string[];
2299
+ /** email this existing share link instead of making one (its settings stand) */
2300
+ share_link_id?: string;
2273
2301
  }): Promise<{
2274
2302
  send_id: string;
2303
+ /** "failed" means Postmark took no email (the share_sends row says why) */
2304
+ delivery: "sent" | "failed";
2275
2305
  share_link_id: string;
2276
2306
  share_url: string;
2277
2307
  work_ids: string[];
@@ -4640,20 +4670,38 @@ declare class UsersResource extends BaseResource {
4640
4670
  handle_accepts_invites: boolean;
4641
4671
  avatar_url: string | null;
4642
4672
  bio: string | null;
4673
+ bio_short: string | null;
4674
+ bio_confirmed: boolean;
4675
+ bio_choice: MyProfileBioChoice | null;
4676
+ set_aside_bios: MyProfileSetAsideBio[];
4643
4677
  linked_person_id: string | null;
4644
4678
  }>;
4679
+ /**
4680
+ * Write your bio: the biography on your own person record (one bio per
4681
+ * person). Refused 409 NO_LINKED_PERSON when your account has no person.
4682
+ */
4645
4683
  setBio(bio: string | null): Promise<{
4646
4684
  bio: string | null;
4685
+ person_id: string;
4686
+ }>;
4687
+ /**
4688
+ * Settle a waiting `bio_choice`: "current" keeps your bio, "earlier" uses
4689
+ * the earlier one. The text not kept goes to `set_aside_bios`, never
4690
+ * deleted. Refused 409 NO_CHOICE_WAITING when nothing is waiting.
4691
+ */
4692
+ chooseBio(keep: "current" | "earlier"): Promise<{
4693
+ bio: string | null;
4694
+ person_id: string;
4647
4695
  }>;
4648
4696
  setAvatarUrl(avatarUrl: string | null): Promise<{
4649
4697
  avatar_url: string | null;
4650
4698
  }>;
4651
4699
  /**
4652
- * Copy `people.biography` into `user_profiles.bio`. Returns the new
4653
- * bio on success. On `would_overwrite` (existing bio + overwrite
4654
- * false), surfaces both the existing and proposed bios so the agent
4655
- * can present a yes/no to the user before re-calling with
4656
- * `overwrite: true`.
4700
+ * @deprecated Retired: there is one bio now. Your profile bio IS the
4701
+ * biography on your own person record, so there is nothing to import, and
4702
+ * the server answers 410 RETIRED. Read the bio with `getMyProfile` and
4703
+ * change it with `setBio`. Kept so an existing caller gets that message
4704
+ * rather than a missing method; removed in the next major.
4657
4705
  */
4658
4706
  importBioFromPerson(params?: {
4659
4707
  overwrite?: boolean;
@@ -4662,6 +4710,17 @@ declare class UsersResource extends BaseResource {
4662
4710
  bio?: string;
4663
4711
  }>;
4664
4712
  }
4713
+ /** An earlier bio waiting for you to choose (see `UsersResource.chooseBio`). */
4714
+ export interface MyProfileBioChoice {
4715
+ id: string;
4716
+ earlier_bio: string;
4717
+ }
4718
+ /** An earlier bio kept after a choice. */
4719
+ export interface MyProfileSetAsideBio {
4720
+ id: string;
4721
+ bio: string;
4722
+ created_at: string;
4723
+ }
4665
4724
  interface DirectorySettings {
4666
4725
  organisation_id: string;
4667
4726
  opted_in: boolean;
@@ -4788,6 +4847,8 @@ export interface RecordingCreditsBulkCreditInput {
4788
4847
  split_type?: string | null;
4789
4848
  display_order?: number;
4790
4849
  notes?: string | null;
4850
+ /** Instrument(s) for this credit, applied on every target recording. */
4851
+ instrument?: string | null;
4791
4852
  }
4792
4853
  export interface RecordingCreditsBulkUpdateInput {
4793
4854
  /** Target every recording on this release. Exactly one of release_id / recording_ids. */
@@ -4990,6 +5051,40 @@ declare class ShareTraceResource extends BaseResource {
4990
5051
  */
4991
5052
  trace(query: ShareTraceQuery): Promise<ShareTraceResult>;
4992
5053
  }
5054
+ /** One line of "who has access" to a song (ADR-346 part 5b). */
5055
+ export interface SongAccessLine {
5056
+ /** Opaque; pass back to remove. */
5057
+ key: string;
5058
+ granteeOrgName: string | null;
5059
+ /** The address a share waits on, when nobody has accepted yet. */
5060
+ pendingEmail: string | null;
5061
+ /** "both" is a legacy share written with no side. */
5062
+ side: "composition" | "master" | "both";
5063
+ /** For a master line: the one recording it covers. */
5064
+ recordingTitle: string | null;
5065
+ status: "active" | "pending";
5066
+ /** "look_after_master": they can also edit this master (2b-1). */
5067
+ canDo: "view" | "look_after_master";
5068
+ /** Part of a wider arrangement: change it from people & access, not here. */
5069
+ widerArrangement: boolean;
5070
+ }
5071
+ export interface SongAccessRemoval {
5072
+ removed: number;
5073
+ failed: number;
5074
+ /** True when they can still see the song: say so and offer a retry. */
5075
+ still_shared: boolean;
5076
+ /** Set when a wider arrangement was kept, so they can still edit. */
5077
+ kept_reason: string | null;
5078
+ }
5079
+ declare class SongAccessResource extends BaseResource {
5080
+ /** GET /admin/works/{id}/access — who can see one of your songs. */
5081
+ list(workId: string): Promise<SongAccessLine[]>;
5082
+ /**
5083
+ * POST /admin/works/{id}/access — end one line. A removal that took
5084
+ * nothing off throws (500 ACCESS_NOT_REMOVED).
5085
+ */
5086
+ remove(workId: string, key: string): Promise<SongAccessRemoval>;
5087
+ }
4993
5088
  /** Siblings of `data` on the recording split edit / end responses. */
4994
5089
  export interface RecordingSplitEditEnvelope {
4995
5090
  previous?: Record<string, any>;
@@ -6298,6 +6393,7 @@ export declare class PicaClient {
6298
6393
  recordingSplits: RecordingSplitsResource;
6299
6394
  recordingCredits: RecordingCreditsResource;
6300
6395
  shareTrace: ShareTraceResource;
6396
+ songAccess: SongAccessResource;
6301
6397
  countExplain: CountExplainResource;
6302
6398
  audioPipelineStatus: AudioPipelineStatusResource;
6303
6399
  publishers: PublishersResource;