@withpica/mcp-sdk 3.1.1 → 3.2.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
@@ -393,6 +393,45 @@ class PeopleResource extends BaseResource {
393
393
  async bulkDelete(ids) {
394
394
  return this.request("POST", "/admin/people/bulk-delete", { ids });
395
395
  }
396
+ /**
397
+ * List a person's artist projects — per-stage-name Spotify/YouTube
398
+ * identity + enrichment status (ADR-289 Wave B2 item 4, ports the
399
+ * bespoke assistant's `get_person_artist_projects`).
400
+ */
401
+ async listArtistProjects(personId) {
402
+ return this.request("GET", `/admin/people/${personId}/artist-projects`);
403
+ }
404
+ /**
405
+ * Trigger enrichment for every stage name on a person — matches each
406
+ * against Spotify/YouTube artist identity, auto-applying confident
407
+ * matches and flagging ambiguous ones for disambiguation (ADR-289
408
+ * Wave B2 item 4, ports `enrich_artist_projects`).
409
+ */
410
+ async enrichArtistProjects(personId) {
411
+ return this.request("POST", `/admin/people/${personId}/enrich-artist-projects`);
412
+ }
413
+ /**
414
+ * Mark one of a person's artist projects as primary (unsets any other
415
+ * primary project for the same person server-side) (ADR-289 Wave B2
416
+ * item 4, ports `set_primary_artist_project`).
417
+ */
418
+ async setPrimaryArtistProject(artistProjectId) {
419
+ return this.request("PATCH", `/admin/artist-projects/${artistProjectId}/set-primary`);
420
+ }
421
+ /**
422
+ * Check whether an external artist name already matches an existing
423
+ * person — exact MusicBrainz-id match, then ISNI-via-MusicBrainz, then
424
+ * a fuzzy name fallback. Read-only (ADR-289 Wave B2 item 5, ports the
425
+ * bespoke assistant's `triangulate_artist` — verdict: NOT subsumed by
426
+ * `pica_resolve_person`, which requires an existing person_id and
427
+ * writes identifiers rather than searching for a match by bare name).
428
+ */
429
+ async triangulate(params) {
430
+ const qp = new URLSearchParams({ artist_name: params.artist_name });
431
+ if (params.musicbrainz_id)
432
+ qp.set("musicbrainz_id", params.musicbrainz_id);
433
+ return this.request("GET", `/admin/people/triangulate?${qp.toString()}`);
434
+ }
396
435
  }
397
436
  class LicensingResource extends BaseResource {
398
437
  /**
@@ -478,6 +517,58 @@ class LicensingResource extends BaseResource {
478
517
  async updateEnquiryStatus(id, status, notes) {
479
518
  return this.request("PATCH", `/admin/license-enquiries/${id}`, { status, your_notes: notes });
480
519
  }
520
+ /**
521
+ * Set a counter offer on a license enquiry (ADR-289 Wave B1 item 6 —
522
+ * counter-offer fields on `pica_update_license_enquiry_status`, ports
523
+ * the bespoke assistant's `set_license_counter_offer`). Setting a counter
524
+ * offer also moves the enquiry to status "quoted" server-side.
525
+ */
526
+ async setLicenseEnquiryCounterOffer(id, counterOffer, notes) {
527
+ return this.request("PATCH", `/admin/license-enquiries/${id}`, { counterOffer, notes });
528
+ }
529
+ }
530
+ /**
531
+ * ADR-289 Wave C1 — booking enquiries (internal-team session/production
532
+ * bookings, distinct from `LicensingResource`'s sync-license enquiries).
533
+ * Wraps `/admin/bookings` + `/admin/bookings/[id]`.
534
+ */
535
+ class BookingsResource extends BaseResource {
536
+ /**
537
+ * List/search booking enquiries. `GET /admin/bookings` returns the raw
538
+ * array (not `{data, count}`) — `request()` unwraps to that array.
539
+ */
540
+ async list(params) {
541
+ const qp = new URLSearchParams();
542
+ if (params?.status)
543
+ qp.set("status", params.status);
544
+ if (params?.priority)
545
+ qp.set("priority", params.priority);
546
+ if (params?.query)
547
+ qp.set("query", params.query);
548
+ if (params?.enquiry_type)
549
+ qp.set("enquiry_type", params.enquiry_type);
550
+ if (params?.follow_up_required !== undefined)
551
+ qp.set("follow_up_required", String(params.follow_up_required));
552
+ if (params?.limit !== undefined)
553
+ qp.set("limit", String(params.limit));
554
+ if (params?.offset !== undefined)
555
+ qp.set("offset", String(params.offset));
556
+ const qs = qp.toString();
557
+ return this.request("GET", `/admin/bookings${qs ? `?${qs}` : ""}`);
558
+ }
559
+ async get(id) {
560
+ return this.request("GET", `/admin/bookings/${encodeURIComponent(id)}`);
561
+ }
562
+ /**
563
+ * `PATCH /admin/bookings/[id]` only processes ONE update mode per call
564
+ * (status, OR responseContent+respondedBy, OR followUp — the route
565
+ * returns on the first matching branch). Callers needing multiple
566
+ * independent updates in one tool invocation must call this once per
567
+ * mode (mirrors the bespoke assistant's three separate handlers).
568
+ */
569
+ async update(id, data) {
570
+ return this.request("PATCH", `/admin/bookings/${encodeURIComponent(id)}`, data);
571
+ }
481
572
  }
