@knowsuchagency/fulcrum 2.8.2 → 2.10.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/README.md CHANGED
@@ -15,7 +15,7 @@ Fulcrum doesn't replace your tools—it gives you leverage over them. You config
15
15
  **Six pillars:**
16
16
 
17
17
  - **Claude Code Ecosystem** — Deep integration with Claude Code. Connect via messaging channels, manage tasks, deploy from one dashboard.
18
- - **Proactive AI Concierge** — Your assistant monitors messages, tracks actionable events, creates daily plans, and sends morning/evening briefings automatically.
18
+ - **Proactive AI Concierge** — Your assistant monitors messages, stores important observations as memories, creates daily plans, and sends morning/evening briefings automatically.
19
19
  - **Work From Anywhere** — Run Fulcrum on a remote server. Close your laptop, agents keep working.
20
20
  - **Project Management** — Tasks with dependencies, due dates, labels, and attachments. Visual kanban boards.
21
21
  - **Production Deployment** — Docker Compose with automatic Traefik routing and Cloudflare DNS/tunnels.
@@ -42,13 +42,13 @@ Fulcrum's AI assistant doesn't just respond—it actively monitors and manages y
42
42
 
43
43
  When messages arrive via Email, WhatsApp, Discord, Telegram, or Slack:
44
44
 
45
- - **Actionable requests** (deadlines, meetings, tasks) → Tracked as events, optionally creates tasks
45
+ - **Actionable requests** (deadlines, meetings, tasks) → Stored as memories with `actionable` tag, optionally creates tasks
46
46
  - **Casual conversations** → Responded to naturally, no tracking overhead
47
47
  - **Spam/newsletters** → Silently ignored
48
48
 
49
- ### Actionable Events
49
+ ### Persistent Memory
50
50
 
51
- Every important message becomes an **actionable event**—searchable, linkable to tasks, with a full decision audit trail. Your assistant remembers what it noticed and what it decided.
51
+ Important observations are stored as **memories** with tags like `actionable` or `monitoring`—searchable via full-text search, with recency-weighted results so recent items surface first.
52
52
 
53
53
  ### Daily Planning
54
54
 
@@ -156,11 +156,13 @@ Create documents with live preview. Generate charts and visualizations. The assi
156
156
 
157
157
  ### Calendar Integration
158
158
 
159
- Connect your calendars via CalDAV so the AI assistant knows your schedule. Google Calendar is supported out of the box with OAuth2.
159
+ Connect multiple calendar accounts via CalDAV so the AI assistant knows your schedule. Copy events between calendars across accounts.
160
160
 
161
+ - **Multiple accounts** — Add as many CalDAV accounts as you need
161
162
  - **Google Calendar** — OAuth2 flow, no password needed
162
163
  - **Any CalDAV server** — Nextcloud, Radicale, Baikal, iCloud
163
- - **Automatic sync** — Calendars sync on a configurable interval
164
+ - **Automatic sync** — Each account syncs independently on a configurable interval
165
+ - **One-way event copying** — Copy events between calendars across accounts via configurable rules
164
166
  - **Assistant awareness** — The AI assistant uses your calendar context for planning and scheduling
165
167
 
166
168
  Enable in Settings → Calendar Integration.
@@ -247,7 +249,8 @@ Both plugins include an MCP server with 60+ tools:
247
249
  | **Backup & Restore** | Snapshot database and settings; auto-safety-backup on restore |
248
250
  | **Settings** | View and update configuration; manage notification channels |
249
251
  | **Memory** | Store and search persistent knowledge with FTS5 full-text search |
250
- | **Assistant Events** | Track actionable events; query decision history |
252
+ | **Calendar** | Manage CalDAV accounts, sync calendars, configure event copy rules |
253
+ | **Assistant** | Send messages via channels; query sweep history |
251
254
 
252
255
  Use `search_tools` to discover available tools by keyword or category.
253
256
 
