keepsake-mcp 1.8.0 → 1.9.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 +9 -1
- package/build/tools.js +106 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ rather than in the chat, which disappears.
|
|
|
114
114
|
|--------|-----------|-------------|
|
|
115
115
|
| `review_note` | `note_id` | Act as the editor of a note: read it, judge form and substance, leave anchored remarks in the margin, never rewrite the text |
|
|
116
116
|
|
|
117
|
-
## Available tools (
|
|
117
|
+
## Available tools (71)
|
|
118
118
|
|
|
119
119
|
### Contacts
|
|
120
120
|
| Tool | Description |
|
|
@@ -188,6 +188,14 @@ Material kept *alongside* a note without entering its text — an idea, a refere
|
|
|
188
188
|
| `get_day` | Get a specific day's journal |
|
|
189
189
|
| `update_day` | Create or update a day's journal (upsert) |
|
|
190
190
|
|
|
191
|
+
### Day blocks (Day-view timeline)
|
|
192
|
+
| Tool | Description |
|
|
193
|
+
|------|-------------|
|
|
194
|
+
| `list_day_blocks` | List a day's time blocks, in timeline order |
|
|
195
|
+
| `create_day_block` | Create a block, auto-placed first-fit (or pinned via anchor_time) |
|
|
196
|
+
| `update_day_block` | Update a block (title, duration, anchor, note, done) |
|
|
197
|
+
| `delete_day_block` | Delete a block and prune its timeline ref |
|
|
198
|
+
|
|
191
199
|
### Tags
|
|
192
200
|
| Tool | Description |
|
|
193
201
|
|------|-------------|
|
package/build/tools.js
CHANGED
|
@@ -7,8 +7,14 @@ export function toContent(result) {
|
|
|
7
7
|
: result.error.message || JSON.stringify(result.error);
|
|
8
8
|
return { content: [{ type: "text", text: `Error: ${msg}` }] };
|
|
9
9
|
}
|
|
10
|
+
// List endpoints ship pagination alongside the rows (meta.total / limit /
|
|
11
|
+
// offset). Dropping it forced agents to binary-search offsets just to count
|
|
12
|
+
// an inbox — keep data and meta together whenever meta is present.
|
|
13
|
+
const payload = result.meta !== undefined
|
|
14
|
+
? { data: result.data ?? [], meta: result.meta }
|
|
15
|
+
: (result.data ?? result);
|
|
10
16
|
return {
|
|
11
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
17
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
12
18
|
};
|
|
13
19
|
}
|
|
14
20
|
/** Build query string from optional params, skipping undefined values. */
|
|
@@ -358,6 +364,18 @@ export function registerAllTools(server, fetchApi) {
|
|
|
358
364
|
.positive()
|
|
359
365
|
.optional()
|
|
360
366
|
.describe("Recurrence interval (e.g., every N days)"),
|
|
367
|
+
start_time: z
|
|
368
|
+
.string()
|
|
369
|
+
.regex(/^([01]\d|2[0-3]):[0-5]\d$/)
|
|
370
|
+
.optional()
|
|
371
|
+
.describe("Wall-clock start time HH:MM (24h). A task of the day WITH a time appears anchored on the Day-view timeline; without one it stays in the day's task list."),
|
|
372
|
+
duration_minutes: z
|
|
373
|
+
.number()
|
|
374
|
+
.int()
|
|
375
|
+
.min(1)
|
|
376
|
+
.max(1440)
|
|
377
|
+
.optional()
|
|
378
|
+
.describe("Estimated duration in minutes (Day-view timeline shows 15 by default when a start time is set)"),
|
|
361
379
|
contact_ids: z
|
|
362
380
|
.array(z.string().uuid())
|
|
363
381
|
.optional()
|
|
@@ -383,6 +401,20 @@ export function registerAllTools(server, fetchApi) {
|
|
|
383
401
|
.optional()
|
|
384
402
|
.describe("Date type: specific (has a due date), asap (do as soon as possible), one_day (someday/no rush)"),
|
|
385
403
|
priority: z.enum(["low", "medium", "high"]).optional().describe("Priority level"),
|
|
404
|
+
start_time: z
|
|
405
|
+
.string()
|
|
406
|
+
.regex(/^([01]\d|2[0-3]):[0-5]\d$/)
|
|
407
|
+
.nullable()
|
|
408
|
+
.optional()
|
|
409
|
+
.describe("Wall-clock start time HH:MM (24h) — anchors the task on the Day-view timeline. Pass null to clear it (unschedule)."),
|
|
410
|
+
duration_minutes: z
|
|
411
|
+
.number()
|
|
412
|
+
.int()
|
|
413
|
+
.min(1)
|
|
414
|
+
.max(1440)
|
|
415
|
+
.nullable()
|
|
416
|
+
.optional()
|
|
417
|
+
.describe("Estimated duration in minutes. Pass null to clear."),
|
|
386
418
|
contact_ids: z
|
|
387
419
|
.array(z.string().uuid())
|
|
388
420
|
.optional()
|
|
@@ -566,6 +598,79 @@ export function registerAllTools(server, fetchApi) {
|
|
|
566
598
|
return toContent(await fetchApi("/days", "POST", params));
|
|
567
599
|
});
|
|
568
600
|
// ===========================================================================
|
|
601
|
+
// DAY BLOCKS (Day-view timeline)
|
|
602
|
+
// ===========================================================================
|
|
603
|
+
server.registerTool("list_day_blocks", {
|
|
604
|
+
description: "List the time blocks of a day's timeline (Day view), in timeline order. A block is either an activity (type 'block') or a task bucket (type 'tasks' — groups the day's untimed tasks). The meta carries the day's raw timeline_order: \"b:<uuid>\" refs are blocks, bare uuids are tasks inside a bucket's run.",
|
|
605
|
+
inputSchema: {
|
|
606
|
+
date: z.string().describe("Date (YYYY-MM-DD)"),
|
|
607
|
+
},
|
|
608
|
+
annotations: { title: "List day blocks", readOnlyHint: true, openWorldHint: false },
|
|
609
|
+
}, async ({ date }) => {
|
|
610
|
+
return toContent(await fetchApi(`/day-blocks${qs({ date })}`));
|
|
611
|
+
});
|
|
612
|
+
server.registerTool("create_day_block", {
|
|
613
|
+
description: "Create a time block on a day's timeline. The block is auto-placed in the earliest free gap large enough for it (same first-fit engine as the app); pass anchor_time to pin it at a fixed hour instead. Its \"b:<id>\" ref is inserted into the day's timeline_order for you — never write timeline_order by hand.",
|
|
614
|
+
inputSchema: {
|
|
615
|
+
date: z.string().describe("Date (YYYY-MM-DD)"),
|
|
616
|
+
title: z.string().optional().describe("Block label (e.g. \"Deep work\", \"Lunch\")"),
|
|
617
|
+
type: z
|
|
618
|
+
.enum(["block", "tasks"])
|
|
619
|
+
.optional()
|
|
620
|
+
.describe("'block' = activity (default). 'tasks' = task bucket: a window that gathers the day's untimed tasks."),
|
|
621
|
+
duration_minutes: z
|
|
622
|
+
.number()
|
|
623
|
+
.int()
|
|
624
|
+
.min(1)
|
|
625
|
+
.max(1440)
|
|
626
|
+
.optional()
|
|
627
|
+
.describe("Duration in minutes (default 30 for an activity, 60 for a bucket)"),
|
|
628
|
+
anchor_time: z
|
|
629
|
+
.string()
|
|
630
|
+
.regex(/^([01]\d|2[0-3]):[0-5]\d$/)
|
|
631
|
+
.optional()
|
|
632
|
+
.describe("Pin the block at a fixed wall-clock hour HH:MM (it becomes a wall other blocks flow around). Omit for automatic first-fit placement."),
|
|
633
|
+
note: z.string().optional().describe("Free note attached to the block"),
|
|
634
|
+
},
|
|
635
|
+
annotations: { title: "Create day block", destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
636
|
+
}, async (params) => {
|
|
637
|
+
return toContent(await fetchApi("/day-blocks", "POST", params));
|
|
638
|
+
});
|
|
639
|
+
server.registerTool("update_day_block", {
|
|
640
|
+
description: "Update a time block (title, duration, anchor, note, done). Only send fields you want to change. The block keeps its position in the timeline order.",
|
|
641
|
+
inputSchema: {
|
|
642
|
+
id: z.string().uuid().describe("Block UUID"),
|
|
643
|
+
title: z.string().nullable().optional().describe("Block label"),
|
|
644
|
+
duration_minutes: z
|
|
645
|
+
.number()
|
|
646
|
+
.int()
|
|
647
|
+
.min(1)
|
|
648
|
+
.max(1440)
|
|
649
|
+
.optional()
|
|
650
|
+
.describe("Duration in minutes"),
|
|
651
|
+
anchor_time: z
|
|
652
|
+
.string()
|
|
653
|
+
.regex(/^([01]\d|2[0-3]):[0-5]\d$/)
|
|
654
|
+
.nullable()
|
|
655
|
+
.optional()
|
|
656
|
+
.describe("Fixed wall-clock hour HH:MM. Pass null to unpin (the block flows with the rest again)."),
|
|
657
|
+
note: z.string().nullable().optional().describe("Free note. Pass null to clear."),
|
|
658
|
+
done: z.boolean().optional().describe("Mark the block done (true) or not done (false)"),
|
|
659
|
+
},
|
|
660
|
+
annotations: { title: "Update day block", destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
661
|
+
}, async ({ id, ...body }) => {
|
|
662
|
+
return toContent(await fetchApi(`/day-blocks/${id}`, "PATCH", body));
|
|
663
|
+
});
|
|
664
|
+
server.registerTool("delete_day_block", {
|
|
665
|
+
description: "Delete a time block. Its ref is pruned from the day's timeline_order; for a task bucket, the tasks themselves are untouched (they fall back to the day's computed bucket).",
|
|
666
|
+
inputSchema: {
|
|
667
|
+
id: z.string().uuid().describe("Block UUID"),
|
|
668
|
+
},
|
|
669
|
+
annotations: { title: "Delete day block", destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
670
|
+
}, async ({ id }) => {
|
|
671
|
+
return toContent(await fetchApi(`/day-blocks/${id}`, "DELETE"));
|
|
672
|
+
});
|
|
673
|
+
// ===========================================================================
|
|
569
674
|
// TAGS
|
|
570
675
|
// ===========================================================================
|
|
571
676
|
server.registerTool("list_tags", {
|