@hostwebhook/node-types 1.69.0 → 1.71.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 (101) hide show
  1. package/dist/bucket-operations.d.ts +88 -0
  2. package/dist/bucket-operations.js +140 -0
  3. package/dist/calendar-toolkit.d.ts +1 -1
  4. package/dist/connections.d.ts +1 -1
  5. package/dist/connections.js +1 -0
  6. package/dist/discord-operations.d.ts +1 -1
  7. package/dist/discord-operations.js +4 -4
  8. package/dist/discord-toolkit.d.ts +1 -1
  9. package/dist/discord-toolkit.js +3 -3
  10. package/dist/dispatch.d.ts +1 -1
  11. package/dist/dispatch.js +1 -0
  12. package/dist/docs-toolkit.d.ts +1 -1
  13. package/dist/drive-toolkit.d.ts +1 -1
  14. package/dist/esm/bucket-operations.d.ts +88 -0
  15. package/dist/esm/bucket-operations.js +136 -0
  16. package/dist/esm/calendar-operations.d.ts +67 -0
  17. package/dist/esm/calendar-operations.js +176 -0
  18. package/dist/esm/calendar-toolkit.d.ts +50 -0
  19. package/dist/esm/calendar-toolkit.js +152 -0
  20. package/dist/esm/capacidad-de-credencial.d.ts +75 -0
  21. package/dist/esm/capacidad-de-credencial.js +68 -0
  22. package/dist/esm/connections.d.ts +17 -0
  23. package/dist/esm/connections.js +107 -0
  24. package/dist/esm/credentials.d.ts +144 -0
  25. package/dist/esm/credentials.js +199 -0
  26. package/dist/esm/discord-operations.d.ts +104 -0
  27. package/dist/esm/discord-operations.js +407 -0
  28. package/dist/esm/discord-toolkit.d.ts +64 -0
  29. package/dist/esm/discord-toolkit.js +260 -0
  30. package/dist/esm/dispatch.d.ts +16 -0
  31. package/dist/esm/dispatch.js +77 -0
  32. package/dist/esm/docs-operations.d.ts +99 -0
  33. package/dist/esm/docs-operations.js +127 -0
  34. package/dist/esm/docs-toolkit.d.ts +42 -0
  35. package/dist/esm/docs-toolkit.js +97 -0
  36. package/dist/esm/drive-operations.d.ts +103 -0
  37. package/dist/esm/drive-operations.js +319 -0
  38. package/dist/esm/drive-toolkit.d.ts +54 -0
  39. package/dist/esm/drive-toolkit.js +177 -0
  40. package/dist/esm/github-operations.d.ts +147 -0
  41. package/dist/esm/github-operations.js +551 -0
  42. package/dist/esm/gmail-operations.d.ts +190 -0
  43. package/dist/esm/gmail-operations.js +560 -0
  44. package/dist/esm/google-analytics-operations.d.ts +99 -0
  45. package/dist/esm/google-analytics-operations.js +222 -0
  46. package/dist/esm/google-contacts-operations.d.ts +93 -0
  47. package/dist/esm/google-contacts-operations.js +363 -0
  48. package/dist/esm/index.d.ts +68 -0
  49. package/dist/esm/index.js +51 -0
  50. package/dist/esm/jira-operations.d.ts +164 -0
  51. package/dist/esm/jira-operations.js +470 -0
  52. package/dist/esm/llm-models.d.ts +101 -0
  53. package/dist/esm/llm-models.js +230 -0
  54. package/dist/esm/mailchimp-operations.d.ts +56 -0
  55. package/dist/esm/mailchimp-operations.js +155 -0
  56. package/dist/esm/mongo-operations.d.ts +61 -0
  57. package/dist/esm/mongo-operations.js +120 -0
  58. package/dist/esm/notion-operations.d.ts +125 -0
  59. package/dist/esm/notion-operations.js +511 -0
  60. package/dist/esm/openrouter.d.ts +142 -0
  61. package/dist/esm/openrouter.js +99 -0
  62. package/dist/esm/package.json +4 -0
  63. package/dist/esm/postgres-operations.d.ts +60 -0
  64. package/dist/esm/postgres-operations.js +75 -0
  65. package/dist/esm/registry.d.ts +160 -0
  66. package/dist/esm/registry.js +885 -0
  67. package/dist/esm/sheets-operations.d.ts +78 -0
  68. package/dist/esm/sheets-operations.js +150 -0
  69. package/dist/esm/sheets-toolkit.d.ts +49 -0
  70. package/dist/esm/sheets-toolkit.js +127 -0
  71. package/dist/esm/shopify-operations.d.ts +95 -0
  72. package/dist/esm/shopify-operations.js +259 -0
  73. package/dist/esm/slack-operations.d.ts +81 -0
  74. package/dist/esm/slack-operations.js +244 -0
  75. package/dist/esm/slack-toolkit.d.ts +60 -0
  76. package/dist/esm/slack-toolkit.js +235 -0
  77. package/dist/esm/telegram-operations.d.ts +104 -0
  78. package/dist/esm/telegram-operations.js +351 -0
  79. package/dist/esm/telegram-toolkit.d.ts +52 -0
  80. package/dist/esm/telegram-toolkit.js +183 -0
  81. package/dist/esm/types.d.ts +149 -0
  82. package/dist/esm/types.js +8 -0
  83. package/dist/esm/ui.d.ts +13 -0
  84. package/dist/esm/ui.js +152 -0
  85. package/dist/esm/whatsapp-operations.d.ts +23 -0
  86. package/dist/esm/whatsapp-operations.js +36 -0
  87. package/dist/index.d.ts +68 -66
  88. package/dist/index.js +193 -187
  89. package/dist/openrouter.d.ts +1 -1
  90. package/dist/registry.d.ts +4 -4
  91. package/dist/registry.js +540 -210
  92. package/dist/sheets-toolkit.d.ts +1 -1
  93. package/dist/slack-operations.d.ts +1 -1
  94. package/dist/slack-operations.js +4 -4
  95. package/dist/slack-toolkit.d.ts +1 -1
  96. package/dist/slack-toolkit.js +3 -3
  97. package/dist/telegram-toolkit.d.ts +1 -1
  98. package/dist/types.d.ts +1 -1
  99. package/dist/ui.d.ts +1 -1
  100. package/dist/ui.js +2 -0
  101. package/package.json +21 -3
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Google Calendar operation enum — single source of truth across the API,
3
+ * Dashboard, and Message Broker. Used by:
4
+ * - calendarAction entity / DTO (api): operation field + validation
5
+ * - dashboard CalendarActionGoogleOperation type
6
+ * - broker hostwebhook types + tool schemas
7
+ * - any future calendar-related node
8
+ *
9
+ * Adding a new Calendar operation = add it here, bump this package's
10
+ * version, publish to npm, and re-install in the consuming repos.
11
+ * Each consumer still owns its operation-specific config schema (the
12
+ * dashboard owns the UI form schema, the api owns the dispatch logic),
13
+ * but the canonical list of valid operation strings lives here.
14
+ */
15
+ export const GOOGLE_CALENDAR_OPERATIONS = [
16
+ 'createEvent',
17
+ 'updateEvent',
18
+ 'deleteEvent',
19
+ 'listEvents',
20
+ 'getEvent',
21
+ /** List all calendars the user can write to. Lets the LLM discover
22
+ * ids before passing `calendarId` to other ops. */
23
+ 'listCalendars',
24
+ /** freebusy.query — returns free windows in a date range. Optionally
25
+ * combine across attendees to find common availability. */
26
+ 'findFreeSlots',
27
+ /** Create a tentative event (status: tentative, no invites sent). The
28
+ * user sees it greyed out in their calendar; LLM follows up with
29
+ * confirmEvent to promote. Mirrors emailAction's createDraft → sendDraft. */
30
+ 'proposeEvent',
31
+ /** Promote a tentative event to confirmed + send invites. Mirrors
32
+ * emailAction's sendDraft. */
33
+ 'confirmEvent',
34
+ ];
35
+ /** Type guard — useful when validating untrusted input (DTOs, tool calls). */
36
+ export function isGoogleCalendarOperation(value) {
37
+ return (typeof value === 'string' &&
38
+ GOOGLE_CALENDAR_OPERATIONS.includes(value));
39
+ }
40
+ /* Fábricas de los campos que se repiten entre operaciones. */
41
+ const eventIdParam = (label, description) => ({
42
+ name: 'eventIdTemplate',
43
+ target: 'root',
44
+ label,
45
+ type: 'template',
46
+ required: true,
47
+ placeholder: '{{payload.eventId}}',
48
+ description,
49
+ execKey: 'eventId',
50
+ });
51
+ /** Los siete de `eventConfig`, que comparten `createEvent`, `updateEvent` y
52
+ `proposeEvent`. */
53
+ const eventConfigParams = () => [
54
+ { name: 'summaryTemplate', target: 'eventConfig', label: 'Summary', type: 'template', placeholder: '{{payload.title}}', execKey: 'summary' },
55
+ { name: 'descriptionTemplate', target: 'eventConfig', label: 'Description', type: 'template', placeholder: 'Event description... (supports {{templates}})', execKey: 'description' },
56
+ { name: 'locationTemplate', target: 'eventConfig', label: 'Location', type: 'template', placeholder: '{{payload.location}}', execKey: 'location' },
57
+ { name: 'startTemplate', target: 'eventConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.startTime}}', execKey: 'start' },
58
+ { name: 'endTemplate', target: 'eventConfig', label: 'End Date', type: 'template', placeholder: '{{payload.endTime}}', execKey: 'end' },
59
+ {
60
+ name: 'attendeesTemplate',
61
+ target: 'eventConfig',
62
+ label: 'Attendees (comma-separated emails)',
63
+ type: 'template',
64
+ placeholder: '{{payload.attendees}}',
65
+ description: 'e.g. user@example.com, other@example.com',
66
+ execKey: 'attendees',
67
+ },
68
+ { name: 'timeZone', target: 'eventConfig', label: 'Time Zone', type: 'timezone', execKey: 'timeZone' },
69
+ ];
70
+ export const GOOGLE_CALENDAR_OPERATION_SPECS = {
71
+ createEvent: {
72
+ label: 'Create Event',
73
+ description: 'Create a new calendar event',
74
+ apiMethod: 'events.insert',
75
+ params: eventConfigParams(),
76
+ },
77
+ updateEvent: {
78
+ label: 'Update Event',
79
+ description: 'Update an existing event by ID',
80
+ apiMethod: 'events.patch',
81
+ params: [
82
+ eventIdParam('Event ID', 'Template to resolve the Google Calendar event ID'),
83
+ ...eventConfigParams(),
84
+ ],
85
+ },
86
+ deleteEvent: {
87
+ label: 'Delete Event',
88
+ description: 'Delete an event by ID',
89
+ apiMethod: 'events.delete',
90
+ params: [eventIdParam('Event ID', 'Template to resolve the Google Calendar event ID')],
91
+ },
92
+ listEvents: {
93
+ label: 'List Events',
94
+ description: 'List events in a date range',
95
+ apiMethod: 'events.list',
96
+ params: [
97
+ { name: 'timeMinTemplate', target: 'listConfig', label: 'Start Date', type: 'template', placeholder: '{{payload.from}}', execKey: 'timeMin' },
98
+ { name: 'timeMaxTemplate', target: 'listConfig', label: 'End Date', type: 'template', placeholder: '{{payload.to}}', execKey: 'timeMax' },
99
+ { name: 'maxResults', target: 'listConfig', label: 'Max Results', type: 'number', min: 1, max: 2500, default: 10 },
100
+ { name: 'query', target: 'listConfig', label: 'Search Query', type: 'template', placeholder: 'meeting' },
101
+ ],
102
+ },
103
+ getEvent: {
104
+ label: 'Get Event',
105
+ description: 'Get a single event by ID',
106
+ apiMethod: 'events.get',
107
+ params: [eventIdParam('Event ID', 'Template to resolve the Google Calendar event ID')],
108
+ },
109
+ /* ── Las cuatro que se abrieron al modo directo el 2026-08-11 ── */
110
+ listCalendars: {
111
+ label: 'List Calendars',
112
+ description: 'List the calendars you can write to (iterable output)',
113
+ apiMethod: 'calendarList.list',
114
+ viaExecutor: true,
115
+ /* Sin campos: no toma nada. Es de descubrimiento, así que en un pipeline
116
+ determinista aporta poco; está por completitud del enum. */
117
+ params: [],
118
+ },
119
+ findFreeSlots: {
120
+ label: 'Find Free Slots',
121
+ description: 'Find open windows in a date range (iterable output)',
122
+ apiMethod: 'freebusy.query',
123
+ viaExecutor: true,
124
+ params: [
125
+ { name: 'timeMinTemplate', target: 'listConfig', label: 'Window Start', type: 'template', required: true, placeholder: '{{payload.from}}', description: 'ISO 8601. Start of the window to search.', execKey: 'timeMin' },
126
+ { name: 'timeMaxTemplate', target: 'listConfig', label: 'Window End', type: 'template', required: true, placeholder: '{{payload.to}}', description: 'ISO 8601. End of the window to search.', execKey: 'timeMax' },
127
+ { name: 'durationMinutes', target: 'listConfig', label: 'Slot Length (minutes)', type: 'number', min: 15, max: 480, default: 30, description: 'Only windows at least this long are returned.', execKey: 'durationMinutes' },
128
+ { name: 'calendarIds', target: 'listConfig', label: 'Extra Calendars (comma-separated ids)', type: 'template', placeholder: 'primary, team@example.com', description: 'Combine availability across these. Empty = just the calendar configured above.', execKey: 'calendarIds' },
129
+ { name: 'timeZone', target: 'listConfig', label: 'Time Zone', type: 'timezone', description: 'IANA zone used to read the window bounds.', execKey: 'timeZone' },
130
+ ],
131
+ },
132
+ proposeEvent: {
133
+ label: 'Propose Event (tentative)',
134
+ description: 'Create a tentative event — no invites sent',
135
+ apiMethod: 'events.insert (status: tentative)',
136
+ viaExecutor: true,
137
+ params: [
138
+ ...eventConfigParams(),
139
+ /* `recurrence` sólo entra aquí, que va por el ejecutor. `createEvent` y
140
+ `updateEvent` siguen sin él porque su ruta es el `buildEventBody`
141
+ escrito a mano del servicio: es una asimetría entre modos que ya
142
+ existía y que esto no crea ni arregla. */
143
+ {
144
+ name: 'recurrenceTemplate',
145
+ target: 'eventConfig',
146
+ label: 'Recurrence (RRULE)',
147
+ type: 'template',
148
+ placeholder: 'RRULE:FREQ=WEEKLY;BYDAY=MO',
149
+ description: 'One RFC 5545 rule. Empty = a one-off event.',
150
+ execKey: 'recurrence',
151
+ },
152
+ ],
153
+ },
154
+ confirmEvent: {
155
+ label: 'Confirm Proposed Event',
156
+ description: 'Promote a tentative event and send invites',
157
+ apiMethod: 'events.patch (status: confirmed)',
158
+ viaExecutor: true,
159
+ params: [
160
+ eventIdParam('Proposal ID', 'The proposalId a Propose Event run returned. Normally {{payload.proposalId}} from an upstream node — this op is meant to sit downstream of a Propose Event.'),
161
+ {
162
+ name: 'sendUpdates',
163
+ target: 'root',
164
+ label: 'Invite Policy',
165
+ type: 'select',
166
+ default: 'all',
167
+ options: [
168
+ { value: 'all', label: 'All attendees' },
169
+ { value: 'externalOnly', label: 'External attendees only' },
170
+ { value: 'none', label: "Don't send invites" },
171
+ ],
172
+ execKey: 'sendUpdates',
173
+ },
174
+ ],
175
+ },
176
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Calendar AI Toolkit — las nueve herramientas que un calendarAction expone
3
+ * cuando `aiEnabled` está encendido.
4
+ *
5
+ * **Se escribe una sola vez.** Antes vivía dos veces —aquí y en
6
+ * `api/src/mcp-servers/toolkit-specs.ts`— y las dos copias YA habían derivado:
7
+ * las **siete** operaciones que aceptan `calendarId` describían el parámetro de
8
+ * dos maneras distintas. Gana la de la api, que es la única que dice cuál es el
9
+ * defecto:
10
+ *
11
+ * api "Optional calendar id. Defaults to the configured calendar
12
+ * (usually 'primary'). Use list_my_calendars to discover ids."
13
+ * dashboard "Optional override of the configured calendar. Use
14
+ * list_my_calendars first to discover ids when the user
15
+ * mentions a non-default calendar."
16
+ *
17
+ * Esa deriva estaba en la descripción de un PARÁMETRO, así que el conteo de la
18
+ * auditoría del 2026-08-10 no la veía y daba Calendar por limpio. Con las
19
+ * descripciones de parámetro incluidas, la deriva real de los ocho toolkits
20
+ * duplicados eran 32 y no 18.
21
+ *
22
+ * Dos cosas que **no** se añaden, a propósito:
23
+ * - `group`: Calendar nunca tuvo cabeceras de grupo en su lista, y meterlas
24
+ * es estructura visible nueva.
25
+ * - `destructive` en `delete_calendar_event`: cambiaría el comportamiento de
26
+ * `requireConfirmationForDestructive`. Mismo criterio que en Telegram.
27
+ *
28
+ * El array se generó desde la copia de la api para que las descripciones largas
29
+ * salieran idénticas, no tecleadas.
30
+ */
31
+ import type { GoogleCalendarOperation } from './calendar-operations.js';
32
+ export interface GoogleCalendarToolkitParameter {
33
+ name: string;
34
+ type: 'string' | 'number' | 'boolean';
35
+ description: string;
36
+ required: boolean;
37
+ }
38
+ export interface GoogleCalendarToolkitSpec {
39
+ operation: GoogleCalendarOperation;
40
+ /** Etiqueta corta de la fila en la lista de herramientas. */
41
+ label: string;
42
+ /** El nombre con el que el LLM llama a la herramienta. */
43
+ toolName: string;
44
+ /** Descripción y reglas de uso que ve el LLM. */
45
+ description: string;
46
+ parameters: GoogleCalendarToolkitParameter[];
47
+ }
48
+ export declare const GOOGLE_CALENDAR_TOOLKIT_SPECS: GoogleCalendarToolkitSpec[];
49
+ /** Índice por nombre de herramienta, para enrutar un `tools/call` sin recorrer. */
50
+ export declare const GOOGLE_CALENDAR_TOOLKIT_BY_TOOL_NAME: Record<string, GoogleCalendarToolkitSpec>;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Calendar AI Toolkit — las nueve herramientas que un calendarAction expone
3
+ * cuando `aiEnabled` está encendido.
4
+ *
5
+ * **Se escribe una sola vez.** Antes vivía dos veces —aquí y en
6
+ * `api/src/mcp-servers/toolkit-specs.ts`— y las dos copias YA habían derivado:
7
+ * las **siete** operaciones que aceptan `calendarId` describían el parámetro de
8
+ * dos maneras distintas. Gana la de la api, que es la única que dice cuál es el
9
+ * defecto:
10
+ *
11
+ * api "Optional calendar id. Defaults to the configured calendar
12
+ * (usually 'primary'). Use list_my_calendars to discover ids."
13
+ * dashboard "Optional override of the configured calendar. Use
14
+ * list_my_calendars first to discover ids when the user
15
+ * mentions a non-default calendar."
16
+ *
17
+ * Esa deriva estaba en la descripción de un PARÁMETRO, así que el conteo de la
18
+ * auditoría del 2026-08-10 no la veía y daba Calendar por limpio. Con las
19
+ * descripciones de parámetro incluidas, la deriva real de los ocho toolkits
20
+ * duplicados eran 32 y no 18.
21
+ *
22
+ * Dos cosas que **no** se añaden, a propósito:
23
+ * - `group`: Calendar nunca tuvo cabeceras de grupo en su lista, y meterlas
24
+ * es estructura visible nueva.
25
+ * - `destructive` en `delete_calendar_event`: cambiaría el comportamiento de
26
+ * `requireConfirmationForDestructive`. Mismo criterio que en Telegram.
27
+ *
28
+ * El array se generó desde la copia de la api para que las descripciones largas
29
+ * salieran idénticas, no tecleadas.
30
+ */
31
+ const p = (name, description, required = true, type = 'string') => ({ name, type, description, required });
32
+ export const GOOGLE_CALENDAR_TOOLKIT_SPECS = [
33
+ {
34
+ operation: "createEvent",
35
+ label: "Create event",
36
+ toolName: "create_calendar_event",
37
+ description: "Create a new event on the user's calendar. USAGE RULES: (1) Always include start AND end (ISO 8601 datetime or YYYY-MM-DD for all-day). (2) For ALL-DAY events the `end` date is EXCLUSIVE — to cover Apr 19+20 send start=2026-04-19 end=2026-04-21. A single-day all-day event needs end = start + 1 day. (3) Confirm date + time + timezone in your reply (the user lives in Mexico City UTC-6 unless told otherwise). (4) Compose the summary fresh from the user's CURRENT request — never reuse content recalled from memory unless the user explicitly references it. (5) For events with external attendees or significant impact, prefer propose_calendar_event (tentative, no invites) so the user can preview before invites go out.",
38
+ parameters: [
39
+ p("summary", "Short event title.", true),
40
+ p("start", "Event start. ISO 8601 datetime (e.g. 2026-04-19T15:00:00) or date (YYYY-MM-DD) for all-day.", true),
41
+ p("end", "Event end. Same format as start. For all-day events this is EXCLUSIVE: an event that covers Apr 19+20 needs end=2026-04-21.", true),
42
+ p("description", "Optional longer description.", false),
43
+ p("location", "Optional physical or virtual location.", false),
44
+ p("attendees", "Comma-separated emails to invite.", false),
45
+ p("timeZone", "IANA timezone (e.g. America/Mexico_City). Defaults to UTC.", false),
46
+ p("recurrence", "Optional RFC 5545 RRULE string for repeating events (e.g. \"RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10\"). Daily=\"RRULE:FREQ=DAILY\"; weekly Mon=\"RRULE:FREQ=WEEKLY;BYDAY=MO\"; monthly first=\"RRULE:FREQ=MONTHLY;BYDAY=1MO\". Confirm the recurrence pattern in your reply.", false),
47
+ p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
48
+ ],
49
+ },
50
+ {
51
+ operation: "updateEvent",
52
+ label: "Update event",
53
+ toolName: "update_calendar_event",
54
+ description: "Update an existing event by id. Only fields you provide are changed (PATCH semantics). USAGE RULES: (1) Use eventId from a getEvent / listEvents call earlier in THIS conversation, never from memory. (2) When changing time, confirm the new time + timezone in your reply. (3) EXTENDING an all-day event across more days: send the new `end` as the day AFTER the last day (Google's all-day end is EXCLUSIVE). To make an event cover Apr 19+20, set end=2026-04-21. (4) When you change one of start/end on an all-day event, send BOTH so the new range is unambiguous (otherwise PATCH may leave a stale boundary).",
55
+ parameters: [
56
+ p("eventId", "Event id from listEvents / getEvent in THIS conversation.", true),
57
+ p("summary", "Optional new title.", false),
58
+ p("start", "Optional new start. For all-day events use YYYY-MM-DD.", false),
59
+ p("end", "Optional new end. For all-day events this is EXCLUSIVE: to cover through Apr 20 send end=2026-04-21.", false),
60
+ p("description", "Optional new description.", false),
61
+ p("location", "Optional new location.", false),
62
+ p("attendees", "Optional new attendee list (REPLACES existing).", false),
63
+ p("timeZone", "Optional timezone.", false),
64
+ p("recurrence", "Optional RFC 5545 RRULE string for repeating events (e.g. \"RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10\"). Daily=\"RRULE:FREQ=DAILY\"; weekly Mon=\"RRULE:FREQ=WEEKLY;BYDAY=MO\"; monthly first=\"RRULE:FREQ=MONTHLY;BYDAY=1MO\". Confirm the recurrence pattern in your reply.", false),
65
+ p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
66
+ ],
67
+ },
68
+ {
69
+ operation: "deleteEvent",
70
+ label: "Delete event",
71
+ toolName: "delete_calendar_event",
72
+ description: "Permanently delete an event. USAGE RULES: (1) ALWAYS confirm with the user before calling this — calendar deletes are silent and irreversible. (2) Use eventId from a tool call earlier in THIS conversation.",
73
+ parameters: [
74
+ p("eventId", "Event id to delete.", true),
75
+ p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
76
+ ],
77
+ },
78
+ {
79
+ operation: "listEvents",
80
+ label: "List events",
81
+ toolName: "list_calendar_events",
82
+ description: "Search the user's calendar. Returns headers (summary, start, end, attendees) per match. USAGE RULES: (1) Default to next 7 days when the user doesn't specify a window. (2) Use ISO datetimes for timeMin / timeMax. (3) For full event details (description, location), call getEvent with the specific id.",
83
+ parameters: [
84
+ p("timeMin", "Start of window (ISO 8601). Defaults to now.", false),
85
+ p("timeMax", "End of window (ISO 8601). Defaults to 7 days from now.", false),
86
+ p("maxResults", "Default 25, max 250.", false, "number"),
87
+ p("query", "Free-text search across summary/description/attendees.", false),
88
+ p("timeZone", "IANA timezone for parsing timeMin/timeMax.", false),
89
+ p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
90
+ ],
91
+ },
92
+ {
93
+ operation: "getEvent",
94
+ label: "Get event",
95
+ toolName: "get_calendar_event",
96
+ description: "Fetch a single event by id. Returns full details including description, attendees, organizer, recurrence.",
97
+ parameters: [
98
+ p("eventId", "Event id to fetch.", true),
99
+ p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
100
+ ],
101
+ },
102
+ {
103
+ operation: "listCalendars",
104
+ label: "List my calendars",
105
+ toolName: "list_my_calendars",
106
+ description: "Return all calendars the user can write to (primary + shared + secondary). USAGE RULES: (1) Call this when the user mentions a non-default calendar by name (e.g. 'add this to my Work calendar') and you don't yet know its id. (2) After listing, pass the matching `id` as `calendarId` on subsequent ops to target that calendar.",
107
+ parameters: [],
108
+ },
109
+ {
110
+ operation: "findFreeSlots",
111
+ label: "Find free slots",
112
+ toolName: "find_calendar_free_slots",
113
+ description: "Return open windows in a date range across one or more calendars. USAGE RULES: (1) Call this BEFORE proposing / creating an event when the user asks 'when am I free' or wants you to pick a time. (2) Default window: next 7 days, business hours 8am-6pm in the user's timezone. (3) Suggest the top 2-3 slots in your reply, then ask which they prefer.",
114
+ parameters: [
115
+ p("timeMin", "Start of window (ISO 8601).", true),
116
+ p("timeMax", "End of window (ISO 8601).", true),
117
+ p("durationMinutes", "Required slot length in minutes. Default 30, min 15, max 480.", false, "number"),
118
+ p("calendarIds", "Comma-separated calendar ids to combine availability across. Defaults to the configured calendar.", false),
119
+ p("timeZone", "IANA timezone for parsing timeMin/timeMax.", false),
120
+ ],
121
+ },
122
+ {
123
+ operation: "proposeEvent",
124
+ label: "Propose event (tentative)",
125
+ toolName: "propose_calendar_event",
126
+ description: "Create a TENTATIVE event (status: tentative, NO invites sent). The user sees it greyed out in their calendar. USAGE RULES: (1) Use this instead of create_calendar_event for events with external attendees or significant impact — the user previews before invites fire. (2) Show the proposalId in your reply ('I drafted: <details>. Confirm with proposalId X to send invites.'). (3) After the user confirms, call confirm_calendar_event with that proposalId. If they reject, call delete_calendar_event with it.",
127
+ parameters: [
128
+ p("summary", "Short event title.", true),
129
+ p("start", "Event start (ISO 8601 or YYYY-MM-DD for all-day).", true),
130
+ p("end", "Event end. For all-day events this is EXCLUSIVE: to cover through Apr 20 send end=2026-04-21.", true),
131
+ p("description", "Optional longer description.", false),
132
+ p("location", "Optional location.", false),
133
+ p("attendees", "Optional comma-separated emails (NOT invited yet — only saved on the tentative event).", false),
134
+ p("timeZone", "IANA timezone.", false),
135
+ p("recurrence", "Optional RFC 5545 RRULE string for repeating events (e.g. \"RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR;COUNT=10\"). Daily=\"RRULE:FREQ=DAILY\"; weekly Mon=\"RRULE:FREQ=WEEKLY;BYDAY=MO\"; monthly first=\"RRULE:FREQ=MONTHLY;BYDAY=1MO\". Confirm the recurrence pattern in your reply.", false),
136
+ p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
137
+ ],
138
+ },
139
+ {
140
+ operation: "confirmEvent",
141
+ label: "Confirm proposed event",
142
+ toolName: "confirm_calendar_event",
143
+ description: "Promote a tentative event to confirmed and (by default) send invites to attendees. Pairs with propose_calendar_event for the preview-then-commit flow. USAGE RULES: (1) Use the proposalId from your most recent propose_calendar_event call in THIS conversation — never from memory. (2) sendUpdates default 'all' fires invites; pass 'externalOnly' for just non-org attendees, or 'none' to silently confirm.",
144
+ parameters: [
145
+ p("eventId", "Proposal id (returned by propose_calendar_event as proposalId).", true),
146
+ p("sendUpdates", "Invite policy: 'all' (default), 'externalOnly', or 'none'.", false),
147
+ p("calendarId", "Optional calendar id. Defaults to the configured calendar (usually 'primary'). Use list_my_calendars to discover ids.", false),
148
+ ],
149
+ },
150
+ ];
151
+ /** Índice por nombre de herramienta, para enrutar un `tools/call` sin recorrer. */
152
+ export const GOOGLE_CALENDAR_TOOLKIT_BY_TOOL_NAME = Object.fromEntries(GOOGLE_CALENDAR_TOOLKIT_SPECS.map((s) => [s.toolName, s]));
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Qué puede hacer un nodo según el TIPO de credencial que lleva puesta.
3
+ *
4
+ * Hasta ahora un nodo ofrecía siempre todas sus operaciones, porque todas sus
5
+ * credenciales podían hacerlas todas. Con los webhooks deja de ser cierto, y de
6
+ * una forma muy desigual:
7
+ *
8
+ * - Un webhook de Discord ejecuta 4 de las 17 —publicar, y leer/editar/borrar
9
+ * **sus propios** mensajes—, siempre en el único canal para el que se creó.
10
+ * - Un webhook de Slack ejecuta **1 de 16**, y ni siquiera puede elegir el
11
+ * canal: lo fija quien instala la credencial.
12
+ *
13
+ * Esa desigualdad es la que decide la forma de este fichero. No basta con
14
+ * esconder operaciones: hay que esconder **campos dentro de** una operación,
15
+ * porque el destino deja de ser una pregunta. Por eso son dos listas y no una.
16
+ *
17
+ * ── Dónde vive esto y por qué ──
18
+ *
19
+ * Aquí, en el paquete, y no en cada consumidor. Lo mismo tienen que saberlo
20
+ * CUATRO sitios, y si cada uno lo deduce por su cuenta acaban discrepando sin
21
+ * que nada falle al compilar:
22
+ *
23
+ * 1. el selector de operación de la pantalla de detalle;
24
+ * 2. el renderizador de campos de esa misma pantalla;
25
+ * 3. la validación al guardar, en la api;
26
+ * 4. **la expansión del toolkit de IA** — que es el que se rompe más callado:
27
+ * sin esto, a un nodo con credencial de webhook se le entregan al modelo
28
+ * 17 herramientas de las que 13 fallan siempre.
29
+ *
30
+ * Es la misma razón por la que los toolkits se mudaron aquí en 1.66.0. Tener el
31
+ * dato dos veces es tenerlo mal a la vuelta de unas semanas.
32
+ */
33
+ /**
34
+ * Lo que una credencial concreta deja hacer.
35
+ *
36
+ * `operaciones` ausente significa «todas»: así el caso normal —un bot, que
37
+ * puede con todo— no necesita enumerarse ni mantenerse, y sólo se escribe lo
38
+ * que está ACOTADO. Añadir una operación nueva al nodo no obliga a tocar este
39
+ * fichero salvo que el webhook también pueda ejecutarla, que es justo la
40
+ * decisión que uno quiere tener que tomar a mano.
41
+ */
42
+ export interface CapacidadDeCredencial<Op extends string = string> {
43
+ /** Las que puede ejecutar. Ausente = todas las del nodo. */
44
+ operaciones?: readonly Op[];
45
+ /**
46
+ * Campos que desaparecen del formulario y que la validación rechaza.
47
+ *
48
+ * Se juntan aquí dos motivos que para el usuario son el mismo —«esto no lo
49
+ * eliges tú»— aunque por dentro no lo sean: el que viene FIJADO por la
50
+ * credencial (el canal de un webhook) y el que el endpoint sencillamente NO
51
+ * ADMITE (responder a un mensaje: `Execute Webhook` no acepta
52
+ * `message_reference`). Separarlos daría dos listas que se consultan siempre
53
+ * juntas.
54
+ */
55
+ camposNoDisponibles?: readonly string[];
56
+ }
57
+ /** Mapa de un proveedor: tipo de credencial → lo que deja hacer. */
58
+ export type CapacidadesPorCredencial<Op extends string = string> = Readonly<Record<string, CapacidadDeCredencial<Op>>>;
59
+ /**
60
+ * Qué operaciones ofrecer para esta credencial.
61
+ *
62
+ * Sin tipo de credencial —el nodo todavía no tiene ninguna elegida— se
63
+ * devuelven todas: es un hueco por rellenar, no una restricción, y esconder
64
+ * operaciones ahí haría creer que el nodo no sabe hacerlas.
65
+ */
66
+ export declare function operacionesPara<Op extends string>(todas: readonly Op[], mapa: CapacidadesPorCredencial<Op>, tipoDeCredencial: string | null | undefined): readonly Op[];
67
+ /** Si esta credencial puede ejecutar esta operación. */
68
+ export declare function puedeEjecutar<Op extends string>(todas: readonly Op[], mapa: CapacidadesPorCredencial<Op>, tipoDeCredencial: string | null | undefined, operacion: Op): boolean;
69
+ /**
70
+ * Campos que esta credencial no deja elegir.
71
+ *
72
+ * Devuelve un `Set` porque quien lo usa siempre pregunta «¿este campo sí o
73
+ * no?», nunca recorre la lista.
74
+ */
75
+ export declare function camposNoDisponiblesPara(mapa: CapacidadesPorCredencial, tipoDeCredencial: string | null | undefined): ReadonlySet<string>;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Qué puede hacer un nodo según el TIPO de credencial que lleva puesta.
3
+ *
4
+ * Hasta ahora un nodo ofrecía siempre todas sus operaciones, porque todas sus
5
+ * credenciales podían hacerlas todas. Con los webhooks deja de ser cierto, y de
6
+ * una forma muy desigual:
7
+ *
8
+ * - Un webhook de Discord ejecuta 4 de las 17 —publicar, y leer/editar/borrar
9
+ * **sus propios** mensajes—, siempre en el único canal para el que se creó.
10
+ * - Un webhook de Slack ejecuta **1 de 16**, y ni siquiera puede elegir el
11
+ * canal: lo fija quien instala la credencial.
12
+ *
13
+ * Esa desigualdad es la que decide la forma de este fichero. No basta con
14
+ * esconder operaciones: hay que esconder **campos dentro de** una operación,
15
+ * porque el destino deja de ser una pregunta. Por eso son dos listas y no una.
16
+ *
17
+ * ── Dónde vive esto y por qué ──
18
+ *
19
+ * Aquí, en el paquete, y no en cada consumidor. Lo mismo tienen que saberlo
20
+ * CUATRO sitios, y si cada uno lo deduce por su cuenta acaban discrepando sin
21
+ * que nada falle al compilar:
22
+ *
23
+ * 1. el selector de operación de la pantalla de detalle;
24
+ * 2. el renderizador de campos de esa misma pantalla;
25
+ * 3. la validación al guardar, en la api;
26
+ * 4. **la expansión del toolkit de IA** — que es el que se rompe más callado:
27
+ * sin esto, a un nodo con credencial de webhook se le entregan al modelo
28
+ * 17 herramientas de las que 13 fallan siempre.
29
+ *
30
+ * Es la misma razón por la que los toolkits se mudaron aquí en 1.66.0. Tener el
31
+ * dato dos veces es tenerlo mal a la vuelta de unas semanas.
32
+ */
33
+ /** Ninguna restricción: el caso del bot, y el de cualquier tipo sin entrada. */
34
+ const SIN_LIMITE = {};
35
+ /**
36
+ * Qué operaciones ofrecer para esta credencial.
37
+ *
38
+ * Sin tipo de credencial —el nodo todavía no tiene ninguna elegida— se
39
+ * devuelven todas: es un hueco por rellenar, no una restricción, y esconder
40
+ * operaciones ahí haría creer que el nodo no sabe hacerlas.
41
+ */
42
+ export function operacionesPara(todas, mapa, tipoDeCredencial) {
43
+ if (!tipoDeCredencial)
44
+ return todas;
45
+ const cap = mapa[tipoDeCredencial] ?? SIN_LIMITE;
46
+ if (!cap.operaciones)
47
+ return todas;
48
+ /* Se filtra `todas` en vez de devolver la lista del mapa para que el ORDEN
49
+ sea siempre el del nodo. Si no, la pantalla reordenaría sus operaciones al
50
+ cambiar de credencial, que se lee como si hubieran cambiado otras cosas. */
51
+ const permitidas = new Set(cap.operaciones);
52
+ return todas.filter((op) => permitidas.has(op));
53
+ }
54
+ /** Si esta credencial puede ejecutar esta operación. */
55
+ export function puedeEjecutar(todas, mapa, tipoDeCredencial, operacion) {
56
+ return operacionesPara(todas, mapa, tipoDeCredencial).includes(operacion);
57
+ }
58
+ /**
59
+ * Campos que esta credencial no deja elegir.
60
+ *
61
+ * Devuelve un `Set` porque quien lo usa siempre pregunta «¿este campo sí o
62
+ * no?», nunca recorre la lista.
63
+ */
64
+ export function camposNoDisponiblesPara(mapa, tipoDeCredencial) {
65
+ if (!tipoDeCredencial)
66
+ return new Set();
67
+ return new Set(mapa[tipoDeCredencial]?.camposNoDisponibles ?? []);
68
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Node Connection Registry — THE single source of truth for what each node
3
+ * type can receive from and send to.
4
+ *
5
+ * Used by: API (pipeline dispatch), Broker (agent wiring), Dashboard (canvas validation)
6
+ *
7
+ * Adding a new node type = add 1 entry here. All repos import from this package.
8
+ */
9
+ import type { NodeType, NodeConnectionConfig } from './types.js';
10
+ export declare const NODE_CONNECTIONS: Record<NodeType, NodeConnectionConfig>;
11
+ export declare function canReceiveFrom(targetType: NodeType, sourceType: NodeType): boolean;
12
+ export declare function canReceiveFromNodes(nodeType: NodeType): boolean;
13
+ export declare function canSendToNodes(nodeType: NodeType): boolean;
14
+ export declare function isTerminal(nodeType: NodeType): boolean;
15
+ export declare function isNodeType(type: string): type is NodeType;
16
+ /** All valid node type strings */
17
+ export declare const ALL_NODE_TYPES: NodeType[];