@noteplanco/noteplan-mcp 1.1.8 → 1.1.9
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/dist/noteplan/frontmatter-parser.d.ts +2 -2
- package/dist/noteplan/frontmatter-parser.js +2 -2
- package/dist/noteplan/markdown-parser.test.js +92 -0
- package/dist/noteplan/markdown-parser.test.js.map +1 -1
- package/dist/noteplan/sqlite-loader.d.ts +11 -2
- package/dist/noteplan/sqlite-loader.d.ts.map +1 -1
- package/dist/noteplan/sqlite-loader.js +143 -15
- package/dist/noteplan/sqlite-loader.js.map +1 -1
- package/dist/noteplan/sqlite-writer.d.ts.map +1 -1
- package/dist/noteplan/sqlite-writer.js +3 -0
- package/dist/noteplan/sqlite-writer.js.map +1 -1
- package/dist/noteplan/unified-store.d.ts.map +1 -1
- package/dist/noteplan/unified-store.js +8 -1
- package/dist/noteplan/unified-store.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +32 -10
- package/dist/server.js.map +1 -1
- package/dist/tools/events.d.ts +16 -16
- package/dist/tools/events.d.ts.map +1 -1
- package/dist/tools/events.js +17 -2
- package/dist/tools/events.js.map +1 -1
- package/dist/tools/notes.d.ts +253 -30
- package/dist/tools/notes.d.ts.map +1 -1
- package/dist/tools/notes.js +124 -30
- package/dist/tools/notes.js.map +1 -1
- package/dist/tools/notes.test.js +757 -1
- package/dist/tools/notes.test.js.map +1 -1
- package/dist/tools/tasks.d.ts +86 -10
- package/dist/tools/tasks.d.ts.map +1 -1
- package/dist/tools/tasks.js +84 -25
- package/dist/tools/tasks.js.map +1 -1
- package/dist/tools/ui-automation.d.ts +74 -0
- package/dist/tools/ui-automation.d.ts.map +1 -0
- package/dist/tools/ui-automation.js +209 -0
- package/dist/tools/ui-automation.js.map +1 -0
- package/dist/utils/version.d.ts.map +1 -1
- package/dist/utils/version.js +23 -5
- package/dist/utils/version.js.map +1 -1
- package/package.json +1 -1
package/dist/tools/notes.js
CHANGED
|
@@ -69,7 +69,7 @@ function resolveNoteTarget(id, filename, space) {
|
|
|
69
69
|
note,
|
|
70
70
|
};
|
|
71
71
|
}
|
|
72
|
-
function resolveWritableNoteReference(input) {
|
|
72
|
+
export function resolveWritableNoteReference(input) {
|
|
73
73
|
if (input.id && input.id.trim().length > 0) {
|
|
74
74
|
const note = store.getNote({ id: input.id.trim(), space: input.space?.trim() });
|
|
75
75
|
return { note, error: note ? undefined : 'Note not found' };
|
|
@@ -124,7 +124,7 @@ function resolveWritableNoteReference(input) {
|
|
|
124
124
|
error: 'Provide one note reference: id, filename, title, date, or query',
|
|
125
125
|
};
|
|
126
126
|
}
|
|
127
|
-
function getWritableIdentifier(note) {
|
|
127
|
+
export function getWritableIdentifier(note) {
|
|
128
128
|
if (note.source === 'space') {
|
|
129
129
|
return {
|
|
130
130
|
identifier: note.id || note.filename,
|
|
@@ -302,7 +302,11 @@ export const createNoteSchema = z.object({
|
|
|
302
302
|
templateTypes: z.array(z.enum(['empty-note', 'meeting-note', 'project-note', 'calendar-note'])).optional().describe('Template type tags — used when noteType="template"'),
|
|
303
303
|
});
|
|
304
304
|
export const updateNoteSchema = z.object({
|
|
305
|
-
|
|
305
|
+
id: z.string().optional().describe('Note ID (preferred for space notes)'),
|
|
306
|
+
filename: z.string().optional().describe('Filename/path of the note to update'),
|
|
307
|
+
title: z.string().optional().describe('Note title to search for'),
|
|
308
|
+
date: z.string().optional().describe('Date for calendar notes (YYYYMMDD, YYYY-MM-DD, today, tomorrow, yesterday)'),
|
|
309
|
+
query: z.string().optional().describe('Fuzzy note query'),
|
|
306
310
|
space: z.string().optional().describe('Space name or ID to search in'),
|
|
307
311
|
content: z
|
|
308
312
|
.string()
|
|
@@ -323,6 +327,14 @@ export const updateNoteSchema = z.object({
|
|
|
323
327
|
.boolean()
|
|
324
328
|
.optional()
|
|
325
329
|
.describe('Allow replacing note content with empty/blank text (default: false)'),
|
|
330
|
+
}).superRefine((input, ctx) => {
|
|
331
|
+
if (!input.id && !input.filename && !input.title && !input.date && !input.query) {
|
|
332
|
+
ctx.addIssue({
|
|
333
|
+
code: z.ZodIssueCode.custom,
|
|
334
|
+
message: 'Provide one note reference: id, filename, title, date, or query',
|
|
335
|
+
path: ['filename'],
|
|
336
|
+
});
|
|
337
|
+
}
|
|
326
338
|
});
|
|
327
339
|
export const deleteNoteSchema = z.object({
|
|
328
340
|
id: z.string().optional().describe('Note ID (preferred for TeamSpace notes)'),
|
|
@@ -348,6 +360,9 @@ export const deleteNoteSchema = z.object({
|
|
|
348
360
|
export const moveNoteSchema = z.object({
|
|
349
361
|
id: z.string().optional().describe('Note ID (preferred for TeamSpace notes)'),
|
|
350
362
|
filename: z.string().optional().describe('Filename/path of the note to move'),
|
|
363
|
+
title: z.string().optional().describe('Note title to search for'),
|
|
364
|
+
date: z.string().optional().describe('Date for calendar notes (YYYYMMDD, YYYY-MM-DD, today, tomorrow, yesterday)'),
|
|
365
|
+
query: z.string().optional().describe('Fuzzy note query'),
|
|
351
366
|
space: z.string().optional().describe('Space name or ID to search in'),
|
|
352
367
|
destinationFolder: z
|
|
353
368
|
.string()
|
|
@@ -731,29 +746,33 @@ export function updateNote(params) {
|
|
|
731
746
|
error: 'Full note replacement is blocked for noteplan_update_note unless fullReplace=true. Prefer noteplan_search_paragraphs + noteplan_edit_line/insert_content/delete_lines for targeted edits.',
|
|
732
747
|
};
|
|
733
748
|
}
|
|
734
|
-
const
|
|
735
|
-
if (!
|
|
749
|
+
const noteRef = resolveWritableNoteReference(params);
|
|
750
|
+
if (!noteRef.note) {
|
|
736
751
|
return {
|
|
737
752
|
success: false,
|
|
738
|
-
error: 'Note not found',
|
|
753
|
+
error: noteRef.error || 'Note not found',
|
|
754
|
+
candidates: noteRef.candidates,
|
|
739
755
|
};
|
|
740
756
|
}
|
|
757
|
+
const existingNote = noteRef.note;
|
|
741
758
|
if (params.allowEmptyContent !== true && params.content.trim().length === 0) {
|
|
742
759
|
return {
|
|
743
760
|
success: false,
|
|
744
761
|
error: 'Empty content is blocked for noteplan_update_note. Use allowEmptyContent=true to override intentionally.',
|
|
745
762
|
};
|
|
746
763
|
}
|
|
764
|
+
// Use the resolved filename as the confirmation token target for consistency
|
|
765
|
+
const confirmationTarget = existingNote.filename;
|
|
747
766
|
if (isTrueBool(params.dryRun)) {
|
|
748
767
|
const token = issueConfirmationToken({
|
|
749
768
|
tool: 'noteplan_update_note',
|
|
750
|
-
target:
|
|
769
|
+
target: confirmationTarget,
|
|
751
770
|
action: 'full_replace',
|
|
752
771
|
});
|
|
753
772
|
return {
|
|
754
773
|
success: true,
|
|
755
774
|
dryRun: true,
|
|
756
|
-
message: `Dry run: note ${
|
|
775
|
+
message: `Dry run: note ${existingNote.filename} would be fully replaced`,
|
|
757
776
|
note: {
|
|
758
777
|
id: existingNote.id,
|
|
759
778
|
title: existingNote.title,
|
|
@@ -770,7 +789,7 @@ export function updateNote(params) {
|
|
|
770
789
|
}
|
|
771
790
|
const confirmation = validateAndConsumeConfirmationToken(params.confirmationToken, {
|
|
772
791
|
tool: 'noteplan_update_note',
|
|
773
|
-
target:
|
|
792
|
+
target: confirmationTarget,
|
|
774
793
|
action: 'full_replace',
|
|
775
794
|
});
|
|
776
795
|
if (!confirmation.ok) {
|
|
@@ -865,14 +884,16 @@ export function deleteNote(params) {
|
|
|
865
884
|
}
|
|
866
885
|
export function moveNote(params) {
|
|
867
886
|
try {
|
|
868
|
-
const
|
|
869
|
-
if (!
|
|
887
|
+
const noteRef = resolveWritableNoteReference(params);
|
|
888
|
+
if (!noteRef.note) {
|
|
870
889
|
return {
|
|
871
890
|
success: false,
|
|
872
|
-
error: 'Note not found',
|
|
891
|
+
error: noteRef.error || 'Note not found',
|
|
892
|
+
candidates: noteRef.candidates,
|
|
873
893
|
};
|
|
874
894
|
}
|
|
875
|
-
const
|
|
895
|
+
const writable = getWritableIdentifier(noteRef.note);
|
|
896
|
+
const preview = store.previewMoveNote(writable.identifier, params.destinationFolder);
|
|
876
897
|
const confirmationTarget = `${preview.fromFilename}=>${preview.toFilename}::${preview.destinationParentId ?? preview.destinationFolder}`;
|
|
877
898
|
if (isTrueBool(params.dryRun)) {
|
|
878
899
|
const token = issueConfirmationToken({
|
|
@@ -910,7 +931,7 @@ export function moveNote(params) {
|
|
|
910
931
|
error: confirmationFailureMessage('noteplan_move_note', confirmation.reason),
|
|
911
932
|
};
|
|
912
933
|
}
|
|
913
|
-
const moved = store.moveNote(
|
|
934
|
+
const moved = store.moveNote(writable.identifier, params.destinationFolder);
|
|
914
935
|
return {
|
|
915
936
|
success: true,
|
|
916
937
|
message: moved.note.source === 'space'
|
|
@@ -1068,6 +1089,21 @@ export function renameNoteFile(params) {
|
|
|
1068
1089
|
};
|
|
1069
1090
|
}
|
|
1070
1091
|
const renamed = store.renameSpaceNote(writeId, params.newTitle);
|
|
1092
|
+
// Also update the # Title heading in the note content if it matches the old title
|
|
1093
|
+
if (renamed.note.content) {
|
|
1094
|
+
const lines = renamed.note.content.split('\n');
|
|
1095
|
+
const titleLineIndex = lines.findIndex((l) => /^#\s+/.test(l));
|
|
1096
|
+
if (titleLineIndex !== -1) {
|
|
1097
|
+
const oldHeadingTitle = lines[titleLineIndex].replace(/^#\s+/, '');
|
|
1098
|
+
if (oldHeadingTitle === renamed.fromTitle) {
|
|
1099
|
+
lines[titleLineIndex] = `# ${params.newTitle}`;
|
|
1100
|
+
const renamedWriteTarget = getWritableIdentifier(renamed.note);
|
|
1101
|
+
store.updateNote(renamedWriteTarget.identifier, lines.join('\n'), {
|
|
1102
|
+
source: renamedWriteTarget.source,
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1071
1107
|
return {
|
|
1072
1108
|
success: true,
|
|
1073
1109
|
message: `TeamSpace note renamed from "${renamed.fromTitle}" to "${renamed.toTitle}"`,
|
|
@@ -1175,13 +1211,25 @@ export function renameNoteFile(params) {
|
|
|
1175
1211
|
}
|
|
1176
1212
|
// Get note with line numbers
|
|
1177
1213
|
export const getParagraphsSchema = z.object({
|
|
1178
|
-
|
|
1214
|
+
id: z.string().optional().describe('Note ID (preferred for space notes)'),
|
|
1215
|
+
filename: z.string().optional().describe('Filename/path of the note'),
|
|
1216
|
+
title: z.string().optional().describe('Note title to search for'),
|
|
1217
|
+
date: z.string().optional().describe('Date for calendar notes (YYYYMMDD, YYYY-MM-DD, today, tomorrow, yesterday)'),
|
|
1218
|
+
query: z.string().optional().describe('Fuzzy note query'),
|
|
1179
1219
|
space: z.string().optional().describe('Space name or ID to search in'),
|
|
1180
1220
|
startLine: z.number().min(1).optional().describe('First line to include (1-indexed, inclusive)'),
|
|
1181
1221
|
endLine: z.number().min(1).optional().describe('Last line to include (1-indexed, inclusive)'),
|
|
1182
1222
|
limit: z.number().min(1).max(1000).optional().default(200).describe('Maximum lines to return'),
|
|
1183
1223
|
offset: z.number().min(0).optional().default(0).describe('Pagination offset within selected range'),
|
|
1184
1224
|
cursor: z.string().optional().describe('Cursor token from previous page (preferred over offset)'),
|
|
1225
|
+
}).superRefine((input, ctx) => {
|
|
1226
|
+
if (!input.id && !input.filename && !input.title && !input.date && !input.query) {
|
|
1227
|
+
ctx.addIssue({
|
|
1228
|
+
code: z.ZodIssueCode.custom,
|
|
1229
|
+
message: 'Provide one note reference: id, filename, title, date, or query',
|
|
1230
|
+
path: ['filename'],
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1185
1233
|
});
|
|
1186
1234
|
export const searchParagraphsSchema = z.object({
|
|
1187
1235
|
id: z.string().optional().describe('Note ID (preferred for space notes)'),
|
|
@@ -1215,13 +1263,15 @@ export const searchParagraphsSchema = z.object({
|
|
|
1215
1263
|
}
|
|
1216
1264
|
});
|
|
1217
1265
|
export function getParagraphs(params) {
|
|
1218
|
-
const
|
|
1219
|
-
if (!note) {
|
|
1266
|
+
const noteRef = resolveWritableNoteReference(params);
|
|
1267
|
+
if (!noteRef.note) {
|
|
1220
1268
|
return {
|
|
1221
1269
|
success: false,
|
|
1222
|
-
error: 'Note not found',
|
|
1270
|
+
error: noteRef.error || 'Note not found',
|
|
1271
|
+
candidates: noteRef.candidates,
|
|
1223
1272
|
};
|
|
1224
1273
|
}
|
|
1274
|
+
const note = noteRef.note;
|
|
1225
1275
|
const allLines = note.content.split('\n');
|
|
1226
1276
|
const lineWindow = buildLineWindow(allLines, {
|
|
1227
1277
|
startLine: params.startLine,
|
|
@@ -1401,15 +1451,39 @@ export function searchParagraphs(params) {
|
|
|
1401
1451
|
}
|
|
1402
1452
|
// Granular note operation schemas
|
|
1403
1453
|
export const setPropertySchema = z.object({
|
|
1404
|
-
|
|
1454
|
+
id: z.string().optional().describe('Note ID (preferred for space notes)'),
|
|
1455
|
+
filename: z.string().optional().describe('Filename/path of the note'),
|
|
1456
|
+
title: z.string().optional().describe('Note title to search for'),
|
|
1457
|
+
date: z.string().optional().describe('Date for calendar notes (YYYYMMDD, YYYY-MM-DD, today, tomorrow, yesterday)'),
|
|
1458
|
+
query: z.string().optional().describe('Fuzzy note query'),
|
|
1405
1459
|
space: z.string().optional().describe('Space name or ID to search in'),
|
|
1406
1460
|
key: z.string().describe('Property key (e.g., "icon", "bg-color", "status")'),
|
|
1407
1461
|
value: z.string().describe('Property value'),
|
|
1462
|
+
}).superRefine((input, ctx) => {
|
|
1463
|
+
if (!input.id && !input.filename && !input.title && !input.date && !input.query) {
|
|
1464
|
+
ctx.addIssue({
|
|
1465
|
+
code: z.ZodIssueCode.custom,
|
|
1466
|
+
message: 'Provide one note reference: id, filename, title, date, or query',
|
|
1467
|
+
path: ['filename'],
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1408
1470
|
});
|
|
1409
1471
|
export const removePropertySchema = z.object({
|
|
1410
|
-
|
|
1472
|
+
id: z.string().optional().describe('Note ID (preferred for space notes)'),
|
|
1473
|
+
filename: z.string().optional().describe('Filename/path of the note'),
|
|
1474
|
+
title: z.string().optional().describe('Note title to search for'),
|
|
1475
|
+
date: z.string().optional().describe('Date for calendar notes (YYYYMMDD, YYYY-MM-DD, today, tomorrow, yesterday)'),
|
|
1476
|
+
query: z.string().optional().describe('Fuzzy note query'),
|
|
1411
1477
|
space: z.string().optional().describe('Space name or ID to search in'),
|
|
1412
1478
|
key: z.string().describe('Property key to remove'),
|
|
1479
|
+
}).superRefine((input, ctx) => {
|
|
1480
|
+
if (!input.id && !input.filename && !input.title && !input.date && !input.query) {
|
|
1481
|
+
ctx.addIssue({
|
|
1482
|
+
code: z.ZodIssueCode.custom,
|
|
1483
|
+
message: 'Provide one note reference: id, filename, title, date, or query',
|
|
1484
|
+
path: ['filename'],
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1413
1487
|
});
|
|
1414
1488
|
export const insertContentSchema = z.object({
|
|
1415
1489
|
id: z.string().optional().describe('Note ID (preferred for space notes)'),
|
|
@@ -1551,13 +1625,14 @@ export const replaceLinesSchema = z.object({
|
|
|
1551
1625
|
// Granular note operation implementations
|
|
1552
1626
|
export function setProperty(params) {
|
|
1553
1627
|
try {
|
|
1554
|
-
const
|
|
1555
|
-
if (!note) {
|
|
1556
|
-
return { success: false, error: 'Note not found' };
|
|
1628
|
+
const noteRef = resolveWritableNoteReference(params);
|
|
1629
|
+
if (!noteRef.note) {
|
|
1630
|
+
return { success: false, error: noteRef.error || 'Note not found', candidates: noteRef.candidates };
|
|
1557
1631
|
}
|
|
1632
|
+
const note = noteRef.note;
|
|
1558
1633
|
const newContent = frontmatter.setFrontmatterProperty(note.content, params.key, params.value);
|
|
1559
|
-
const
|
|
1560
|
-
store.updateNote(
|
|
1634
|
+
const writable = getWritableIdentifier(note);
|
|
1635
|
+
store.updateNote(writable.identifier, newContent, { source: writable.source });
|
|
1561
1636
|
return {
|
|
1562
1637
|
success: true,
|
|
1563
1638
|
message: `Property "${params.key}" set to "${params.value}"`,
|
|
@@ -1572,13 +1647,14 @@ export function setProperty(params) {
|
|
|
1572
1647
|
}
|
|
1573
1648
|
export function removeProperty(params) {
|
|
1574
1649
|
try {
|
|
1575
|
-
const
|
|
1576
|
-
if (!note) {
|
|
1577
|
-
return { success: false, error: 'Note not found' };
|
|
1650
|
+
const noteRef = resolveWritableNoteReference(params);
|
|
1651
|
+
if (!noteRef.note) {
|
|
1652
|
+
return { success: false, error: noteRef.error || 'Note not found', candidates: noteRef.candidates };
|
|
1578
1653
|
}
|
|
1654
|
+
const note = noteRef.note;
|
|
1579
1655
|
const newContent = frontmatter.removeFrontmatterProperty(note.content, params.key);
|
|
1580
|
-
const
|
|
1581
|
-
store.updateNote(
|
|
1656
|
+
const writable = getWritableIdentifier(note);
|
|
1657
|
+
store.updateNote(writable.identifier, newContent, { source: writable.source });
|
|
1582
1658
|
return {
|
|
1583
1659
|
success: true,
|
|
1584
1660
|
message: `Property "${params.key}" removed`,
|
|
@@ -1722,6 +1798,15 @@ export function appendContent(params) {
|
|
|
1722
1798
|
}
|
|
1723
1799
|
export function deleteLines(params) {
|
|
1724
1800
|
try {
|
|
1801
|
+
// Validate required line params — MCP may deliver them as undefined when omitted
|
|
1802
|
+
const rawStart = params.startLine !== undefined && params.startLine !== null ? Number(params.startLine) : NaN;
|
|
1803
|
+
const rawEnd = params.endLine !== undefined && params.endLine !== null ? Number(params.endLine) : NaN;
|
|
1804
|
+
if (!Number.isFinite(rawStart)) {
|
|
1805
|
+
return { success: false, error: 'startLine is required (1-indexed).' };
|
|
1806
|
+
}
|
|
1807
|
+
if (!Number.isFinite(rawEnd)) {
|
|
1808
|
+
return { success: false, error: 'endLine is required (1-indexed). Pass the same value as startLine to delete a single line.' };
|
|
1809
|
+
}
|
|
1725
1810
|
const resolved = resolveWritableNoteReference(params);
|
|
1726
1811
|
if (!resolved.note) {
|
|
1727
1812
|
return { success: false, error: resolved.error || 'Note not found', candidates: resolved.candidates };
|
|
@@ -1881,6 +1966,15 @@ export function editLine(params) {
|
|
|
1881
1966
|
}
|
|
1882
1967
|
export function replaceLines(params) {
|
|
1883
1968
|
try {
|
|
1969
|
+
// Validate required line params — MCP may deliver them as undefined when omitted
|
|
1970
|
+
const rawStart = params.startLine !== undefined && params.startLine !== null ? Number(params.startLine) : NaN;
|
|
1971
|
+
const rawEnd = params.endLine !== undefined && params.endLine !== null ? Number(params.endLine) : NaN;
|
|
1972
|
+
if (!Number.isFinite(rawStart)) {
|
|
1973
|
+
return { success: false, error: 'startLine is required (1-indexed).' };
|
|
1974
|
+
}
|
|
1975
|
+
if (!Number.isFinite(rawEnd)) {
|
|
1976
|
+
return { success: false, error: 'endLine is required (1-indexed). Pass the same value as startLine to replace a single line.' };
|
|
1977
|
+
}
|
|
1884
1978
|
const resolved = resolveWritableNoteReference(params);
|
|
1885
1979
|
if (!resolved.note) {
|
|
1886
1980
|
return { success: false, error: resolved.error || 'Note not found', candidates: resolved.candidates };
|