package/bin/fulcrum.js CHANGED
@@ -1197,6 +1197,13 @@ class FulcrumClient {
1197
1197
  method: "DELETE"
1198
1198
  });
1199
1199
  }
1200
+ async deleteTag(tagName) {
1201
+ const allTags = await this.fetch("/api/tags");
1202
+ const tag = allTags.find((t2) => t2.name === tagName);
1203
+ if (!tag)
1204
+ throw new ApiError(404, "Tag not found");
1205
+ return this.fetch(`/api/tags/${tag.id}`, { method: "DELETE" });
1206
+ }
1200
1207
  async setTaskDueDate(taskId, dueDate) {
1201
1208
  return this.fetch(`/api/tasks/${taskId}/due-date`, {
1202
1209
  method: "PATCH",
@@ -1487,39 +1494,6 @@ class FulcrumClient {
1487
1494
  body: JSON.stringify({ uids, limit })
1488
1495
  });
1489
1496
  }
1490
- async listActionableEvents(options) {
1491
- const params = new URLSearchParams;
1492
- if (options?.status)
1493
- params.set("status", options.status);
1494
- if (options?.channel)
1495
- params.set("channel", options.channel);
1496
- if (options?.limit)
1497
- params.set("limit", String(options.limit));
1498
- if (options?.offset)
1499
- params.set("offset", String(options.offset));
1500
- const query = params.toString();
1501
- return this.fetch(`/api/assistant/events${query ? `?${query}` : ""}`);
1502
- }
1503
- async getActionableEvent(id) {
1504
- return this.fetch(`/api/assistant/events/${id}`);
1505
- }
1506
- async createActionableEvent(data) {
1507
- return this.fetch("/api/assistant/events", {
1508
- method: "POST",
1509
- body: JSON.stringify(data)
1510
- });
1511
- }
1512
- async updateActionableEvent(id, updates) {
1513
- return this.fetch(`/api/assistant/events/${id}`, {
1514
- method: "PATCH",
1515
- body: JSON.stringify(updates)
1516
- });
1517
- }
1518
- async deleteActionableEvent(id) {
1519
- return this.fetch(`/api/assistant/events/${id}`, {
1520
- method: "DELETE"
1521
- });
1522
- }
1523
1497
  async listSweepRuns(options) {
1524
1498
  const params = new URLSearchParams;
1525
1499
  if (options?.type)
@@ -1544,8 +1518,39 @@ class FulcrumClient {
1544
1518
  async getCaldavStatus() {
1545
1519
  return this.fetch("/api/caldav/status");
1546
1520
  }
1547
- async listCalendars() {
1548
- return this.fetch("/api/caldav/calendars");
1521
+ async listCalendars(accountId) {
1522
+ const params = accountId ? `?accountId=${accountId}` : "";
1523
+ return this.fetch(`/api/caldav/calendars${params}`);
1524
+ }
1525
+ async listCaldavAccounts() {
1526
+ return this.fetch("/api/caldav/accounts");
1527
+ }
1528
+ async createCaldavAccount(input) {
1529
+ return this.fetch("/api/caldav/accounts", {
1530
+ method: "POST",
1531
+ body: JSON.stringify(input)
1532
+ });
1533
+ }
1534
+ async deleteCaldavAccount(id) {
1535
+ return this.fetch(`/api/caldav/accounts/${id}`, { method: "DELETE" });
1536
+ }
1537
+ async syncCaldavAccount(id) {
1538
+ return this.fetch(`/api/caldav/accounts/${id}/sync`, { method: "POST" });
1539
+ }
1540
+ async listCaldavCopyRules() {
1541
+ return this.fetch("/api/caldav/copy-rules");
1542
+ }
1543
+ async createCaldavCopyRule(input) {
1544
+ return this.fetch("/api/caldav/copy-rules", {
1545
+ method: "POST",
1546
+ body: JSON.stringify(input)
1547
+ });
1548
+ }
1549
+ async deleteCaldavCopyRule(id) {
1550
+ return this.fetch(`/api/caldav/copy-rules/${id}`, { method: "DELETE" });
1551
+ }
1552
+ async executeCaldavCopyRule(id) {
1553
+ return this.fetch(`/api/caldav/copy-rules/${id}/execute`, { method: "POST" });
1549
1554
  }
1550
1555
  async syncCalendars() {
1551
1556
  return this.fetch("/api/caldav/sync", { method: "POST" });
@@ -1611,9 +1616,6 @@ class FulcrumClient {
1611
1616
  async deleteMemory(id) {
1612
1617
  return this.fetch(`/api/memory/${id}`, { method: "DELETE" });
1613
1618
  }
1614
- async getAssistantStats() {
1615
- return this.fetch("/api/assistant/stats");
1616
- }
1617
1619
  }
1618
1620
  var init_client = __esm(() => {
1619
1621
  init_server();
@@ -43951,6 +43953,13 @@ var init_registry = __esm(() => {
43951
43953
  keywords: ["tags", "categories", "filter", "search", "discover"],
43952
43954
  defer_loading: false
43953
43955
  },
43956
+ {
43957
+ name: "delete_tag",
43958
+ description: "Delete a tag from the database and all its associations",
43959
+ category: "tasks",
43960
+ keywords: ["tag", "delete", "remove", "cleanup"],
43961
+ defer_loading: false
43962
+ },
43954
43963
  {
43955
43964
  name: "list_task_attachments",
43956
43965
  description: "List all file attachments for a task",
@@ -44113,46 +44122,67 @@ var init_registry = __esm(() => {
44113
44122
  defer_loading: false
44114
44123
  },
44115
44124
  {
44116
- name: "create_actionable_event",
44117
- description: "Create an actionable event to track something noticed",
44125
+ name: "get_last_sweep",
44126
+ description: "Get information about the last sweep run of a type",
44118
44127
  category: "assistant",
44119
- keywords: ["event", "actionable", "track", "remember", "log", "decision", "memory"],
44128
+ keywords: ["sweep", "last", "hourly", "morning", "evening", "ritual"],
44120
44129
  defer_loading: false
44121
44130
  },
44122
44131
  {
44123
- name: "list_actionable_events",
44124
- description: "List actionable events by status or channel",
44125
- category: "assistant",
44126
- keywords: ["event", "actionable", "list", "pending", "review", "memory"],
44127
- defer_loading: false
44132
+ name: "list_caldav_accounts",
44133
+ description: "List all CalDAV accounts configured for calendar sync",
44134
+ category: "caldav",
44135
+ keywords: ["caldav", "account", "list", "calendar", "google", "nextcloud"],
44136
+ defer_loading: true
44128
44137
  },
44129
44138
  {
44130
- name: "get_actionable_event",
44131
- description: "Get details of a specific actionable event",
44132
- category: "assistant",
44133
- keywords: ["event", "actionable", "get", "details", "history"],
44134
- defer_loading: false
44139
+ name: "create_caldav_account",
44140
+ description: "Create a new CalDAV account with basic authentication",
44141
+ category: "caldav",
44142
+ keywords: ["caldav", "account", "create", "add", "calendar", "connect"],
44143
+ defer_loading: true
44135
44144
  },
44136
44145
  {
44137
- name: "update_actionable_event",
44138
- description: "Update an actionable event status or link to a task",
44139
- category: "assistant",
44140
- keywords: ["event", "actionable", "update", "status", "link", "task", "log"],
44141
- defer_loading: false
44146
+ name: "delete_caldav_account",
44147
+ description: "Delete a CalDAV account and all its calendars and events",
44148
+ category: "caldav",
44149
+ keywords: ["caldav", "account", "delete", "remove", "disconnect"],
44150
+ defer_loading: true
44142
44151
  },
44143
44152
  {
44144
- name: "get_assistant_stats",
44145
- description: "Get assistant statistics: event counts by status and last sweep times",
44146
- category: "assistant",
44147
- keywords: ["assistant", "stats", "statistics", "events", "sweep", "summary"],
44148
- defer_loading: false
44153
+ name: "sync_caldav_account",
44154
+ description: "Trigger a manual sync for a specific CalDAV account",
44155
+ category: "caldav",
44156
+ keywords: ["caldav", "account", "sync", "refresh", "calendar"],
44157
+ defer_loading: true
44149
44158
  },
44150
44159
  {
44151
- name: "get_last_sweep",
44152
- description: "Get information about the last sweep run of a type",
44153
- category: "assistant",
44154
- keywords: ["sweep", "last", "hourly", "morning", "evening", "ritual"],
44155
- defer_loading: false
44160
+ name: "list_caldav_copy_rules",
44161
+ description: "List all CalDAV copy rules for one-way event replication between calendars",
44162
+ category: "caldav",
44163
+ keywords: ["caldav", "copy", "rule", "list", "replicate", "sync", "calendar"],
44164
+ defer_loading: true
44165
+ },
44166
+ {
44167
+ name: "create_caldav_copy_rule",
44168
+ description: "Create a copy rule to replicate events from one calendar to another",
44169
+ category: "caldav",
44170
+ keywords: ["caldav", "copy", "rule", "create", "replicate", "calendar"],
44171
+ defer_loading: true
44172
+ },
44173
+ {
44174
+ name: "delete_caldav_copy_rule",
44175
+ description: "Delete a CalDAV copy rule",
44176
+ category: "caldav",
44177
+ keywords: ["caldav", "copy", "rule", "delete", "remove"],
44178
+ defer_loading: true
44179
+ },
44180
+ {
44181
+ name: "execute_caldav_copy_rule",
44182
+ description: "Manually execute a copy rule to replicate events now",
44183
+ category: "caldav",
44184
+ keywords: ["caldav", "copy", "rule", "execute", "run", "replicate"],
44185
+ defer_loading: true
44156
44186
  },
44157
44187
  {
44158
44188
  name: "list_calendars",
@@ -44683,6 +44713,16 @@ var registerTaskTools = (server, client) => {
44683
44713
  return handleToolError(err);
44684
44714
  }
44685
44715
  });
44716
+ server.tool("delete_tag", "Delete a tag from the database. This removes the tag and all its associations with tasks and projects.", {
44717
+ tag: exports_external.string().describe("The exact name of the tag to delete")
44718
+ }, async ({ tag }) => {
44719
+ try {
44720
+ await client.deleteTag(tag);
44721
+ return formatSuccess({ deleted: tag });
44722
+ } catch (err) {
44723
+ return handleToolError(err);
44724
+ }
44725
+ });
44686
44726
  server.tool("list_tasks_by_due_date", "List tasks within a date range based on due date", {
44687
44727
  startDate: exports_external.optional(exports_external.string()).describe("Start date (YYYY-MM-DD), inclusive"),
44688
44728
  endDate: exports_external.optional(exports_external.string()).describe("End date (YYYY-MM-DD), inclusive"),
@@ -45615,8 +45655,8 @@ var init_email = __esm(() => {
45615
45655
  init_utils();
45616
45656
  });
45617
45657
 
45618
- // cli/src/mcp/tools/assistant-events.ts
45619
- var ActionableEventStatusSchema, ChannelSchema, registerAssistantEventTools = (server, client) => {
45658
+ // cli/src/mcp/tools/assistant.ts
45659
+ var ChannelSchema, registerAssistantTools = (server, client) => {
45620
45660
  server.tool("message", "Send a message to a messaging channel (email, WhatsApp, etc.). Use this to reply to messages or send proactive communications.", {
45621
45661
  channel: ChannelSchema.describe("Target channel: email, whatsapp, discord, telegram, slack, or all"),
45622
45662
  to: exports_external.string().describe("Recipient (email address, phone number, or channel ID)"),
@@ -45639,102 +45679,112 @@ var ActionableEventStatusSchema, ChannelSchema, registerAssistantEventTools = (s
45639
45679
  return handleToolError(err);
45640
45680
  }
45641
45681
  });
45642
- server.tool("create_actionable_event", "Create an actionable event to track something noticed (message, request, etc.). Use this to log decisions and maintain memory of things that need attention.", {
45643
- source_channel: ChannelSchema.exclude(["all"]).describe("Channel where the event originated"),
45644
- source_id: exports_external.string().describe("ID of the source message/email"),
45645
- source_metadata: exports_external.optional(exports_external.record(exports_external.string(), exports_external.any())).describe("Additional context (sender, subject, etc.)"),
45646
- summary: exports_external.optional(exports_external.string()).describe("AI-generated description of what this event is about"),
45647
- status: exports_external.optional(ActionableEventStatusSchema).describe("Event status (default: pending)"),
45648
- linked_task_id: exports_external.optional(exports_external.string()).describe("Fulcrum task ID if this event relates to a task")
45649
- }, async ({ source_channel, source_id, source_metadata, summary, status, linked_task_id }) => {
45682
+ server.tool("get_last_sweep", "Get information about the last sweep run of a specific type. Useful for context about what was last reviewed.", {
45683
+ type: exports_external.enum(["hourly", "morning_ritual", "evening_ritual"]).describe("Type of sweep")
45684
+ }, async ({ type }) => {
45650
45685
  try {
45651
- const result = await client.createActionableEvent({
45652
- sourceChannel: source_channel,
45653
- sourceId: source_id,
45654
- sourceMetadata: source_metadata,
45655
- summary,
45656
- status,
45657
- linkedTaskId: linked_task_id
45658
- });
45659
- return formatSuccess(result);
45686
+ const result = await client.getLastSweepRun(type);
45687
+ return formatSuccess(result || { message: "No sweep of this type has run yet" });
45660
45688
  } catch (err) {
45661
45689
  return handleToolError(err);
45662
45690
  }
45663
45691
  });
45664
- server.tool("list_actionable_events", "List actionable events. Use this to review what needs attention, check for patterns, or avoid creating duplicates.", {
45665
- status: exports_external.optional(ActionableEventStatusSchema).describe("Filter by status"),
45666
- source_channel: exports_external.optional(exports_external.string()).describe("Filter by source channel"),
45667
- limit: exports_external.optional(exports_external.number()).describe("Maximum events to return (default: 50)")
45668
- }, async ({ status, source_channel, limit }) => {
45692
+ };
45693
+ var init_assistant = __esm(() => {
45694
+ init_zod2();
45695
+ init_utils();
45696
+ ChannelSchema = exports_external.enum(["email", "whatsapp", "discord", "telegram", "slack", "all"]);
45697
+ });
45698
+
45699
+ // cli/src/mcp/tools/caldav.ts
45700
+ var registerCaldavTools = (server, client) => {
45701
+ server.tool("list_caldav_accounts", "List all CalDAV accounts configured for calendar sync.", {}, async () => {
45669
45702
  try {
45670
- const result = await client.listActionableEvents({
45671
- status,
45672
- channel: source_channel,
45673
- limit: limit ?? 50
45674
- });
45675
- return formatSuccess(result);
45703
+ const accounts = await client.listCaldavAccounts();
45704
+ return formatSuccess(accounts);
45676
45705
  } catch (err) {
45677
45706
  return handleToolError(err);
45678
45707
  }
45679
45708
  });
45680
- server.tool("get_actionable_event", "Get details of a specific actionable event including its action log and linked task.", {
45681
- id: exports_external.string().describe("Event ID")
45709
+ server.tool("create_caldav_account", "Create a new CalDAV account with basic authentication.", {
45710
+ name: exports_external.string().describe("Display name for the account"),
45711
+ serverUrl: exports_external.string().describe("CalDAV server URL"),
45712
+ username: exports_external.string().describe("Username for authentication"),
45713
+ password: exports_external.string().describe("Password for authentication"),
45714
+ syncIntervalMinutes: exports_external.optional(exports_external.number()).describe("Sync interval in minutes (default: 15)")
45715
+ }, async (input) => {
45716
+ try {
45717
+ const account = await client.createCaldavAccount(input);
45718
+ return formatSuccess(account);
45719
+ } catch (err) {
45720
+ return handleToolError(err);
45721
+ }
45722
+ });
45723
+ server.tool("delete_caldav_account", "Delete a CalDAV account and all its calendars and events.", {
45724
+ id: exports_external.string().describe("Account ID to delete")
45682
45725
  }, async ({ id }) => {
45683
45726
  try {
45684
- const result = await client.getActionableEvent(id);
45727
+ const result = await client.deleteCaldavAccount(id);
45685
45728
  return formatSuccess(result);
45686
45729
  } catch (err) {
45687
45730
  return handleToolError(err);
45688
45731
  }
45689
45732
  });
45690
- server.tool("update_actionable_event", "Update an actionable event status, link it to a task, or add to its action log. Use action_log_entry to record decisions/actions taken.", {
45691
- id: exports_external.string().describe("Event ID"),
45692
- status: exports_external.optional(ActionableEventStatusSchema).describe("New status"),
45693
- linked_task_id: exports_external.optional(exports_external.string()).describe("Link to a Fulcrum task (use empty string to unlink)"),
45694
- action_log_entry: exports_external.optional(exports_external.string()).describe('Action to log (e.g., "Replied with project update")')
45695
- }, async ({ id, status, linked_task_id, action_log_entry }) => {
45733
+ server.tool("sync_caldav_account", "Trigger a manual sync for a specific CalDAV account.", {
45734
+ id: exports_external.string().describe("Account ID to sync")
45735
+ }, async ({ id }) => {
45696
45736
  try {
45697
- const result = await client.updateActionableEvent(id, {
45698
- status,
45699
- linkedTaskId: linked_task_id === "" ? null : linked_task_id,
45700
- actionLogEntry: action_log_entry
45701
- });
45737
+ const result = await client.syncCaldavAccount(id);
45702
45738
  return formatSuccess(result);
45703
45739
  } catch (err) {
45704
45740
  return handleToolError(err);
45705
45741
  }
45706
45742
  });
45707
- server.tool("get_assistant_stats", "Get assistant statistics: event counts by status and last sweep times. Useful for understanding workload and activity.", {}, async () => {
45743
+ server.tool("list_caldav_copy_rules", "List all CalDAV copy rules for one-way event replication between calendars.", {}, async () => {
45744
+ try {
45745
+ const rules = await client.listCaldavCopyRules();
45746
+ return formatSuccess(rules);
45747
+ } catch (err) {
45748
+ return handleToolError(err);
45749
+ }
45750
+ });
45751
+ server.tool("create_caldav_copy_rule", "Create a copy rule to replicate events from one calendar to another.", {
45752
+ sourceCalendarId: exports_external.string().describe("Source calendar ID"),
45753
+ destCalendarId: exports_external.string().describe("Destination calendar ID"),
45754
+ name: exports_external.optional(exports_external.string()).describe("Optional label for the rule")
45755
+ }, async (input) => {
45756
+ try {
45757
+ const rule = await client.createCaldavCopyRule(input);
45758
+ return formatSuccess(rule);
45759
+ } catch (err) {
45760
+ return handleToolError(err);
45761
+ }
45762
+ });
45763
+ server.tool("delete_caldav_copy_rule", "Delete a CalDAV copy rule.", {
45764
+ id: exports_external.string().describe("Copy rule ID to delete")
45765
+ }, async ({ id }) => {
45708
45766
  try {
45709
- const result = await client.getAssistantStats();
45767
+ const result = await client.deleteCaldavCopyRule(id);
45710
45768
  return formatSuccess(result);
45711
45769
  } catch (err) {
45712
45770
  return handleToolError(err);
45713
45771
  }
45714
45772
  });
45715
- server.tool("get_last_sweep", "Get information about the last sweep run of a specific type. Useful for context about what was last reviewed.", {
45716
- type: exports_external.enum(["hourly", "morning_ritual", "evening_ritual"]).describe("Type of sweep")
45717
- }, async ({ type }) => {
45773
+ server.tool("execute_caldav_copy_rule", "Manually execute a copy rule to replicate events now.", {
45774
+ id: exports_external.string().describe("Copy rule ID to execute")
45775
+ }, async ({ id }) => {
45718
45776
  try {
45719
- const result = await client.getLastSweepRun(type);
45720
- return formatSuccess(result || { message: "No sweep of this type has run yet" });
45777
+ const result = await client.executeCaldavCopyRule(id);
45778
+ return formatSuccess(result);
45721
45779
  } catch (err) {
45722
45780
  return handleToolError(err);
45723
45781
  }
45724
45782
  });
45725
- };
45726
- var init_assistant_events = __esm(() => {
45727
- init_zod2();
45728
- init_utils();
45729
- ActionableEventStatusSchema = exports_external.enum(["pending", "acted_upon", "dismissed", "monitoring"]);
45730
- ChannelSchema = exports_external.enum(["email", "whatsapp", "discord", "telegram", "slack", "all"]);
45731
- });
45732
-
45733
- // cli/src/mcp/tools/caldav.ts
45734
- var registerCaldavTools = (server, client) => {
45735
- server.tool("list_calendars", "List all CalDAV calendars synced from the configured server.", {}, async () => {
45783
+ server.tool("list_calendars", "List all CalDAV calendars synced from the configured server.", {
45784
+ accountId: exports_external.optional(exports_external.string()).describe("Filter by account ID")
45785
+ }, async ({ accountId }) => {
45736
45786
  try {
45737
- const calendars = await client.listCalendars();
45787
+ const calendars = await client.listCalendars(accountId);
45738
45788
  return formatSuccess(calendars);
45739
45789
  } catch (err) {
45740
45790
  return handleToolError(err);
@@ -45884,7 +45934,7 @@ function registerTools(server, client) {
45884
45934
  registerSettingsTools(server, client);
45885
45935
  registerBackupTools(server, client);
45886
45936
  registerEmailTools(server, client);
45887
- registerAssistantEventTools(server, client);
45937
+ registerAssistantTools(server, client);
45888
45938
  registerCaldavTools(server, client);
45889
45939
  registerMemoryTools(server, client);
45890
45940
  }
@@ -45900,7 +45950,7 @@ var init_tools = __esm(() => {
45900
45950
  init_settings();
45901
45951
  init_backup();
45902
45952
  init_email();
45903
- init_assistant_events();
45953
+ init_assistant();
45904
45954
  init_caldav();
45905
45955
  init_memory();
45906
45956
  init_types4();
@@ -45921,7 +45971,7 @@ async function runMcpServer(urlOverride, portOverride) {
45921
45971
  const client = new FulcrumClient(urlOverride, portOverride);
45922
45972
  const server = new McpServer({
45923
45973
  name: "fulcrum",
45924
- version: "2.8.2"
45974
+ version: "2.10.0"
45925
45975
  });
45926
45976
  registerTools(server, client);
45927
45977
  const transport = new StdioServerTransport;
@@ -48270,7 +48320,7 @@ var marketplace_default = `{
48270
48320
  "name": "fulcrum",
48271
48321
  "source": "./",
48272
48322
  "description": "Task orchestration for Claude Code",
48273
- "version": "2.8.2",
48323
+ "version": "2.10.0",
48274
48324
  "skills": [
48275
48325
  "./skills/fulcrum"
48276
48326
  ],
@@ -49458,7 +49508,7 @@ function compareVersions(v1, v2) {
49458
49508
  var package_default = {
49459
49509
  name: "@knowsuchagency/fulcrum",
49460
49510
  private: true,
49461
- version: "2.8.2",
49511
+ version: "2.10.0",
49462
49512
  description: "Harness Attention. Orchestrate Agents. Ship.",
49463
49513
  license: "PolyForm-Perimeter-1.0.0",
49464
49514
  type: "module",