@setluca/mcp 0.1.1 → 0.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.
Files changed (60) hide show
  1. package/README.md +110 -42
  2. package/dist/annotations.js +45 -0
  3. package/dist/completions.js +90 -0
  4. package/dist/config.js +55 -29
  5. package/dist/errors.js +59 -14
  6. package/dist/generated/openapi-inputs.js +4324 -1429
  7. package/dist/generated/openapi-outputs.js +21992 -8516
  8. package/dist/generated/route-catalog.js +1480 -0
  9. package/dist/http.js +95 -103
  10. package/dist/index.js +16 -10
  11. package/dist/oauth-resolver.js +58 -36
  12. package/dist/observability.js +11 -3
  13. package/dist/openapi-zod.js +129 -65
  14. package/dist/operations/catalog.js +50 -0
  15. package/dist/operations/groups/analytics.js +122 -0
  16. package/dist/operations/groups/bookings.js +189 -0
  17. package/dist/operations/groups/broadcasts.js +106 -0
  18. package/dist/operations/groups/cadences.js +14 -0
  19. package/dist/operations/groups/callEvents.js +131 -0
  20. package/dist/operations/groups/campaigns.js +132 -0
  21. package/dist/operations/groups/capabilities.js +8 -0
  22. package/dist/operations/groups/coach.js +43 -0
  23. package/dist/operations/groups/conversations.js +48 -0
  24. package/dist/operations/groups/insights.js +33 -0
  25. package/dist/operations/groups/integrations.js +80 -0
  26. package/dist/operations/groups/knowledge.js +34 -0
  27. package/dist/operations/groups/leads.js +101 -0
  28. package/dist/operations/groups/learning.js +24 -0
  29. package/dist/operations/groups/memory.js +27 -0
  30. package/dist/operations/groups/reports.js +14 -0
  31. package/dist/operations/groups/reviewQueue.js +57 -0
  32. package/dist/operations/groups/safety.js +8 -0
  33. package/dist/operations/groups/usage.js +13 -0
  34. package/dist/operations/groups/voice.js +14 -0
  35. package/dist/operations/groups/webhooks.js +76 -0
  36. package/dist/operations/manifest.js +40 -0
  37. package/dist/operations/registry.js +331 -0
  38. package/dist/operations.js +11 -780
  39. package/dist/optional-field.js +12 -0
  40. package/dist/page-shape.js +47 -0
  41. package/dist/pagination.js +164 -0
  42. package/dist/prompts.js +63 -8
  43. package/dist/provenance.js +18 -2
  44. package/dist/remote.js +80 -49
  45. package/dist/resilience.js +117 -0
  46. package/dist/serialization.js +36 -0
  47. package/dist/server.js +256 -281
  48. package/dist/task-tools/analytics.js +168 -0
  49. package/dist/task-tools/bookings.js +154 -0
  50. package/dist/task-tools/cadences.js +65 -0
  51. package/dist/task-tools/calls.js +202 -0
  52. package/dist/task-tools/inbox.js +74 -0
  53. package/dist/task-tools/leads.js +123 -0
  54. package/dist/task-tools/runtime.js +92 -0
  55. package/dist/task-tools.js +21 -0
  56. package/dist/tool-cache.js +39 -0
  57. package/dist/tool.js +228 -0
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/dist/version.js +14 -0
  60. package/package.json +36 -33
