@knowsuchagency/fulcrum 2.6.4 → 2.6.6

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/README.md CHANGED
@@ -153,6 +153,17 @@ Create documents with live preview. Generate charts and visualizations. The assi
153
153
 
154
154
  ![AI Assistant Editor](https://raw.githubusercontent.com/knowsuchagency/fulcrum/main/screenshots/assistant-editor-dark.png)
155
155
 
156
+ ### Calendar Integration
157
+
158
+ Connect your calendars via CalDAV so the AI assistant knows your schedule. Google Calendar is supported out of the box with OAuth2.
159
+
160
+ - **Google Calendar** — OAuth2 flow, no password needed
161
+ - **Any CalDAV server** — Nextcloud, Radicale, Baikal, iCloud
162
+ - **Automatic sync** — Calendars sync on a configurable interval
163
+ - **Assistant awareness** — The AI assistant uses your calendar context for planning and scheduling
164
+
165
+ Enable in Settings → Calendar Integration.
166
+
156
167
  ### Messaging Integrations
157
168
 
158
169
  Chat with the AI assistant from anywhere via your favorite messaging platform.
package/bin/fulcrum.js CHANGED
@@ -1541,6 +1541,48 @@ class FulcrumClient {
1541
1541
  body: JSON.stringify(data)
1542
1542
  });
1543
1543
  }
1544
+ async getCaldavStatus() {
1545
+ return this.fetch("/api/caldav/status");
1546
+ }
1547
+ async listCalendars() {
1548
+ return this.fetch("/api/caldav/calendars");
1549
+ }
1550
+ async syncCalendars() {
1551
+ return this.fetch("/api/caldav/sync", { method: "POST" });
1552
+ }
1553
+ async listCalendarEvents(options) {
1554
+ const params = new URLSearchParams;
1555
+ if (options?.calendarId)
1556
+ params.set("calendarId", options.calendarId);
1557
+ if (options?.from)
1558
+ params.set("from", options.from);
1559
+ if (options?.to)
1560
+ params.set("to", options.to);
1561
+ if (options?.limit)
1562
+ params.set("limit", String(options.limit));
1563
+ const query = params.toString();
1564
+ return this.fetch(`/api/caldav/events${query ? `?${query}` : ""}`);
1565
+ }
1566
+ async getCalendarEvent(id) {
1567
+ return this.fetch(`/api/caldav/events/${id}`);
1568
+ }
1569
+ async createCalendarEvent(input) {
1570
+ return this.fetch("/api/caldav/events", {
1571
+ method: "POST",
1572
+ body: JSON.stringify(input)
1573
+ });
1574
+ }
1575
+ async updateCalendarEvent(id, updates) {
1576
+ return this.fetch(`/api/caldav/events/${id}`, {
1577
+ method: "PATCH",
1578
+ body: JSON.stringify(updates)
1579
+ });
1580
+ }
1581
+ async deleteCalendarEvent(id) {
1582
+ return this.fetch(`/api/caldav/events/${id}`, {
1583
+ method: "DELETE"
1584
+ });
1585
+ }
1544
1586
  async getAssistantStats() {
1545
1587
  return this.fetch("/api/assistant/stats");
1546
1588
  }
@@ -43378,7 +43420,8 @@ var init_types4 = __esm(() => {
43378
43420
  "backup",
43379
43421
  "email",
43380
43422
  "messaging",
43381
- "assistant"
43423
+ "assistant",
43424
+ "caldav"
43382
43425
  ]);
43383
43426
  AgentTypeSchema = exports_external.enum(["claude", "opencode"]);
43384
43427
  });