482
573
  class CreditsResource extends BaseResource {
483
574
  async listForWork(workId) {
@@ -636,6 +727,8 @@ class AgreementsResource extends BaseResource {
636
727
  queryParams.set("party_name", params.party_name);
637
728
  if (params?.includeWorkCounts)
638
729
  queryParams.set("includeWorkCounts", "true");
730
+ if (params?.awaiting_signature)
731
+ queryParams.set("awaiting_signature", "true");
639
732
  if (params?.limit !== undefined)
640
733
  queryParams.set("limit", String(params.limit));
641
734
  if (params?.offset !== undefined)
@@ -661,6 +754,23 @@ class AgreementsResource extends BaseResource {
661
754
  async linkWork(id, data) {
662
755
  return this.request("POST", `/admin/agreements/${id}/works`, data);
663
756
  }
757
+ /**
758
+ * Unlink (detach) a work from an agreement (ADR-289 Wave B1 item 5 —
759
+ * `detach` mode on `pica_agreements_link_work`, ports the bespoke
760
+ * assistant's `unlink_agreement_from_work`).
761
+ */
762
+ async unlinkWork(id, workId) {
763
+ await this.request("DELETE", `/admin/agreements/${id}/works?work_id=${encodeURIComponent(workId)}`);
764
+ }
765
+ /**
766
+ * Per-signer signature status: name, signed/pending, signed_at
767
+ * (ADR-289 Wave B1 item 3 — backs the `signatures` section on
768
+ * `pica_agreements_inspect`, ports the bespoke assistant's
769
+ * `get_agreement_signature_status`).
770
+ */
771
+ async getSignatureStatusWithSigners(id) {
772
+ return this.request("GET", `/admin/agreements/${id}/signatures`);
773
+ }
664
774
  async sourceAgreementSplits(workId, agreementId, extractedSplits, confidence, confirm) {
665
775
  return this.request("POST", `/admin/works/${workId}/agreement-source-splits`, {
666
776
  agreement_id: agreementId,
@@ -669,6 +779,14 @@ class AgreementsResource extends BaseResource {
669
779
  confirm: confirm ?? false,
670
780
  });
671
781
  }
782
+ /**
783
+ * ADR-289 — mint a per-signer `/sign/<token>` link and email every required
784
+ * signer of a draft agreement. Every signer lands in exactly one of
785
+ * `sent`/`skipped` (with a reason) — never silently half-done.
786
+ */
787
+ async sendForSignature(id, params) {
788
+ return this.request("POST", `/admin/agreements/${id}/send-for-signature`, { expiresInDays: params?.expires_in_days });
789
+ }
672
790
  }
673
791
  // ADR-222 — sync placements as a first-class domain. REST routes implemented
674
792
  // by W4 at /api/admin/sync-placements (paired PR on the same parent feature
@@ -785,6 +903,14 @@ class MemoryResource extends BaseResource {
785
903
  async delete(id) {
786
904
  await this.request("DELETE", `/admin/memory/${id}`);
787
905
  }
906
+ // ADR-289 Wave C2 — pica_memory_update. Backing route is
907
+ // PATCH /admin/memory/[id] (lib/services/assistant-memory
908
+ // updateMemory); only content is exposed here (mirrors the retired
909
+ // bespoke assistant's handleUpdateMemory, which hard-coded
910
+ // source:"corrected" server-side).
911
+ async update(id, params) {
912
+ return this.request("PATCH", `/admin/memory/${id}`, params);
913
+ }
788
914
  }
789
915
  class NotesResource extends BaseResource {
790
916
  async list(params) {
@@ -1961,6 +2087,11 @@ class SendResource extends BaseResource {
1961
2087
  async resend(id) {
1962
2088
  return this.request("POST", `/admin/send/${id}/resend`);
1963
2089
  }
2090
+ // ADR-289 Wave C2 — pica_send_cancel. Backing route is
2091
+ // DELETE /admin/send/[id] (sendHubService.cancel).
2092
+ async cancel(id) {
2093
+ return this.request("DELETE", `/admin/send/${id}`);
2094
+ }
1964
2095
  }
1965
2096
  // --- Assets Resource (physical assets: equipment, instruments, studio gear) ---
1966
2097
  class AssetsResource extends BaseResource {
@@ -2413,6 +2544,83 @@ class ProjectsResource extends BaseResource {
2413
2544
  async attachWork(projectId, data) {
2414
2545
  return this.request("POST", `/admin/projects/${projectId}/works`, data);
2415
2546
  }
2547
+ /**
2548
+ * Detach (remove) a work from a project (ADR-289 Wave B2 item 2 —
2549
+ * `detach` mode on `pica_projects_attach_works`, ports the bespoke
2550
+ * assistant's `remove_work_from_project`). The work itself is not
2551
+ * deleted — only the `project_works` junction row.
2552
+ */
2553
+ async detachWork(projectId, workId) {
2554
+ await this.request("DELETE", `/admin/projects/${projectId}/works/${encodeURIComponent(workId)}`);
2555
+ }
2556
+ // -------------------------------------------------------------------
2557
+ // ADR-289 Wave C1 — participants, ports the bespoke assistant's
2558
+ // add_participants / update_participant / remove_participant /
2559
+ // list_project_participants / get_participant_details trio.
2560
+ //
2561
+ // Route asymmetry (both pre-existing, not introduced here):
2562
+ // - PATCH /participants/[participantId] keys off the participant's
2563
+ // OWN row id.
2564
+ // - DELETE /participants/[participantId] actually keys off person_id
2565
+ // (route comment: "participantId here is actually the person_id
2566
+ // for consistency"). removeParticipant() below reproduces that
2567
+ // literally; callers wanting participant-id ergonomics resolve via
2568
+ // listParticipants() first (see ProjectsTools.manageParticipants).
2569
+ // -------------------------------------------------------------------
2570
+ async listParticipants(projectId) {
2571
+ return this.request("GET", `/admin/projects/${projectId}/participants`);
2572
+ }
2573
+ async addParticipant(projectId, data) {
2574
+ return this.request("POST", `/admin/projects/${projectId}/participants`, data);
2575
+ }
2576
+ async addParticipantsBulk(projectId, participants) {
2577
+ return this.request("POST", `/admin/projects/${projectId}/participants`, {
2578
+ participants,
2579
+ });
2580
+ }
2581
+ /** `participantId` is the `project_participants` row id. */
2582
+ async updateParticipant(projectId, participantId, data) {
2583
+ return this.request("PATCH", `/admin/projects/${projectId}/participants/${encodeURIComponent(participantId)}`, data);
2584
+ }
2585
+ /** `personId` — the route's `[participantId]` segment is actually person_id here. */
2586
+ async removeParticipant(projectId, personId) {
2587
+ await this.request("DELETE", `/admin/projects/${projectId}/participants/${encodeURIComponent(personId)}`);
2588
+ }
2589
+ // -------------------------------------------------------------------
2590
+ // ADR-289 Wave C1 — multimedia, ports the bespoke assistant's
2591
+ // list_project_multimedia / add_multimedia_to_project /
2592
+ // update_project_multimedia / remove_multimedia_from_project.
2593
+ //
2594
+ // Route asymmetry (both pre-existing, not introduced here):
2595
+ // - PATCH /multimedia/[multimediaId] keys off the `project_multimedia`
2596
+ // join row's OWN id.
2597
+ // - DELETE /multimedia/[multimediaId] keys off `multimedia_id` (the
2598
+ // underlying multimedia_items id), not the join row id. Callers
2599
+ // wanting join-row-id ergonomics resolve via listMultimedia() first
2600
+ // (see ProjectsTools.manageMultimedia).
2601
+ // -------------------------------------------------------------------
2602
+ async listMultimedia(projectId, day) {
2603
+ const qs = day !== undefined ? `?day=${day}` : "";
2604
+ return this.request("GET", `/admin/projects/${projectId}/multimedia${qs}`);
2605
+ }
2606
+ async addMultimedia(projectId, data) {
2607
+ return this.request("POST", `/admin/projects/${projectId}/multimedia`, data);
2608
+ }
2609
+ async addMultimediaBulk(projectId, multimediaIds, options) {
2610
+ return this.request("POST", `/admin/projects/${projectId}/multimedia`, {
2611
+ multimedia_ids: multimediaIds,
2612
+ project_day: options?.project_day,
2613
+ allow_download: options?.allow_download,
2614
+ });
2615
+ }
2616
+ /** `multimediaLinkId` is the `project_multimedia` join row's own id. */
2617
+ async updateMultimediaLink(projectId, multimediaLinkId, data) {
2618
+ return this.request("PATCH", `/admin/projects/${projectId}/multimedia/${encodeURIComponent(multimediaLinkId)}`, data);
2619
+ }
2620
+ /** `multimediaId` — the route's `[multimediaId]` segment on DELETE is the underlying multimedia_items id, not the join row id. */
2621
+ async removeMultimediaLink(projectId, multimediaId) {
2622
+ await this.request("DELETE", `/admin/projects/${projectId}/multimedia/${encodeURIComponent(multimediaId)}`);
2623
+ }
2416
2624
  }
2417
2625
  class SplitSheetsResource extends BaseResource {
2418
2626
  async listForWork(workId) {
@@ -3121,6 +3329,25 @@ class TelegramResource extends BaseResource {
3121
3329
  async getPreferences() {
3122
3330
  return this.request("GET", "/admin/settings/telegram/notifications");
3123
3331
  }
3332
+ // ADR-289 Wave C2 — pica_telegram_config write half. The REST route
3333
+ // (POST /admin/settings/telegram/notifications) speaks camelCase
3334
+ // (eventType/isActive/configs) — translate from the snake_case tool args
3335
+ // here so the tool layer stays consistent with every other tool's
3336
+ // snake_case convention.
3337
+ async setPreferences(params) {
3338
+ const body = {};
3339
+ if (params.event_type !== undefined) {
3340
+ body.eventType = params.event_type;
3341
+ body.isActive = params.is_enabled;
3342
+ }
3343
+ if (params.bulk_config) {
3344
+ body.configs = params.bulk_config.map((c) => ({
3345
+ eventType: c.event_type,
3346
+ isActive: c.is_enabled,
3347
+ }));
3348
+ }
3349
+ return this.request("POST", "/admin/settings/telegram/notifications", body);
3350
+ }
3124
3351
  // ADR-159: MCP-native Telegram pairing. Wraps the pair endpoint which
3125
3352
  // returns a magic code (or short-circuits on already-connected / live
3126
3353
  // pending code). Rate-limited to 3 new codes per user per rolling hour.
@@ -3167,6 +3394,8 @@ export class PicaClient {
3167
3394
  people;
3168
3395
  recordings;
3169
3396
  licensing;
3397
+ // ADR-289 Wave C1 — internal-team booking enquiries.
3398
+ bookings;
3170
3399
  credits;
3171
3400
  creditsBalance;
3172
3401
  picaScore;
@@ -3274,6 +3503,7 @@ export class PicaClient {
3274
3503
  this.people = new PeopleResource(baseUrl, config.apiKey, debug);
3275
3504
  this.recordings = new RecordingsResource(baseUrl, config.apiKey, debug);
3276
3505
  this.licensing = new LicensingResource(baseUrl, config.apiKey, debug);
3506
+ this.bookings = new BookingsResource(baseUrl, config.apiKey, debug);
3277
3507
  this.credits = new CreditsResource(baseUrl, config.apiKey, debug);
3278
3508
  this.creditsBalance = new CreditsBalanceResource(baseUrl, config.apiKey, debug);
3279
3509
  this.picaScore = new PicaScoreResource(baseUrl, config.apiKey, debug);