@@ -0,0 +1,106 @@
1
+ import { op } from "../registry.js";
2
+ export const broadcastsOperations = [
3
+ op({
4
+ id: "broadcasts.list",
5
+ title: "List broadcasts",
6
+ description: "List broadcasts. Query supports limit, cursor, and status.",
7
+ }),
8
+ op({
9
+ id: "broadcasts.get",
10
+ title: "Get a broadcast",
11
+ description: "Get broadcast detail.",
12
+ redactedFields: [
13
+ "recipients[].messageBody",
14
+ "sampleMessages[].body",
15
+ "segmentSnapshot.excludedRecipients[].displayName",
16
+ "segmentSnapshot.leads[].customFields",
17
+ "segmentSnapshot.leads[].displayName",
18
+ ],
19
+ }),
20
+ op({
21
+ id: "broadcasts.create",
22
+ title: "Create a broadcast",
23
+ description: "Create a broadcast draft. Body requires campaignId and name.",
24
+ redactedFields: [
25
+ "recipients[].messageBody",
26
+ "sampleMessages[].body",
27
+ "segmentSnapshot.excludedRecipients[].displayName",
28
+ "segmentSnapshot.leads[].customFields",
29
+ "segmentSnapshot.leads[].displayName",
30
+ ],
31
+ }),
32
+ op({
33
+ id: "broadcasts.preview",
34
+ title: "Preview a broadcast",
35
+ description: "Refresh broadcast recipient and sample-message preview.",
36
+ redactedFields: [
37
+ "recipients[].messageBody",
38
+ "sampleMessages[].body",
39
+ "segmentSnapshot.excludedRecipients[].displayName",
40
+ "segmentSnapshot.leads[].customFields",
41
+ "segmentSnapshot.leads[].displayName",
42
+ ],
43
+ }),
44
+ op({
45
+ id: "broadcasts.approve",
46
+ title: "Approve a broadcast",
47
+ description: "Approve a safe broadcast draft and snapshot recipients.",
48
+ redactedFields: [
49
+ "recipients[].messageBody",
50
+ "sampleMessages[].body",
51
+ "segmentSnapshot.excludedRecipients[].displayName",
52
+ "segmentSnapshot.leads[].customFields",
53
+ "segmentSnapshot.leads[].displayName",
54
+ ],
55
+ }),
56
+ op({
57
+ id: "broadcasts.launch",
58
+ title: "Launch a broadcast",
59
+ confirmRequired: true,
60
+ description: "Launch an approved broadcast. Sends messages to live leads.",
61
+ redactedFields: [
62
+ "recipients[].messageBody",
63
+ "sampleMessages[].body",
64
+ "segmentSnapshot.excludedRecipients[].displayName",
65
+ "segmentSnapshot.leads[].customFields",
66
+ "segmentSnapshot.leads[].displayName",
67
+ ],
68
+ }),
69
+ op({
70
+ id: "broadcasts.pause",
71
+ title: "Pause a broadcast",
72
+ description: "Pause a running broadcast with an optional operator reason.",
73
+ redactedFields: [
74
+ "recipients[].messageBody",
75
+ "sampleMessages[].body",
76
+ "segmentSnapshot.excludedRecipients[].displayName",
77
+ "segmentSnapshot.leads[].customFields",
78
+ "segmentSnapshot.leads[].displayName",
79
+ ],
80
+ }),
81
+ op({
82
+ id: "broadcasts.retry",
83
+ title: "Retry a broadcast's failed sends",
84
+ confirmRequired: true,
85
+ description: "Retry failed broadcast recipients after operator review. Re-sends messages to leads.",
86
+ redactedFields: [
87
+ "recipients[].messageBody",
88
+ "sampleMessages[].body",
89
+ "segmentSnapshot.excludedRecipients[].displayName",
90
+ "segmentSnapshot.leads[].customFields",
91
+ "segmentSnapshot.leads[].displayName",
92
+ ],
93
+ }),
94
+ op({
95
+ id: "broadcasts.cancel",
96
+ title: "Cancel a broadcast",
97
+ description: "Cancel a draft, approved, running, paused, or failed broadcast.",
98
+ redactedFields: [
99
+ "recipients[].messageBody",
100
+ "sampleMessages[].body",
101
+ "segmentSnapshot.excludedRecipients[].displayName",
102
+ "segmentSnapshot.leads[].customFields",
103
+ "segmentSnapshot.leads[].displayName",
104
+ ],
105
+ }),
106
+ ];
@@ -0,0 +1,14 @@
1
+ import { op } from "../registry.js";
2
+ export const cadencesOperations = [
3
+ op({
4
+ id: "cadences.rescueStart",
5
+ title: "Start a silent-lead rescue",
6
+ confirmRequired: true,
7
+ description: "Enroll silent leads into the multi-day rescue cadence. Starts outbound touches to real leads.",
8
+ }),
9
+ op({
10
+ id: "cadences.pause",
11
+ title: "Pause a lead's cadence",
12
+ description: "Pause (cancel) a lead's running rescue cadence with an optional reason.",
13
+ }),
14
+ ];
@@ -0,0 +1,131 @@
1
+ import { op } from "../registry.js";
2
+ export const callEventsOperations = [
3
+ op({
4
+ id: "callEvents.needingFeedback",
5
+ title: "List calls still needing a report",
6
+ description: "List calls whose time has passed that still need the coach to say what happened. The post-call work queue.",
7
+ redactedFields: [
8
+ "callEvents[].coachNotes",
9
+ "callEvents[].crmSyncError",
10
+ "callEvents[].feedbackFields.followUpNote",
11
+ "callEvents[].feedbackFields.surprise",
12
+ "callEvents[].leadName",
13
+ "callEvents[].summary",
14
+ "callEvents[].summaryStructured",
15
+ ],
16
+ }),
17
+ op({
18
+ id: "callEvents.get",
19
+ title: "Get a call event",
20
+ description: "Read one call event: outcome, rating, summary, and CRM sync state.",
21
+ redactedFields: [
22
+ "callEvent.coachNotes",
23
+ "callEvent.crmSyncError",
24
+ "callEvent.feedbackFields.followUpNote",
25
+ "callEvent.feedbackFields.surprise",
26
+ "callEvent.leadName",
27
+ "callEvent.summary",
28
+ "callEvent.summaryStructured",
29
+ ],
30
+ }),
31
+ op({
32
+ id: "callEvents.byBooking",
33
+ title: "Get a booking's call event",
34
+ description: "Find the call event attached to a booking. A booking whose call hasn't happened yet returns 404, which is normal.",
35
+ redactedFields: [
36
+ "callEvent.coachNotes",
37
+ "callEvent.crmSyncError",
38
+ "callEvent.feedbackFields.followUpNote",
39
+ "callEvent.feedbackFields.surprise",
40
+ "callEvent.leadName",
41
+ "callEvent.summary",
42
+ "callEvent.summaryStructured",
43
+ ],
44
+ }),
45
+ op({
46
+ id: "callEvents.byLead",
47
+ title: "List a lead's call events",
48
+ description: "Read a lead's full call history, oldest first, so a second or third call reads in sequence.",
49
+ redactedFields: [
50
+ "callEvents[].coachNotes",
51
+ "callEvents[].crmSyncError",
52
+ "callEvents[].feedbackFields.followUpNote",
53
+ "callEvents[].feedbackFields.surprise",
54
+ "callEvents[].leadName",
55
+ "callEvents[].summary",
56
+ "callEvents[].summaryStructured",
57
+ ],
58
+ }),
59
+ op({
60
+ id: "callEvents.feedback",
61
+ title: "Report how a call went",
62
+ untrustedContent: true,
63
+ description: "File the coach's report on how a call went. A completed or no_show outcome also records booking attendance, and a completed call queues its summary.",
64
+ redactedFields: [
65
+ "callEvent.coachNotes",
66
+ "callEvent.crmSyncError",
67
+ "callEvent.feedbackFields.followUpNote",
68
+ "callEvent.feedbackFields.surprise",
69
+ "callEvent.leadName",
70
+ "callEvent.summary",
71
+ "callEvent.summaryStructured",
72
+ ],
73
+ }),
74
+ op({
75
+ id: "callEvents.summary.generate",
76
+ title: "Generate a call summary",
77
+ untrustedContent: true,
78
+ description: "Queue a fresh summary and return straight away. Poll the call event for the result.",
79
+ }),
80
+ op({
81
+ id: "callEvents.summary.replace",
82
+ title: "Replace a call summary",
83
+ untrustedContent: true,
84
+ description: "Replace the generated summary with the coach's own wording and push it. A summary already in the CRM updates that same note.",
85
+ redactedFields: [
86
+ "callEvent.coachNotes",
87
+ "callEvent.crmSyncError",
88
+ "callEvent.feedbackFields.followUpNote",
89
+ "callEvent.feedbackFields.surprise",
90
+ "callEvent.leadName",
91
+ "callEvent.summary",
92
+ "callEvent.summaryStructured",
93
+ ],
94
+ }),
95
+ op({
96
+ id: "callEvents.pushToCrm",
97
+ title: "Push a call to the CRM",
98
+ untrustedContent: true,
99
+ description: "Send the current summary to the CRM now, without waiting out the review window. Re-pushing updates the existing note.",
100
+ }),
101
+ op({
102
+ id: "callEvents.undoOutcome",
103
+ title: "Undo a call's outcome",
104
+ untrustedContent: true,
105
+ description: "Clear a mistaken attendance mark and put the call back in the queue. The window is 48 hours from when the outcome was set.",
106
+ redactedFields: [
107
+ "callEvent.coachNotes",
108
+ "callEvent.crmSyncError",
109
+ "callEvent.feedbackFields.followUpNote",
110
+ "callEvent.feedbackFields.surprise",
111
+ "callEvent.leadName",
112
+ "callEvent.summary",
113
+ "callEvent.summaryStructured",
114
+ ],
115
+ }),
116
+ op({
117
+ id: "callEvents.backfill",
118
+ title: "Backfill a booking's call event",
119
+ untrustedContent: true,
120
+ description: "Create a call event for a booking that predates automatic creation, then queue its summary. Safe to call twice: an existing call event comes back as is.",
121
+ redactedFields: [
122
+ "callEvent.coachNotes",
123
+ "callEvent.crmSyncError",
124
+ "callEvent.feedbackFields.followUpNote",
125
+ "callEvent.feedbackFields.surprise",
126
+ "callEvent.leadName",
127
+ "callEvent.summary",
128
+ "callEvent.summaryStructured",
129
+ ],
130
+ }),
131
+ ];
@@ -0,0 +1,132 @@
1
+ import { op } from "../registry.js";
2
+ export const campaignsOperations = [
3
+ op({
4
+ id: "campaigns.list",
5
+ title: "List campaigns",
6
+ description: "List campaigns. Query supports limit, cursor, and status.",
7
+ }),
8
+ op({
9
+ id: "campaigns.get",
10
+ title: "Get a campaign",
11
+ description: "Get campaign draft and latest published version.",
12
+ }),
13
+ op({
14
+ id: "campaigns.create",
15
+ title: "Create a campaign",
16
+ description: "Create a campaign draft. Body requires name and may include graph.",
17
+ }),
18
+ op({
19
+ id: "campaigns.generate",
20
+ title: "Generate a campaign draft",
21
+ description: "Generate a safe AI campaign plan without creating or publishing it.",
22
+ }),
23
+ op({
24
+ id: "campaigns.draft.update",
25
+ title: "Edit a campaign draft",
26
+ description: "Autosave a campaign draft.",
27
+ // The route requires an idempotency key; without this the tool never sends
28
+ // one and every call is rejected (the dead-tool the drift guard now flags).
29
+ }),
30
+ op({
31
+ id: "campaigns.enrollments.list",
32
+ title: "List a campaign's enrollments",
33
+ description: "List campaign enrollments.",
34
+ redactedFields: ["enrollments[].context"],
35
+ }),
36
+ op({
37
+ id: "campaigns.enroll",
38
+ title: "Enroll leads in a campaign",
39
+ confirmRequired: true,
40
+ description: "Enroll a lead in the latest published campaign version. Triggers the live campaign's automation for that lead.",
41
+ }),
42
+ op({
43
+ id: "campaigns.analytics",
44
+ title: "Read a campaign's results",
45
+ description: "Read campaign attribution and performance analytics.",
46
+ }),
47
+ op({
48
+ id: "campaigns.providerCapabilities",
49
+ title: "Check what a campaign's channel supports",
50
+ description: "Evaluate provider capability blockers for a campaign draft.",
51
+ }),
52
+ op({
53
+ id: "campaigns.commentEvents.list",
54
+ title: "List campaign comment events",
55
+ description: "List matched, suppressed, blocked, and replayed comment automation events.",
56
+ // Each event carries verbatim external-commenter text (`body`,
57
+ // `commenterDisplayName`), so this read must be framed untrusted even
58
+ // though the campaigns group is not blanket-untrusted.
59
+ untrustedContent: true,
60
+ redactedFields: [
61
+ "events[].aiClassification",
62
+ "events[].body",
63
+ "events[].commenterDisplayName",
64
+ "events[].matchExplanation",
65
+ "events[].matchResult",
66
+ "events[].providerSnapshot",
67
+ "events[].safetyNotes",
68
+ "events[].sourceMetadata",
69
+ ],
70
+ }),
71
+ op({
72
+ id: "campaigns.simulations.list",
73
+ title: "List a campaign's simulations",
74
+ description: "List persisted campaign simulation runs.",
75
+ }),
76
+ op({
77
+ id: "campaigns.simulations.create",
78
+ title: "Simulate a campaign",
79
+ description: "Run a persisted dry-run simulation without sending messages.",
80
+ redactedFields: [
81
+ "generatedDrafts[]",
82
+ "input.lead",
83
+ "trace[].generatedDraft",
84
+ ],
85
+ }),
86
+ op({
87
+ id: "campaigns.simulations.get",
88
+ title: "Get a campaign simulation",
89
+ description: "Get a campaign simulation run with trace.",
90
+ redactedFields: [
91
+ "generatedDrafts[]",
92
+ "input.lead",
93
+ "trace[].generatedDraft",
94
+ ],
95
+ }),
96
+ op({
97
+ id: "campaigns.commentSimulationSuite.run",
98
+ title: "Run the comment automation suite",
99
+ redactedFields: [
100
+ "simulations[].generatedDrafts[]",
101
+ "simulations[].trace[].generatedDraft",
102
+ ],
103
+ description: "Run the Instagram comment-to-DM simulation suite against a campaign. Any campaign that uses comment automation has to pass it before it can publish, so run this before reaching for publish.",
104
+ }),
105
+ op({
106
+ id: "campaigns.publish",
107
+ title: "Publish a campaign",
108
+ confirmRequired: true,
109
+ description: "Freeze the draft as a new immutable version and point new enrollments at it. Published versions never change, and enrollments against a live campaign reach real leads. Publish is blocked when the target provider cannot do something the campaign needs, so read the provider capabilities first.",
110
+ }),
111
+ op({
112
+ id: "campaigns.setStatus",
113
+ title: "Pause, resume, or archive a campaign",
114
+ description: "Pause, resume, or archive a campaign. A transition that does not make sense for the campaign's current state is rejected rather than forced through.",
115
+ }),
116
+ op({
117
+ id: "campaigns.duplicate",
118
+ title: "Duplicate a campaign",
119
+ description: "Copy a campaign into a fresh unpublished draft and leave the original alone. Use it to change a live campaign without touching what is currently running.",
120
+ }),
121
+ op({
122
+ id: "campaigns.versions.list",
123
+ title: "List campaign versions",
124
+ description: "List a campaign's published version history. Published versions cannot change, so this is the record of what actually ran rather than what the draft says today.",
125
+ }),
126
+ op({
127
+ id: "campaigns.enrollments.timeline",
128
+ title: "Read an enrollment timeline",
129
+ redactedFields: ["enrollment.context"],
130
+ description: "Read every step one enrollment has been through: what got sent, when, and how the lead responded.",
131
+ }),
132
+ ];
@@ -0,0 +1,8 @@
1
+ import { op } from "../registry.js";
2
+ export const capabilitiesOperations = [
3
+ op({
4
+ id: "capabilities.get",
5
+ title: "What this workspace supports",
6
+ description: "Describe Luca's public API capabilities, scopes, and boundaries.",
7
+ }),
8
+ ];
@@ -0,0 +1,43 @@
1
+ import { op } from "../registry.js";
2
+ export const coachOperations = [
3
+ op({
4
+ id: "coach.profile",
5
+ title: "Read the coach's profile",
6
+ description: "Read the coach's account record: name, timezone, business hours, and tone slider. Use it to know when the coach is reachable and how formal they want to sound.",
7
+ }),
8
+ op({
9
+ id: "coach.niche",
10
+ title: "Read the coach's niche",
11
+ description: "Read the coach's canonical niche, the cohort key their benchmarks are compared against.",
12
+ }),
13
+ op({
14
+ id: "coach.nicheProfile",
15
+ title: "Read the coach's niche profile",
16
+ description: "Read the coach's offer, audience, price range, promised outcomes, disqualifiers, and FAQs. This is the context that decides whether a lead is a fit.",
17
+ }),
18
+ op({
19
+ id: "coach.objectionPlaybook",
20
+ title: "Read the coach's objection playbook",
21
+ description: "Read how the coach wants each objection type handled — price, timing, trust, fit — before drafting a reply to one.",
22
+ }),
23
+ op({
24
+ id: "coach.postCallSettings",
25
+ title: "Read the post-call settings",
26
+ description: "Read the coach's post-call preferences: what gets summarized, what gets pushed to the CRM, and what the coach fills in themselves.",
27
+ }),
28
+ op({
29
+ id: "coach.postCallCrmMapping",
30
+ title: "Read the post-call CRM mapping",
31
+ description: "Read which CRM field each post-call value writes to. Check this before a CRM push to know what will land where.",
32
+ }),
33
+ op({
34
+ id: "coach.postCallDealSync",
35
+ title: "Read the post-call deal sync settings",
36
+ description: "Read the CRM pipeline and the stage each call outcome moves a deal to.",
37
+ }),
38
+ op({
39
+ id: "coach.auditLog",
40
+ title: "Read the audit log",
41
+ description: "Read the coach-visible audit trail, newest first, filterable by actor type, action, action prefix, or target. It is the one read that spans every domain, so use it to check what a previous run actually did instead of replaying each list route.",
42
+ }),
43
+ ];
@@ -0,0 +1,48 @@
1
+ import { op } from "../registry.js";
2
+ export const conversationsOperations = [
3
+ op({
4
+ id: "conversations.list",
5
+ title: "List conversations",
6
+ description: "List recent conversations. Query supports limit, cursor, channel, and q.",
7
+ redactedFields: [
8
+ "conversations[].lastMessagePreview",
9
+ "conversations[].leadDisplayName",
10
+ ],
11
+ }),
12
+ op({
13
+ id: "conversations.get",
14
+ title: "Get a conversation",
15
+ description: "Get a conversation with messages and lead context.",
16
+ redactedFields: [
17
+ "conversation.qualificationProgress",
18
+ "copilotContext.leadDisplayName",
19
+ "lead.customFields",
20
+ "lead.displayName",
21
+ "lead.externalUserId",
22
+ "messages[].body",
23
+ "messages[].media",
24
+ "messages[].mediaUrls",
25
+ "messages[].rawPayload",
26
+ "pendingReview.criticIssues",
27
+ "pendingReview.draftBody",
28
+ "pendingReview.qualification",
29
+ ],
30
+ }),
31
+ op({
32
+ id: "conversations.messages",
33
+ title: "Read a conversation's messages",
34
+ description: "Page backward through a thread's older messages, for threads longer than the window the conversation read returns.",
35
+ redactedFields: [
36
+ "messages[].body",
37
+ "messages[].media",
38
+ "messages[].mediaUrls",
39
+ "messages[].rawPayload",
40
+ ],
41
+ }),
42
+ op({
43
+ id: "conversations.send",
44
+ title: "Send a message to a lead",
45
+ confirmRequired: true,
46
+ description: "Send a message to the lead on their channel right away. This is the one conversation tool that reaches a real person without a reviewer seeing the message first, which is why it needs an explicit confirm. Prefer drafting into the review queue unless the coach has asked for this message to go out now.",
47
+ }),
48
+ ];
@@ -0,0 +1,33 @@
1
+ import { op } from "../registry.js";
2
+ export const insightsOperations = [
3
+ op({
4
+ id: "insights.unreadCount",
5
+ title: "Count unread insights",
6
+ description: "How many insights the coach has not read yet. Cheap enough to poll before pulling the whole feed.",
7
+ }),
8
+ op({
9
+ id: "insights.markRead",
10
+ title: "Mark an insight read",
11
+ description: "Mark one insight read, so it stops coming back at the top of the feed.",
12
+ }),
13
+ op({
14
+ id: "insights.dismiss",
15
+ title: "Dismiss an insight",
16
+ description: "Dismiss one insight the coach does not want to act on. Use this rather than leaving it unread forever.",
17
+ }),
18
+ op({
19
+ id: "insights.markActioned",
20
+ title: "Mark an insight actioned",
21
+ description: "Record that the thing an insight asked for was actually done. Use it after doing the work, not instead of it.",
22
+ }),
23
+ op({
24
+ id: "insights.settings.get",
25
+ title: "Read alert delivery settings",
26
+ description: "Read which insight alerts reach the coach and how. The row is created with defaults on the first read, so this never 404s. Check it before concluding a quiet feed means nothing is happening \u2014 it may just be muted.",
27
+ }),
28
+ op({
29
+ id: "insights.settings.update",
30
+ title: "Update alert delivery settings",
31
+ description: "Merge-patch the coach's alert-delivery settings. Send only what you are changing; anything left out keeps its current value.",
32
+ }),
33
+ ];
@@ -0,0 +1,80 @@
1
+ import { op } from "../registry.js";
2
+ export const integrationsOperations = [
3
+ op({
4
+ id: "integrations.connectors.list",
5
+ title: "List available connectors",
6
+ description: "List Zapier, Make, and CRM provider capabilities.",
7
+ }),
8
+ op({
9
+ id: "integrations.crm.oauthUrl",
10
+ title: "Start a CRM connection",
11
+ description: "Create a CRM provider OAuth URL.",
12
+ }),
13
+ op({
14
+ id: "integrations.crm.oauthCallback",
15
+ title: "Finish a CRM connection",
16
+ description: "Exchange a CRM OAuth code and store encrypted credentials.",
17
+ }),
18
+ op({
19
+ id: "integrations.crm.connections.list",
20
+ title: "List CRM connections",
21
+ description: "List CRM connections.",
22
+ }),
23
+ op({
24
+ id: "integrations.crm.connections.create",
25
+ title: "Create a CRM connection",
26
+ description: "Create or update a workspace-scoped CRM connection.",
27
+ }),
28
+ op({
29
+ id: "integrations.crm.connections.schema",
30
+ title: "Read a CRM's field schema",
31
+ description: "Discover CRM provider schema.",
32
+ redactedFields: ["sampleRecords"],
33
+ }),
34
+ op({
35
+ id: "integrations.crm.connections.health",
36
+ title: "Check a CRM connection's health",
37
+ description: "Probe CRM provider health.",
38
+ }),
39
+ op({
40
+ id: "integrations.crm.connections.webhooksSetup",
41
+ title: "Set up a CRM's webhooks",
42
+ description: "Configure CRM provider webhook status.",
43
+ }),
44
+ op({
45
+ id: "integrations.crm.webhooks.record",
46
+ title: "Record a CRM webhook",
47
+ description: "Record an inbound CRM provider webhook event. Idempotent on the provider's event id, so a redelivery is recorded once.",
48
+ }),
49
+ op({
50
+ id: "integrations.crm.mappings.suggest",
51
+ title: "Suggest CRM field mappings",
52
+ description: "Suggest CRM field mappings.",
53
+ }),
54
+ op({
55
+ id: "integrations.crm.mappings.confirm",
56
+ title: "Confirm CRM field mappings",
57
+ description: "Confirm CRM field mappings.",
58
+ }),
59
+ op({
60
+ id: "integrations.crm.syncRuns.list",
61
+ title: "List CRM sync runs",
62
+ description: "List CRM sync history.",
63
+ redactedFields: [
64
+ "syncRuns[].appliedMutations[].fields",
65
+ "syncRuns[].plannedMutations[].fields",
66
+ ],
67
+ }),
68
+ op({
69
+ id: "integrations.crm.syncRuns.create",
70
+ title: "Start a CRM sync",
71
+ description: "Create a CRM dry-run or live sync run.",
72
+ redactedFields: ["appliedMutations[].fields", "plannedMutations[].fields"],
73
+ }),
74
+ op({
75
+ id: "integrations.events.list",
76
+ title: "List integration events",
77
+ description: "List integration event log.",
78
+ redactedFields: ["events[].payload"],
79
+ }),
80
+ ];
@@ -0,0 +1,34 @@
1
+ import { op } from "../registry.js";
2
+ export const knowledgeOperations = [
3
+ op({
4
+ id: "knowledge.suggestions",
5
+ title: "List knowledge suggestions",
6
+ description: "List profile changes proposed from the coach's own knowledge sources, each with the excerpt it was drawn from and the value it would replace.",
7
+ }),
8
+ op({
9
+ id: "knowledge.approveSuggestion",
10
+ title: "Approve a knowledge suggestion",
11
+ confirmRequired: true,
12
+ description: "Approve a profile suggestion and write it into the coach's profile. Every later draft reads the result, so check the excerpt supports the change before approving.",
13
+ }),
14
+ op({
15
+ id: "knowledge.rejectSuggestion",
16
+ title: "Reject a knowledge suggestion",
17
+ description: "Reject a profile suggestion so it stops being offered. The profile is left as it stands.",
18
+ }),
19
+ op({
20
+ id: "knowledge.sources.list",
21
+ title: "List knowledge sources",
22
+ description: "List the content sources the coach has connected \u2014 Notion, Google Docs, a website, an Instagram bio \u2014 with the sync state of each one. Connecting a new source is app-only; this lists what is already there.",
23
+ }),
24
+ op({
25
+ id: "knowledge.sources.sync",
26
+ title: "Re-sync a knowledge source",
27
+ description: "Queue a re-read of one knowledge source now rather than waiting for its next scheduled sync. It returns as soon as the job is queued, so any new suggestions appear on a later read.",
28
+ }),
29
+ op({
30
+ id: "knowledge.sources.disconnect",
31
+ title: "Disconnect a knowledge source",
32
+ description: "Delete a knowledge source. Its pending suggestions go with it; values the coach already approved stay in the profile, because approving copies them there.",
33
+ }),
34
+ ];