@@ -44081,6 +44124,55 @@ var init_registry = __esm(() => {
44081
44124
  category: "assistant",
44082
44125
  keywords: ["sweep", "last", "hourly", "morning", "evening", "ritual"],
44083
44126
  defer_loading: false
44127
+ },
44128
+ {
44129
+ name: "list_calendars",
44130
+ description: "List all CalDAV calendars synced from the configured server",
44131
+ category: "caldav",
44132
+ keywords: ["calendar", "caldav", "list", "schedule"],
44133
+ defer_loading: true
44134
+ },
44135
+ {
44136
+ name: "sync_calendars",
44137
+ description: "Trigger a manual sync of all CalDAV calendars and events",
44138
+ category: "caldav",
44139
+ keywords: ["calendar", "caldav", "sync", "refresh", "update"],
44140
+ defer_loading: true
44141
+ },
44142
+ {
44143
+ name: "list_calendar_events",
44144
+ description: "List calendar events with optional filtering by calendar, date range, or limit",
44145
+ category: "caldav",
44146
+ keywords: ["calendar", "event", "list", "schedule", "appointment", "meeting"],
44147
+ defer_loading: true
44148
+ },
44149
+ {
44150
+ name: "get_calendar_event",
44151
+ description: "Get details of a specific calendar event by ID",
44152
+ category: "caldav",
44153
+ keywords: ["calendar", "event", "get", "details", "appointment"],
44154
+ defer_loading: true
44155
+ },
44156
+ {
44157
+ name: "create_calendar_event",
44158
+ description: "Create a new calendar event on a CalDAV calendar",
44159
+ category: "caldav",
44160
+ keywords: ["calendar", "event", "create", "new", "schedule", "appointment", "meeting"],
44161
+ defer_loading: true
44162
+ },
44163
+ {
44164
+ name: "update_calendar_event",
44165
+ description: "Update an existing calendar event",
44166
+ category: "caldav",
44167
+ keywords: ["calendar", "event", "update", "edit", "modify", "reschedule"],
44168
+ defer_loading: true
44169
+ },
44170
+ {
44171
+ name: "delete_calendar_event",
44172
+ description: "Delete a calendar event",
44173
+ category: "caldav",
44174
+ keywords: ["calendar", "event", "delete", "remove", "cancel"],
44175
+ defer_loading: true
44084
44176
  }
44085
44177
  ];
44086
44178
  });
@@ -45595,6 +45687,101 @@ var init_assistant_events = __esm(() => {
45595
45687
  ChannelSchema = exports_external.enum(["email", "whatsapp", "discord", "telegram", "slack", "all"]);
45596
45688
  });
45597
45689
 
45690
+ // cli/src/mcp/tools/caldav.ts
45691
+ var registerCaldavTools = (server, client) => {
45692
+ server.tool("list_calendars", "List all CalDAV calendars synced from the configured server.", {}, async () => {
45693
+ try {
45694
+ const calendars = await client.listCalendars();
45695
+ return formatSuccess(calendars);
45696
+ } catch (err) {
45697
+ return handleToolError(err);
45698
+ }
45699
+ });
45700
+ server.tool("sync_calendars", "Trigger a manual sync of all CalDAV calendars and events from the server.", {}, async () => {
45701
+ try {
45702
+ const result = await client.syncCalendars();
45703
+ return formatSuccess(result);
45704
+ } catch (err) {
45705
+ return handleToolError(err);
45706
+ }
45707
+ });
45708
+ server.tool("list_calendar_events", "List calendar events with optional filtering by calendar, date range, or limit.", {
45709
+ calendarId: exports_external.optional(exports_external.string()).describe("Filter by calendar ID"),
45710
+ from: exports_external.optional(exports_external.string()).describe("Start date filter (ISO format or iCal date)"),
45711
+ to: exports_external.optional(exports_external.string()).describe("End date filter (ISO format or iCal date)"),
45712
+ limit: exports_external.optional(exports_external.number()).describe("Maximum events to return")
45713
+ }, async ({ calendarId, from, to, limit }) => {
45714
+ try {
45715
+ const events = await client.listCalendarEvents({ calendarId, from, to, limit });
45716
+ return formatSuccess(events);
45717
+ } catch (err) {
45718
+ return handleToolError(err);
45719
+ }
45720
+ });
45721
+ server.tool("get_calendar_event", "Get details of a specific calendar event by ID.", {
45722
+ id: exports_external.string().describe("Event ID")
45723
+ }, async ({ id }) => {
45724
+ try {
45725
+ const event = await client.getCalendarEvent(id);
45726
+ return formatSuccess(event);
45727
+ } catch (err) {
45728
+ return handleToolError(err);
45729
+ }
45730
+ });
45731
+ server.tool("create_calendar_event", "Create a new calendar event on a CalDAV calendar.", {
45732
+ calendarId: exports_external.string().describe("Calendar ID to create the event in"),
45733
+ summary: exports_external.string().describe("Event title/summary"),
45734
+ dtstart: exports_external.string().describe("Start date/time (iCal format: 20250115T090000Z or 20250115 for all-day)"),
45735
+ dtend: exports_external.optional(exports_external.string()).describe("End date/time (iCal format)"),
45736
+ duration: exports_external.optional(exports_external.string()).describe("Duration (iCal format, e.g., PT1H for 1 hour)"),
45737
+ description: exports_external.optional(exports_external.string()).describe("Event description"),
45738
+ location: exports_external.optional(exports_external.string()).describe("Event location"),
45739
+ allDay: exports_external.optional(exports_external.boolean()).describe("Whether this is an all-day event"),
45740
+ recurrenceRule: exports_external.optional(exports_external.string()).describe("Recurrence rule (RRULE format)"),
45741
+ status: exports_external.optional(exports_external.string()).describe("Event status (TENTATIVE, CONFIRMED, CANCELLED)")
45742
+ }, async (input) => {
45743
+ try {
45744
+ const event = await client.createCalendarEvent(input);
45745
+ return formatSuccess(event);
45746
+ } catch (err) {
45747
+ return handleToolError(err);
45748
+ }
45749
+ });
45750
+ server.tool("update_calendar_event", "Update an existing calendar event.", {
45751
+ id: exports_external.string().describe("Event ID to update"),
45752
+ summary: exports_external.optional(exports_external.string()).describe("New event title/summary"),
45753
+ dtstart: exports_external.optional(exports_external.string()).describe("New start date/time"),
45754
+ dtend: exports_external.optional(exports_external.string()).describe("New end date/time"),
45755
+ duration: exports_external.optional(exports_external.string()).describe("New duration"),
45756
+ description: exports_external.optional(exports_external.string()).describe("New description"),
45757
+ location: exports_external.optional(exports_external.string()).describe("New location"),
45758
+ allDay: exports_external.optional(exports_external.boolean()).describe("Whether this is an all-day event"),
45759
+ recurrenceRule: exports_external.optional(exports_external.string()).describe("New recurrence rule"),
45760
+ status: exports_external.optional(exports_external.string()).describe("New status")
45761
+ }, async ({ id, ...updates }) => {
45762
+ try {
45763
+ const event = await client.updateCalendarEvent(id, updates);
45764
+ return formatSuccess(event);
45765
+ } catch (err) {
45766
+ return handleToolError(err);
45767
+ }
45768
+ });
45769
+ server.tool("delete_calendar_event", "Delete a calendar event from the CalDAV server.", {
45770
+ id: exports_external.string().describe("Event ID to delete")
45771
+ }, async ({ id }) => {
45772
+ try {
45773
+ const result = await client.deleteCalendarEvent(id);
45774
+ return formatSuccess(result);
45775
+ } catch (err) {
45776
+ return handleToolError(err);
45777
+ }
45778
+ });
45779
+ };
45780
+ var init_caldav = __esm(() => {
45781
+ init_zod2();
45782
+ init_utils();
45783
+ });
45784
+
45598
45785
  // cli/src/mcp/tools/index.ts
