@knowsuchagency/fulcrum 3.2.1 → 3.4.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/bin/fulcrum.js +183 -78
- package/dist/assets/{index-Ck5YiSQm.css → index-B2M7Gsbw.css} +1 -1
- package/dist/assets/{index-Dr24efhZ.js → index-Cbt5USzt.js} +136 -136
- package/dist/index.html +2 -2
- package/drizzle/0060_add_claude_session_id.sql +1 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/server/index.js +821 -314
package/bin/fulcrum.js
CHANGED
|
@@ -1710,6 +1710,14 @@ class FulcrumClient {
|
|
|
1710
1710
|
params.set("conversationProvider", input.conversationProvider);
|
|
1711
1711
|
if (input.conversationProjectId)
|
|
1712
1712
|
params.set("conversationProjectId", input.conversationProjectId);
|
|
1713
|
+
if (input.gmailFrom)
|
|
1714
|
+
params.set("gmailFrom", input.gmailFrom);
|
|
1715
|
+
if (input.gmailTo)
|
|
1716
|
+
params.set("gmailTo", input.gmailTo);
|
|
1717
|
+
if (input.gmailAfter)
|
|
1718
|
+
params.set("gmailAfter", input.gmailAfter);
|
|
1719
|
+
if (input.gmailBefore)
|
|
1720
|
+
params.set("gmailBefore", input.gmailBefore);
|
|
1713
1721
|
return this.fetch(`/api/search?${params.toString()}`);
|
|
1714
1722
|
}
|
|
1715
1723
|
}
|
|
@@ -44343,6 +44351,27 @@ var init_registry = __esm(() => {
|
|
|
44343
44351
|
keywords: ["memory", "store", "save", "remember", "knowledge", "persist", "fact"],
|
|
44344
44352
|
defer_loading: false
|
|
44345
44353
|
},
|
|
44354
|
+
{
|
|
44355
|
+
name: "memory_search",
|
|
44356
|
+
description: "Search persistent memories using full-text search (FTS5)",
|
|
44357
|
+
category: "memory",
|
|
44358
|
+
keywords: ["memory", "search", "find", "query", "fts", "recall", "knowledge"],
|
|
44359
|
+
defer_loading: false
|
|
44360
|
+
},
|
|
44361
|
+
{
|
|
44362
|
+
name: "memory_list",
|
|
44363
|
+
description: "List persistent memories with optional tag filter",
|
|
44364
|
+
category: "memory",
|
|
44365
|
+
keywords: ["memory", "list", "browse", "tags", "filter", "all"],
|
|
44366
|
+
defer_loading: false
|
|
44367
|
+
},
|
|
44368
|
+
{
|
|
44369
|
+
name: "memory_delete",
|
|
44370
|
+
description: "Delete a persistent memory by ID",
|
|
44371
|
+
category: "memory",
|
|
44372
|
+
keywords: ["memory", "delete", "remove", "clean", "resolved", "outdated"],
|
|
44373
|
+
defer_loading: false
|
|
44374
|
+
},
|
|
44346
44375
|
{
|
|
44347
44376
|
name: "memory_file_read",
|
|
44348
44377
|
description: "Read the master memory file (MEMORY.md)",
|
|
@@ -44359,9 +44388,9 @@ var init_registry = __esm(() => {
|
|
|
44359
44388
|
},
|
|
44360
44389
|
{
|
|
44361
44390
|
name: "search",
|
|
44362
|
-
description: "Search across all Fulcrum entities (tasks, projects, messages, events, memories) using full-text search",
|
|
44391
|
+
description: "Search across all Fulcrum entities (tasks, projects, messages, events, memories, gmail) using full-text search",
|
|
44363
44392
|
category: "core",
|
|
44364
|
-
keywords: ["search", "find", "query", "fts", "full-text", "task", "project", "message", "event", "memory", "recall", "knowledge"],
|
|
44393
|
+
keywords: ["search", "find", "query", "fts", "full-text", "task", "project", "message", "event", "memory", "recall", "knowledge", "gmail", "email", "google"],
|
|
44365
44394
|
defer_loading: false
|
|
44366
44395
|
},
|
|
44367
44396
|
{
|
|
@@ -44456,7 +44485,7 @@ function getTodayInTimezone(timezone) {
|
|
|
44456
44485
|
|
|
44457
44486
|
// cli/src/mcp/tools/tasks.ts
|
|
44458
44487
|
import { basename as basename2 } from "path";
|
|
44459
|
-
|
|
44488
|
+
function registerListTasks(server, client) {
|
|
44460
44489
|
server.tool("list_tasks", "List all Fulcrum tasks with flexible filtering. Supports text search across title/tags/project, multi-tag filtering (OR logic), multi-status filtering, date range, and overdue detection.", {
|
|
44461
44490
|
status: exports_external.optional(TaskStatusSchema2).describe("Filter by single task status (use statuses for multiple)"),
|
|
44462
44491
|
statuses: exports_external.optional(exports_external.array(TaskStatusSchema2)).describe("Filter by multiple statuses (OR logic)"),
|
|
@@ -44548,20 +44577,8 @@ var registerTaskTools = (server, client) => {
|
|
|
44548
44577
|
return handleToolError(err);
|
|
44549
44578
|
}
|
|
44550
44579
|
});
|
|
44551
|
-
|
|
44552
|
-
|
|
44553
|
-
}, async ({ id }) => {
|
|
44554
|
-
try {
|
|
44555
|
-
const [task, dependencies, attachments] = await Promise.all([
|
|
44556
|
-
client.getTask(id),
|
|
44557
|
-
client.getTaskDependencies(id),
|
|
44558
|
-
client.listTaskAttachments(id)
|
|
44559
|
-
]);
|
|
44560
|
-
return formatSuccess({ ...task, dependencies, attachments });
|
|
44561
|
-
} catch (err) {
|
|
44562
|
-
return handleToolError(err);
|
|
44563
|
-
}
|
|
44564
|
-
});
|
|
44580
|
+
}
|
|
44581
|
+
function registerCreateTask(server, client) {
|
|
44565
44582
|
server.tool("create_task", "Create a new task. For worktree tasks, provide repoPath to create a git worktree. For non-worktree tasks, omit repoPath. When tags are provided, returns all existing tags for reference.", {
|
|
44566
44583
|
title: exports_external.string().describe("Task title"),
|
|
44567
44584
|
repoPath: exports_external.optional(exports_external.string()).describe("Absolute path to the git repository (optional for non-worktree tasks)"),
|
|
@@ -44622,6 +44639,8 @@ var registerTaskTools = (server, client) => {
|
|
|
44622
44639
|
return handleToolError(err);
|
|
44623
44640
|
}
|
|
44624
44641
|
});
|
|
44642
|
+
}
|
|
44643
|
+
function registerUpdateTask(server, client) {
|
|
44625
44644
|
server.tool("update_task", "Update task metadata (title or description)", {
|
|
44626
44645
|
id: exports_external.string().describe("Task ID"),
|
|
44627
44646
|
title: exports_external.optional(exports_external.string()).describe("New title"),
|
|
@@ -44639,6 +44658,82 @@ var registerTaskTools = (server, client) => {
|
|
|
44639
44658
|
return handleToolError(err);
|
|
44640
44659
|
}
|
|
44641
44660
|
});
|
|
44661
|
+
}
|
|
44662
|
+
function registerAddTaskLink(server, client) {
|
|
44663
|
+
server.tool("add_task_link", "Add a URL link to a task (for documentation, related PRs, design files, etc.)", {
|
|
44664
|
+
taskId: exports_external.string().describe("Task ID"),
|
|
44665
|
+
url: exports_external.string().url().describe("URL to add"),
|
|
44666
|
+
label: exports_external.optional(exports_external.string()).describe("Display label (auto-detected if not provided)")
|
|
44667
|
+
}, async ({ taskId, url: url2, label }) => {
|
|
44668
|
+
try {
|
|
44669
|
+
const link = await client.addTaskLink(taskId, url2, label);
|
|
44670
|
+
return formatSuccess(link);
|
|
44671
|
+
} catch (err) {
|
|
44672
|
+
return handleToolError(err);
|
|
44673
|
+
}
|
|
44674
|
+
});
|
|
44675
|
+
}
|
|
44676
|
+
function registerAddTaskTag(server, client) {
|
|
44677
|
+
server.tool("add_task_tag", "Add a tag to a task for categorization. Returns similar existing tags to help catch typos.", {
|
|
44678
|
+
taskId: exports_external.string().describe("Task ID"),
|
|
44679
|
+
tag: exports_external.string().describe("Tag to add")
|
|
44680
|
+
}, async ({ taskId, tag }) => {
|
|
44681
|
+
try {
|
|
44682
|
+
const result = await client.addTaskTag(taskId, tag);
|
|
44683
|
+
const allTasks = await client.listTasks();
|
|
44684
|
+
const existingTags = new Set;
|
|
44685
|
+
for (const t2 of allTasks) {
|
|
44686
|
+
if (t2.tags) {
|
|
44687
|
+
for (const tg of t2.tags) {
|
|
44688
|
+
existingTags.add(tg);
|
|
44689
|
+
}
|
|
44690
|
+
}
|
|
44691
|
+
}
|
|
44692
|
+
const tagLower = tag.toLowerCase();
|
|
44693
|
+
const similarTags = Array.from(existingTags).filter((tg) => tg !== tag && (tg.toLowerCase().includes(tagLower) || tagLower.includes(tg.toLowerCase())));
|
|
44694
|
+
return formatSuccess({
|
|
44695
|
+
...result,
|
|
44696
|
+
similarTags: similarTags.length > 0 ? similarTags : undefined
|
|
44697
|
+
});
|
|
44698
|
+
} catch (err) {
|
|
44699
|
+
return handleToolError(err);
|
|
44700
|
+
}
|
|
44701
|
+
});
|
|
44702
|
+
}
|
|
44703
|
+
function registerSetTaskDueDate(server, client) {
|
|
44704
|
+
server.tool("set_task_due_date", "Set or clear the due date for a task", {
|
|
44705
|
+
taskId: exports_external.string().describe("Task ID"),
|
|
44706
|
+
dueDate: exports_external.nullable(exports_external.string()).describe("Due date in YYYY-MM-DD format, or null to clear")
|
|
44707
|
+
}, async ({ taskId, dueDate }) => {
|
|
44708
|
+
try {
|
|
44709
|
+
const result = await client.setTaskDueDate(taskId, dueDate);
|
|
44710
|
+
return formatSuccess(result);
|
|
44711
|
+
} catch (err) {
|
|
44712
|
+
return handleToolError(err);
|
|
44713
|
+
}
|
|
44714
|
+
});
|
|
44715
|
+
}
|
|
44716
|
+
var registerTaskTools = (server, client) => {
|
|
44717
|
+
registerListTasks(server, client);
|
|
44718
|
+
registerCreateTask(server, client);
|
|
44719
|
+
registerUpdateTask(server, client);
|
|
44720
|
+
registerAddTaskLink(server, client);
|
|
44721
|
+
registerAddTaskTag(server, client);
|
|
44722
|
+
registerSetTaskDueDate(server, client);
|
|
44723
|
+
server.tool("get_task", "Get details of a specific task by ID, including dependencies and attachments", {
|
|
44724
|
+
id: exports_external.string().describe("Task ID (UUID)")
|
|
44725
|
+
}, async ({ id }) => {
|
|
44726
|
+
try {
|
|
44727
|
+
const [task, dependencies, attachments] = await Promise.all([
|
|
44728
|
+
client.getTask(id),
|
|
44729
|
+
client.getTaskDependencies(id),
|
|
44730
|
+
client.listTaskAttachments(id)
|
|
44731
|
+
]);
|
|
44732
|
+
return formatSuccess({ ...task, dependencies, attachments });
|
|
44733
|
+
} catch (err) {
|
|
44734
|
+
return handleToolError(err);
|
|
44735
|
+
}
|
|
44736
|
+
});
|
|
44642
44737
|
server.tool("delete_task", "Delete a task and optionally its linked git worktree", {
|
|
44643
44738
|
id: exports_external.string().describe("Task ID"),
|
|
44644
44739
|
deleteWorktree: exports_external.optional(exports_external.boolean()).describe("Also delete the linked git worktree (default: false)")
|
|
@@ -44663,18 +44758,6 @@ var registerTaskTools = (server, client) => {
|
|
|
44663
44758
|
return handleToolError(err);
|
|
44664
44759
|
}
|
|
44665
44760
|
});
|
|
44666
|
-
server.tool("add_task_link", "Add a URL link to a task (for documentation, related PRs, design files, etc.)", {
|
|
44667
|
-
taskId: exports_external.string().describe("Task ID"),
|
|
44668
|
-
url: exports_external.string().url().describe("URL to add"),
|
|
44669
|
-
label: exports_external.optional(exports_external.string()).describe("Display label (auto-detected if not provided)")
|
|
44670
|
-
}, async ({ taskId, url: url2, label }) => {
|
|
44671
|
-
try {
|
|
44672
|
-
const link = await client.addTaskLink(taskId, url2, label);
|
|
44673
|
-
return formatSuccess(link);
|
|
44674
|
-
} catch (err) {
|
|
44675
|
-
return handleToolError(err);
|
|
44676
|
-
}
|
|
44677
|
-
});
|
|
44678
44761
|
server.tool("remove_task_link", "Remove a URL link from a task", {
|
|
44679
44762
|
taskId: exports_external.string().describe("Task ID"),
|
|
44680
44763
|
linkId: exports_external.string().describe("Link ID to remove")
|
|
@@ -44696,31 +44779,6 @@ var registerTaskTools = (server, client) => {
|
|
|
44696
44779
|
return handleToolError(err);
|
|
44697
44780
|
}
|
|
44698
44781
|
});
|
|
44699
|
-
server.tool("add_task_tag", "Add a tag to a task for categorization. Returns similar existing tags to help catch typos.", {
|
|
44700
|
-
taskId: exports_external.string().describe("Task ID"),
|
|
44701
|
-
tag: exports_external.string().describe("Tag to add")
|
|
44702
|
-
}, async ({ taskId, tag }) => {
|
|
44703
|
-
try {
|
|
44704
|
-
const result = await client.addTaskTag(taskId, tag);
|
|
44705
|
-
const allTasks = await client.listTasks();
|
|
44706
|
-
const existingTags = new Set;
|
|
44707
|
-
for (const t2 of allTasks) {
|
|
44708
|
-
if (t2.tags) {
|
|
44709
|
-
for (const tg of t2.tags) {
|
|
44710
|
-
existingTags.add(tg);
|
|
44711
|
-
}
|
|
44712
|
-
}
|
|
44713
|
-
}
|
|
44714
|
-
const tagLower = tag.toLowerCase();
|
|
44715
|
-
const similarTags = Array.from(existingTags).filter((tg) => tg !== tag && (tg.toLowerCase().includes(tagLower) || tagLower.includes(tg.toLowerCase())));
|
|
44716
|
-
return formatSuccess({
|
|
44717
|
-
...result,
|
|
44718
|
-
similarTags: similarTags.length > 0 ? similarTags : undefined
|
|
44719
|
-
});
|
|
44720
|
-
} catch (err) {
|
|
44721
|
-
return handleToolError(err);
|
|
44722
|
-
}
|
|
44723
|
-
});
|
|
44724
44782
|
server.tool("remove_task_tag", "Remove a tag from a task", {
|
|
44725
44783
|
taskId: exports_external.string().describe("Task ID"),
|
|
44726
44784
|
tag: exports_external.string().describe("Tag to remove")
|
|
@@ -44732,17 +44790,6 @@ var registerTaskTools = (server, client) => {
|
|
|
44732
44790
|
return handleToolError(err);
|
|
44733
44791
|
}
|
|
44734
44792
|
});
|
|
44735
|
-
server.tool("set_task_due_date", "Set or clear the due date for a task", {
|
|
44736
|
-
taskId: exports_external.string().describe("Task ID"),
|
|
44737
|
-
dueDate: exports_external.nullable(exports_external.string()).describe("Due date in YYYY-MM-DD format, or null to clear")
|
|
44738
|
-
}, async ({ taskId, dueDate }) => {
|
|
44739
|
-
try {
|
|
44740
|
-
const result = await client.setTaskDueDate(taskId, dueDate);
|
|
44741
|
-
return formatSuccess(result);
|
|
44742
|
-
} catch (err) {
|
|
44743
|
-
return handleToolError(err);
|
|
44744
|
-
}
|
|
44745
|
-
});
|
|
44746
44793
|
server.tool("get_task_dependencies", "Get the dependencies and dependents of a task, and whether it is blocked", {
|
|
44747
44794
|
taskId: exports_external.string().describe("Task ID")
|
|
44748
44795
|
}, async ({ taskId }) => {
|
|
@@ -45833,8 +45880,9 @@ var ChannelSchema, registerAssistantTools = (server, client) => {
|
|
|
45833
45880
|
subject: exports_external.optional(exports_external.string()).describe("Email subject (for Gmail channel only)"),
|
|
45834
45881
|
replyToMessageId: exports_external.optional(exports_external.string()).describe("Message ID to reply to (for threading)"),
|
|
45835
45882
|
slack_blocks: exports_external.optional(exports_external.array(exports_external.record(exports_external.string(), exports_external.any()))).describe("Slack Block Kit blocks for rich formatting (Slack channel only). Array of block objects."),
|
|
45883
|
+
filePath: exports_external.optional(exports_external.string()).describe("Absolute path to a local file to upload alongside the message (Slack only). Use for sending images, documents, etc."),
|
|
45836
45884
|
googleAccountId: exports_external.optional(exports_external.string()).describe("Google account ID for Gmail channel. If omitted, auto-resolves when exactly one Gmail-enabled account exists.")
|
|
45837
|
-
}, async ({ channel, body, subject, replyToMessageId, slack_blocks, googleAccountId }) => {
|
|
45885
|
+
}, async ({ channel, body, subject, replyToMessageId, slack_blocks, filePath, googleAccountId }) => {
|
|
45838
45886
|
try {
|
|
45839
45887
|
if (channel === "gmail") {
|
|
45840
45888
|
let accountId = googleAccountId;
|
|
@@ -45857,7 +45905,8 @@ var ChannelSchema, registerAssistantTools = (server, client) => {
|
|
|
45857
45905
|
body,
|
|
45858
45906
|
subject,
|
|
45859
45907
|
replyToMessageId,
|
|
45860
|
-
slackBlocks: slack_blocks
|
|
45908
|
+
slackBlocks: slack_blocks,
|
|
45909
|
+
filePath
|
|
45861
45910
|
});
|
|
45862
45911
|
return formatSuccess(result);
|
|
45863
45912
|
} catch (err) {
|
|
@@ -46144,7 +46193,7 @@ var init_types5 = __esm(() => {
|
|
|
46144
46193
|
});
|
|
46145
46194
|
|
|
46146
46195
|
// cli/src/mcp/tools/memory.ts
|
|
46147
|
-
|
|
46196
|
+
function registerMemoryStoreTool(server, client) {
|
|
46148
46197
|
server.tool("memory_store", "Store a piece of knowledge in persistent memory. Use this to remember facts, preferences, decisions, patterns, or any information that should persist across conversations.", {
|
|
46149
46198
|
content: exports_external.string().describe("The memory content to store. Be specific and self-contained."),
|
|
46150
46199
|
tags: exports_external.optional(exports_external.array(exports_external.string())).describe('Optional tags for categorization (e.g., ["preference", "architecture", "decision"])'),
|
|
@@ -46157,6 +46206,52 @@ var registerMemoryTools = (server, client) => {
|
|
|
46157
46206
|
return handleToolError(err);
|
|
46158
46207
|
}
|
|
46159
46208
|
});
|
|
46209
|
+
}
|
|
46210
|
+
function registerMemorySearchTool(server, client) {
|
|
46211
|
+
server.tool("memory_search", 'Search persistent memories using full-text search (FTS5). Supports boolean operators (AND, OR, NOT), phrase matching ("quoted"), and prefix matching (term*).', {
|
|
46212
|
+
query: exports_external.string().describe('Search query. Supports FTS5 syntax: AND, OR, NOT, "phrases", prefix*'),
|
|
46213
|
+
tags: exports_external.optional(exports_external.array(exports_external.string())).describe('Filter by tags (e.g., ["actionable", "preference"])'),
|
|
46214
|
+
limit: exports_external.optional(exports_external.number()).describe("Max results to return (default: 20)")
|
|
46215
|
+
}, async ({ query, tags, limit }) => {
|
|
46216
|
+
try {
|
|
46217
|
+
const result = await client.searchMemories({ query, tags, limit });
|
|
46218
|
+
return formatSuccess(result);
|
|
46219
|
+
} catch (err) {
|
|
46220
|
+
return handleToolError(err);
|
|
46221
|
+
}
|
|
46222
|
+
});
|
|
46223
|
+
}
|
|
46224
|
+
function registerMemoryListTool(server, client) {
|
|
46225
|
+
server.tool("memory_list", "List all persistent memories, optionally filtered by tags. Returns memories sorted by creation date (newest first).", {
|
|
46226
|
+
tags: exports_external.optional(exports_external.array(exports_external.string())).describe('Filter by tags (e.g., ["actionable"])'),
|
|
46227
|
+
limit: exports_external.optional(exports_external.number()).describe("Max results to return (default: 50)"),
|
|
46228
|
+
offset: exports_external.optional(exports_external.number()).describe("Offset for pagination")
|
|
46229
|
+
}, async ({ tags, limit, offset }) => {
|
|
46230
|
+
try {
|
|
46231
|
+
const result = await client.listMemories({ tags, limit, offset });
|
|
46232
|
+
return formatSuccess(result);
|
|
46233
|
+
} catch (err) {
|
|
46234
|
+
return handleToolError(err);
|
|
46235
|
+
}
|
|
46236
|
+
});
|
|
46237
|
+
}
|
|
46238
|
+
function registerMemoryDeleteTool(server, client) {
|
|
46239
|
+
server.tool("memory_delete", "Delete a persistent memory by ID. Use this to clean up resolved or outdated memories.", {
|
|
46240
|
+
id: exports_external.string().describe("The ID of the memory to delete")
|
|
46241
|
+
}, async ({ id }) => {
|
|
46242
|
+
try {
|
|
46243
|
+
const result = await client.deleteMemory(id);
|
|
46244
|
+
return formatSuccess(result);
|
|
46245
|
+
} catch (err) {
|
|
46246
|
+
return handleToolError(err);
|
|
46247
|
+
}
|
|
46248
|
+
});
|
|
46249
|
+
}
|
|
46250
|
+
var registerMemoryTools = (server, client) => {
|
|
46251
|
+
registerMemoryStoreTool(server, client);
|
|
46252
|
+
registerMemorySearchTool(server, client);
|
|
46253
|
+
registerMemoryListTool(server, client);
|
|
46254
|
+
registerMemoryDeleteTool(server, client);
|
|
46160
46255
|
};
|
|
46161
46256
|
var init_memory = __esm(() => {
|
|
46162
46257
|
init_zod2();
|
|
@@ -46165,7 +46260,7 @@ var init_memory = __esm(() => {
|
|
|
46165
46260
|
});
|
|
46166
46261
|
|
|
46167
46262
|
// cli/src/mcp/tools/memory-file.ts
|
|
46168
|
-
var
|
|
46263
|
+
var registerMemoryFileReadTool = (server, client) => {
|
|
46169
46264
|
server.tool("memory_file_read", "Read the master memory file (MEMORY.md). This file contains persistent knowledge, user preferences, and instructions that are included in every conversation.", {}, async () => {
|
|
46170
46265
|
try {
|
|
46171
46266
|
const result = await client.readMemoryFile();
|
|
@@ -46174,6 +46269,8 @@ var registerMemoryFileTools = (server, client) => {
|
|
|
46174
46269
|
return handleToolError(err);
|
|
46175
46270
|
}
|
|
46176
46271
|
});
|
|
46272
|
+
}, registerMemoryFileTools = (server, client) => {
|
|
46273
|
+
registerMemoryFileReadTool(server, client);
|
|
46177
46274
|
server.tool("memory_file_update", "Update the master memory file. Provide full content to replace the entire file, or specify a section heading to update just that section. The memory file is included in every conversation, so keep it organized and concise.", {
|
|
46178
46275
|
content: exports_external.string().describe("The content to write. If section is specified, this replaces only that section body."),
|
|
46179
46276
|
section: exports_external.optional(exports_external.string()).describe('Optional markdown heading (e.g., "## Preferences") to update a specific section. If omitted, replaces the entire file.')
|
|
@@ -46215,7 +46312,7 @@ var init_messaging = __esm(() => {
|
|
|
46215
46312
|
|
|
46216
46313
|
// cli/src/mcp/tools/search.ts
|
|
46217
46314
|
var EntityTypeSchema, registerSearchTools = (server, client) => {
|
|
46218
|
-
server.tool("search", 'Search across all Fulcrum entities (tasks, projects, messages, calendar events, memories, conversations) using full-text search. Supports boolean operators (AND, OR, NOT), phrase matching ("quoted phrases"), and prefix matching (term*). Returns results ranked by relevance.', {
|
|
46315
|
+
server.tool("search", 'Search across all Fulcrum entities (tasks, projects, messages, calendar events, memories, conversations) using full-text search. Supports boolean operators (AND, OR, NOT), phrase matching ("quoted phrases"), and prefix matching (term*). Returns results ranked by relevance. Gmail search is opt-in: include "gmail" in entities to search Gmail via API (not included in default searches).', {
|
|
46219
46316
|
query: exports_external.string().describe('FTS5 search query. Supports: AND, OR, NOT operators, "quoted phrases", prefix* matching. Example: "kubernetes deployment" OR k8s'),
|
|
46220
46317
|
entities: exports_external.optional(exports_external.array(EntityTypeSchema)).describe("Entity types to search. Defaults to all: tasks, projects, messages, events, memories, conversations"),
|
|
46221
46318
|
limit: exports_external.optional(exports_external.number()).describe("Maximum results per entity type (default: 10)"),
|
|
@@ -46228,8 +46325,12 @@ var EntityTypeSchema, registerSearchTools = (server, client) => {
|
|
|
46228
46325
|
memoryTags: exports_external.optional(exports_external.array(exports_external.string())).describe("Filter memories by tags"),
|
|
46229
46326
|
conversationRole: exports_external.optional(exports_external.string()).describe('Filter conversations by role (e.g., "user", "assistant")'),
|
|
46230
46327
|
conversationProvider: exports_external.optional(exports_external.string()).describe('Filter conversations by provider (e.g., "claude", "opencode")'),
|
|
46231
|
-
conversationProjectId: exports_external.optional(exports_external.string()).describe("Filter conversations by project ID")
|
|
46232
|
-
|
|
46328
|
+
conversationProjectId: exports_external.optional(exports_external.string()).describe("Filter conversations by project ID"),
|
|
46329
|
+
gmailFrom: exports_external.optional(exports_external.string()).describe('Filter Gmail results by sender (e.g., "user@example.com")'),
|
|
46330
|
+
gmailTo: exports_external.optional(exports_external.string()).describe('Filter Gmail results by recipient (e.g., "user@example.com")'),
|
|
46331
|
+
gmailAfter: exports_external.optional(exports_external.string()).describe("Filter Gmail results after this date (YYYY/MM/DD format)"),
|
|
46332
|
+
gmailBefore: exports_external.optional(exports_external.string()).describe("Filter Gmail results before this date (YYYY/MM/DD format)")
|
|
46333
|
+
}, async ({ query, entities, limit, taskStatus, projectStatus, messageChannel, messageDirection, eventFrom, eventTo, memoryTags, conversationRole, conversationProvider, conversationProjectId, gmailFrom, gmailTo, gmailAfter, gmailBefore }) => {
|
|
46233
46334
|
try {
|
|
46234
46335
|
const results = await client.search({
|
|
46235
46336
|
query,
|
|
@@ -46244,7 +46345,11 @@ var EntityTypeSchema, registerSearchTools = (server, client) => {
|
|
|
46244
46345
|
memoryTags,
|
|
46245
46346
|
conversationRole,
|
|
46246
46347
|
conversationProvider,
|
|
46247
|
-
conversationProjectId
|
|
46348
|
+
conversationProjectId,
|
|
46349
|
+
gmailFrom,
|
|
46350
|
+
gmailTo,
|
|
46351
|
+
gmailAfter,
|
|
46352
|
+
gmailBefore
|
|
46248
46353
|
});
|
|
46249
46354
|
return formatSuccess(results);
|
|
46250
46355
|
} catch (err) {
|
|
@@ -46255,7 +46360,7 @@ var EntityTypeSchema, registerSearchTools = (server, client) => {
|
|
|
46255
46360
|
var init_search = __esm(() => {
|
|
46256
46361
|
init_zod2();
|
|
46257
46362
|
init_utils();
|
|
46258
|
-
EntityTypeSchema = exports_external.enum(["tasks", "projects", "messages", "events", "memories", "conversations"]);
|
|
46363
|
+
EntityTypeSchema = exports_external.enum(["tasks", "projects", "messages", "events", "memories", "conversations", "gmail"]);
|
|
46259
46364
|
});
|
|
46260
46365
|
|
|
46261
46366
|
// cli/src/mcp/tools/index.ts
|
|
@@ -46316,7 +46421,7 @@ async function runMcpServer(urlOverride, portOverride) {
|
|
|
46316
46421
|
const client = new FulcrumClient(urlOverride, portOverride);
|
|
46317
46422
|
const server = new McpServer({
|
|
46318
46423
|
name: "fulcrum",
|
|
46319
|
-
version: "3.
|
|
46424
|
+
version: "3.4.0"
|
|
46320
46425
|
});
|
|
46321
46426
|
registerTools(server, client);
|
|
46322
46427
|
const transport = new StdioServerTransport;
|
|
@@ -48665,7 +48770,7 @@ var marketplace_default = `{
|
|
|
48665
48770
|
"name": "fulcrum",
|
|
48666
48771
|
"source": "./",
|
|
48667
48772
|
"description": "Task orchestration for Claude Code",
|
|
48668
|
-
"version": "3.
|
|
48773
|
+
"version": "3.4.0",
|
|
48669
48774
|
"skills": [
|
|
48670
48775
|
"./skills/fulcrum"
|
|
48671
48776
|
],
|
|
@@ -49869,7 +49974,7 @@ function compareVersions(v1, v2) {
|
|
|
49869
49974
|
var package_default = {
|
|
49870
49975
|
name: "@knowsuchagency/fulcrum",
|
|
49871
49976
|
private: true,
|
|
49872
|
-
version: "3.
|
|
49977
|
+
version: "3.4.0",
|
|
49873
49978
|
description: "Harness Attention. Orchestrate Agents. Ship.",
|
|
49874
49979
|
license: "PolyForm-Perimeter-1.0.0",
|
|
49875
49980
|
type: "module",
|
|
@@ -49885,7 +49990,7 @@ var package_default = {
|
|
|
49885
49990
|
"db:studio": "drizzle-kit studio"
|
|
49886
49991
|
},
|
|
49887
49992
|
dependencies: {
|
|
49888
|
-
"@anthropic-ai/claude-agent-sdk": "^0.2.
|
|
49993
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.37",
|
|
49889
49994
|
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
|
|
49890
49995
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
|
|
49891
49996
|
"@azurity/pure-nerd-font": "^3.0.5",
|