45599
45786
  function registerTools(server, client) {
45600
45787
  registerCoreTools(server, client);
@@ -45609,6 +45796,7 @@ function registerTools(server, client) {
45609
45796
  registerBackupTools(server, client);
45610
45797
  registerEmailTools(server, client);
45611
45798
  registerAssistantEventTools(server, client);
45799
+ registerCaldavTools(server, client);
45612
45800
  }
45613
45801
  var init_tools = __esm(() => {
45614
45802
  init_core5();
@@ -45623,6 +45811,7 @@ var init_tools = __esm(() => {
45623
45811
  init_backup();
45624
45812
  init_email();
45625
45813
  init_assistant_events();
45814
+ init_caldav();
45626
45815
  init_types4();
45627
45816
  });
45628
45817
 
@@ -45641,7 +45830,7 @@ async function runMcpServer(urlOverride, portOverride) {
45641
45830
  const client = new FulcrumClient(urlOverride, portOverride);
45642
45831
  const server = new McpServer({
45643
45832
  name: "fulcrum",
45644
- version: "2.6.4"
45833
+ version: "2.6.6"
45645
45834
  });
45646
45835
  registerTools(server, client);
45647
45836
  const transport = new StdioServerTransport;
@@ -47990,7 +48179,7 @@ var marketplace_default = `{
47990
48179
  "name": "fulcrum",
47991
48180
  "source": "./",
47992
48181
  "description": "Task orchestration for Claude Code",
47993
- "version": "2.6.4",
48182
+ "version": "2.6.6",
47994
48183
  "skills": [
47995
48184
  "./skills/fulcrum"
47996
48185
  ],
@@ -49178,7 +49367,7 @@ function compareVersions(v1, v2) {
49178
49367
  var package_default = {
49179
49368
  name: "@knowsuchagency/fulcrum",
49180
49369
  private: true,
49181
- version: "2.6.4",
49370
+ version: "2.6.6",
49182
49371
  description: "Harness Attention. Orchestrate Agents. Ship.",
49183
49372
  license: "PolyForm-Perimeter-1.0.0",
49184
49373
  type: "module",
@@ -49258,6 +49447,7 @@ var package_default = {
49258
49447
  sonner: "^2.0.7",
49259
49448
  "tailwind-merge": "^3.4.0",
49260
49449
  tailwindcss: "^4.1.17",
49450
+ tsdav: "^2.1.6",
49261
49451
  "tw-animate-css": "^1.4.0",
49262
49452
  ws: "^8.18.3",
49263
49453
  yaml: "^2.8.2"