@tekmidian/devon 3.0.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.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +472 -0
  3. package/dist/index.d.ts +12 -0
  4. package/dist/index.js +82 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/jxa/escape.d.ts +22 -0
  7. package/dist/jxa/escape.js +38 -0
  8. package/dist/jxa/escape.js.map +1 -0
  9. package/dist/jxa/executor.d.ts +32 -0
  10. package/dist/jxa/executor.js +65 -0
  11. package/dist/jxa/executor.js.map +1 -0
  12. package/dist/jxa/helpers.d.ts +51 -0
  13. package/dist/jxa/helpers.js +136 -0
  14. package/dist/jxa/helpers.js.map +1 -0
  15. package/dist/jxa/types.d.ts +33 -0
  16. package/dist/jxa/types.js +43 -0
  17. package/dist/jxa/types.js.map +1 -0
  18. package/dist/server.d.ts +10 -0
  19. package/dist/server.js +65 -0
  20. package/dist/server.js.map +1 -0
  21. package/dist/setup.d.ts +12 -0
  22. package/dist/setup.js +323 -0
  23. package/dist/setup.js.map +1 -0
  24. package/dist/shared/plist/parser.d.ts +29 -0
  25. package/dist/shared/plist/parser.js +112 -0
  26. package/dist/shared/plist/parser.js.map +1 -0
  27. package/dist/shared/plist/reader.d.ts +31 -0
  28. package/dist/shared/plist/reader.js +127 -0
  29. package/dist/shared/plist/reader.js.map +1 -0
  30. package/dist/shared/shell.d.ts +15 -0
  31. package/dist/shared/shell.js +22 -0
  32. package/dist/shared/shell.js.map +1 -0
  33. package/dist/tools/ai/ask-ai-about-documents.d.ts +8 -0
  34. package/dist/tools/ai/ask-ai-about-documents.js +88 -0
  35. package/dist/tools/ai/ask-ai-about-documents.js.map +1 -0
  36. package/dist/tools/ai/check-ai-health.d.ts +8 -0
  37. package/dist/tools/ai/check-ai-health.js +40 -0
  38. package/dist/tools/ai/check-ai-health.js.map +1 -0
  39. package/dist/tools/ai/create-summary-document.d.ts +8 -0
  40. package/dist/tools/ai/create-summary-document.js +102 -0
  41. package/dist/tools/ai/create-summary-document.js.map +1 -0
  42. package/dist/tools/ai/get-ai-tool-documentation.d.ts +8 -0
  43. package/dist/tools/ai/get-ai-tool-documentation.js +220 -0
  44. package/dist/tools/ai/get-ai-tool-documentation.js.map +1 -0
  45. package/dist/tools/application/is-running.d.ts +7 -0
  46. package/dist/tools/application/is-running.js +24 -0
  47. package/dist/tools/application/is-running.js.map +1 -0
  48. package/dist/tools/custom/column-layout.d.ts +9 -0
  49. package/dist/tools/custom/column-layout.js +244 -0
  50. package/dist/tools/custom/column-layout.js.map +1 -0
  51. package/dist/tools/custom/list-smart-groups.d.ts +8 -0
  52. package/dist/tools/custom/list-smart-groups.js +79 -0
  53. package/dist/tools/custom/list-smart-groups.js.map +1 -0
  54. package/dist/tools/custom/list-smart-rules.d.ts +8 -0
  55. package/dist/tools/custom/list-smart-rules.js +85 -0
  56. package/dist/tools/custom/list-smart-rules.js.map +1 -0
  57. package/dist/tools/custom/parse-eml-headers.d.ts +8 -0
  58. package/dist/tools/custom/parse-eml-headers.js +155 -0
  59. package/dist/tools/custom/parse-eml-headers.js.map +1 -0
  60. package/dist/tools/database/get-current-database.d.ts +7 -0
  61. package/dist/tools/database/get-current-database.js +29 -0
  62. package/dist/tools/database/get-current-database.js.map +1 -0
  63. package/dist/tools/database/get-open-databases.d.ts +6 -0
  64. package/dist/tools/database/get-open-databases.js +32 -0
  65. package/dist/tools/database/get-open-databases.js.map +1 -0
  66. package/dist/tools/groups/get-selected-records.d.ts +8 -0
  67. package/dist/tools/groups/get-selected-records.js +30 -0
  68. package/dist/tools/groups/get-selected-records.js.map +1 -0
  69. package/dist/tools/groups/list-group-content.d.ts +8 -0
  70. package/dist/tools/groups/list-group-content.js +65 -0
  71. package/dist/tools/groups/list-group-content.js.map +1 -0
  72. package/dist/tools/index.d.ts +9 -0
  73. package/dist/tools/index.js +87 -0
  74. package/dist/tools/index.js.map +1 -0
  75. package/dist/tools/intelligence/classify.d.ts +8 -0
  76. package/dist/tools/intelligence/classify.js +83 -0
  77. package/dist/tools/intelligence/classify.js.map +1 -0
  78. package/dist/tools/intelligence/compare.d.ts +8 -0
  79. package/dist/tools/intelligence/compare.js +121 -0
  80. package/dist/tools/intelligence/compare.js.map +1 -0
  81. package/dist/tools/records/convert-record.d.ts +10 -0
  82. package/dist/tools/records/convert-record.js +77 -0
  83. package/dist/tools/records/convert-record.js.map +1 -0
  84. package/dist/tools/records/create-record.d.ts +8 -0
  85. package/dist/tools/records/create-record.js +64 -0
  86. package/dist/tools/records/create-record.js.map +1 -0
  87. package/dist/tools/records/delete-record.d.ts +9 -0
  88. package/dist/tools/records/delete-record.js +50 -0
  89. package/dist/tools/records/delete-record.js.map +1 -0
  90. package/dist/tools/records/duplicate-record.d.ts +8 -0
  91. package/dist/tools/records/duplicate-record.js +53 -0
  92. package/dist/tools/records/duplicate-record.js.map +1 -0
  93. package/dist/tools/records/get-record-by-id.d.ts +8 -0
  94. package/dist/tools/records/get-record-by-id.js +51 -0
  95. package/dist/tools/records/get-record-by-id.js.map +1 -0
  96. package/dist/tools/records/get-record-content.d.ts +7 -0
  97. package/dist/tools/records/get-record-content.js +48 -0
  98. package/dist/tools/records/get-record-content.js.map +1 -0
  99. package/dist/tools/records/get-record-properties.d.ts +7 -0
  100. package/dist/tools/records/get-record-properties.js +42 -0
  101. package/dist/tools/records/get-record-properties.js.map +1 -0
  102. package/dist/tools/records/move-record.d.ts +8 -0
  103. package/dist/tools/records/move-record.js +60 -0
  104. package/dist/tools/records/move-record.js.map +1 -0
  105. package/dist/tools/records/rename-record.d.ts +7 -0
  106. package/dist/tools/records/rename-record.js +40 -0
  107. package/dist/tools/records/rename-record.js.map +1 -0
  108. package/dist/tools/records/replicate-record.d.ts +8 -0
  109. package/dist/tools/records/replicate-record.js +53 -0
  110. package/dist/tools/records/replicate-record.js.map +1 -0
  111. package/dist/tools/records/set-record-properties.d.ts +10 -0
  112. package/dist/tools/records/set-record-properties.js +76 -0
  113. package/dist/tools/records/set-record-properties.js.map +1 -0
  114. package/dist/tools/records/update-record-content.d.ts +7 -0
  115. package/dist/tools/records/update-record-content.js +43 -0
  116. package/dist/tools/records/update-record-content.js.map +1 -0
  117. package/dist/tools/search/lookup-record.d.ts +7 -0
  118. package/dist/tools/search/lookup-record.js +160 -0
  119. package/dist/tools/search/lookup-record.js.map +1 -0
  120. package/dist/tools/search/search.d.ts +8 -0
  121. package/dist/tools/search/search.js +146 -0
  122. package/dist/tools/search/search.js.map +1 -0
  123. package/dist/tools/tags/add-tags.d.ts +7 -0
  124. package/dist/tools/tags/add-tags.js +47 -0
  125. package/dist/tools/tags/add-tags.js.map +1 -0
  126. package/dist/tools/tags/remove-tags.d.ts +7 -0
  127. package/dist/tools/tags/remove-tags.js +53 -0
  128. package/dist/tools/tags/remove-tags.js.map +1 -0
  129. package/dist/tools/web/create-from-url.d.ts +8 -0
  130. package/dist/tools/web/create-from-url.js +140 -0
  131. package/dist/tools/web/create-from-url.js.map +1 -0
  132. package/package.json +48 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * set-record-properties.ts — Set properties on a DEVONthink record.
3
+ *
4
+ * Supports setting: comment, flagged, locking, and the six exclude* flags
5
+ * (excludeFromClassification, excludeFromSearch, excludeFromSeeAlso,
6
+ * excludeFromTagging, excludeFromWikiLinking, excludeFromChat).
7
+ *
8
+ * Resolves the record via uuid, recordId, or recordPath before setting props.
9
+ */
10
+ import { z } from "zod";
11
+ import { defineTool } from "../../jxa/types.js";
12
+ import { jxaLiteral } from "../../jxa/escape.js";
13
+ import { JXA_APP, JXA_RESOLVE_DB, JXA_RESOLVE_RECORD, JXA_RECORD_PROPS } from "../../jxa/helpers.js";
14
+ export const setRecordPropertiesTool = defineTool({
15
+ name: "set_record_properties",
16
+ description: "Set properties on a DEVONthink record. " +
17
+ "Settable properties: comment, flag (flagged), locked (locking), " +
18
+ "excludeFromChat, excludeFromClassification, excludeFromSearch, " +
19
+ "excludeFromSeeAlso, excludeFromTagging, excludeFromWikiLinking. " +
20
+ "Resolve record by uuid (preferred), recordId + databaseName, or recordPath + databaseName. " +
21
+ "Only provided properties are updated; others remain unchanged.",
22
+ schema: z.object({
23
+ uuid: z.string().optional().describe("UUID of the record"),
24
+ recordId: z.number().int().nonnegative().optional().describe("Numeric record ID (requires databaseName)"),
25
+ recordPath: z.string().optional().describe("Record path within the database (requires databaseName)"),
26
+ databaseName: z.string().optional().describe("Database name"),
27
+ comment: z.string().optional().describe("Set the record comment/annotation"),
28
+ flag: z.boolean().optional().describe("Set the flagged (starred) state"),
29
+ locked: z.boolean().optional().describe("Set the locked (locking) state"),
30
+ excludeFromChat: z.boolean().optional().describe("Exclude record from AI chat"),
31
+ excludeFromClassification: z.boolean().optional().describe("Exclude record from auto-classification"),
32
+ excludeFromSearch: z.boolean().optional().describe("Exclude record from search results"),
33
+ excludeFromSeeAlso: z.boolean().optional().describe("Exclude record from See Also suggestions"),
34
+ excludeFromTagging: z.boolean().optional().describe("Exclude record from auto-tagging"),
35
+ excludeFromWikiLinking: z.boolean().optional().describe("Exclude record from wiki-style auto-linking"),
36
+ }),
37
+ run: async (args, executor) => {
38
+ const { uuid, recordId, recordPath, databaseName, comment, flag, locked, excludeFromChat, excludeFromClassification, excludeFromSearch, excludeFromSeeAlso, excludeFromTagging, excludeFromWikiLinking, } = args;
39
+ const script = `
40
+ ${JXA_APP}
41
+ var uuid = ${jxaLiteral(uuid ?? null)};
42
+ var recordId = ${jxaLiteral(recordId ?? null)};
43
+ var recordPath = ${jxaLiteral(recordPath ?? null)};
44
+ var recordName = null;
45
+ var dbName = ${jxaLiteral(databaseName ?? null)};
46
+
47
+ ${JXA_RESOLVE_DB}
48
+ ${JXA_RESOLVE_RECORD}
49
+
50
+ var comment = ${jxaLiteral(comment ?? null)};
51
+ var flag = ${jxaLiteral(flag ?? null)};
52
+ var locked = ${jxaLiteral(locked ?? null)};
53
+ var excludeFromChat = ${jxaLiteral(excludeFromChat ?? null)};
54
+ var excludeFromClassification = ${jxaLiteral(excludeFromClassification ?? null)};
55
+ var excludeFromSearch = ${jxaLiteral(excludeFromSearch ?? null)};
56
+ var excludeFromSeeAlso = ${jxaLiteral(excludeFromSeeAlso ?? null)};
57
+ var excludeFromTagging = ${jxaLiteral(excludeFromTagging ?? null)};
58
+ var excludeFromWikiLinking = ${jxaLiteral(excludeFromWikiLinking ?? null)};
59
+
60
+ if (comment !== null) record.comment = comment;
61
+ if (flag !== null) record.flag = flag;
62
+ if (locked !== null) record.locking = locked;
63
+ if (excludeFromChat !== null) record.excludeFromChat = excludeFromChat;
64
+ if (excludeFromClassification !== null) record.excludeFromClassification = excludeFromClassification;
65
+ if (excludeFromSearch !== null) record.excludeFromSearch = excludeFromSearch;
66
+ if (excludeFromSeeAlso !== null) record.excludeFromSeeAlso = excludeFromSeeAlso;
67
+ if (excludeFromTagging !== null) record.excludeFromTagging = excludeFromTagging;
68
+ if (excludeFromWikiLinking !== null) record.excludeFromWikiLinking = excludeFromWikiLinking;
69
+
70
+ JSON.stringify(${JXA_RECORD_PROPS});
71
+ `;
72
+ const result = executor.run(script);
73
+ return JSON.parse(result.stdout);
74
+ },
75
+ });
76
+ //# sourceMappingURL=set-record-properties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set-record-properties.js","sourceRoot":"","sources":["../../../src/tools/records/set-record-properties.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * update-record-content.ts — Update the text content of a DEVONthink record.
3
+ *
4
+ * Sets plainText() for text-based records or source() for HTML/Markdown records.
5
+ * UUID is required. Returns confirmation with uuid and name.
6
+ */
7
+ export declare const updateRecordContentTool: import("../../jxa/types.js").McpTool;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * update-record-content.ts — Update the text content of a DEVONthink record.
3
+ *
4
+ * Sets plainText() for text-based records or source() for HTML/Markdown records.
5
+ * UUID is required. Returns confirmation with uuid and name.
6
+ */
7
+ import { z } from "zod";
8
+ import { defineTool } from "../../jxa/types.js";
9
+ import { jxaLiteral } from "../../jxa/escape.js";
10
+ import { JXA_APP } from "../../jxa/helpers.js";
11
+ export const updateRecordContentTool = defineTool({
12
+ name: "update_record_content",
13
+ description: "Updates the content of an existing record in DEVONthink. " +
14
+ "For text records, sets plain text. For HTML/Markdown records, sets the source. " +
15
+ "UUID is required. Returns updated: true with uuid and name on success.",
16
+ schema: z.object({
17
+ uuid: z.string().describe("UUID of the record to update"),
18
+ content: z.string().describe("New content to write to the record"),
19
+ }),
20
+ run: async (args, executor) => {
21
+ const { uuid, content } = args;
22
+ const script = `
23
+ ${JXA_APP}
24
+ var uuid = ${jxaLiteral(uuid)};
25
+ var content = ${jxaLiteral(content)};
26
+
27
+ var record = app.getRecordWithUuid(uuid);
28
+ if (!record || !record.uuid()) throw new Error("Record not found for UUID: " + uuid);
29
+
30
+ var recordType = record.type();
31
+ if (recordType === "html" || recordType === "markdown" || recordType === "feed") {
32
+ record.source = content;
33
+ } else {
34
+ record.plainText = content;
35
+ }
36
+
37
+ JSON.stringify({ updated: true, uuid: record.uuid(), name: record.name() });
38
+ `;
39
+ const result = executor.run(script);
40
+ return JSON.parse(result.stdout);
41
+ },
42
+ });
43
+ //# sourceMappingURL=update-record-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-record-content.js","sourceRoot":"","sources":["../../../src/tools/records/update-record-content.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,MAAM,CAAC,MAAM,uBAAuB,GAAG,UAAU,CAAC;IAChD,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EACT,2DAA2D;QAC3D,iFAAiF;QACjF,wEAAwE;IAC1E,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QACzD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KACnE,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAC5B,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;QAE/B,MAAM,MAAM,GAAG;QACX,OAAO;mBACI,UAAU,CAAC,IAAI,CAAC;sBACb,UAAU,CAAC,OAAO,CAAC;;;;;;;;;;;;;KAapC,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * lookup-record.ts — Look up DEVONthink records by a specific attribute.
3
+ *
4
+ * Supports looking up by filename, path, url, tags, comment, or contentHash.
5
+ * Returns an array of matching record summaries, optionally limited.
6
+ */
7
+ export declare const lookupRecordTool: import("../../jxa/types.js").McpTool;
@@ -0,0 +1,160 @@
1
+ /**
2
+ * lookup-record.ts — Look up DEVONthink records by a specific attribute.
3
+ *
4
+ * Supports looking up by filename, path, url, tags, comment, or contentHash.
5
+ * Returns an array of matching record summaries, optionally limited.
6
+ */
7
+ import { z } from "zod";
8
+ import { defineTool } from "../../jxa/types.js";
9
+ import { jxaLiteral } from "../../jxa/escape.js";
10
+ import { JXA_APP, JXA_RESOLVE_DB, JXA_RECORD_SUMMARY, } from "../../jxa/helpers.js";
11
+ const LOOKUP_TYPE_VALUES = [
12
+ "filename",
13
+ "path",
14
+ "url",
15
+ "tags",
16
+ "comment",
17
+ "contentHash",
18
+ ];
19
+ export const lookupRecordTool = defineTool({
20
+ name: "lookup_record",
21
+ description: "Look up records in DEVONthink by a specific attribute.",
22
+ schema: z.object({
23
+ lookupType: z
24
+ .enum(LOOKUP_TYPE_VALUES)
25
+ .describe("The attribute to look up by"),
26
+ value: z
27
+ .string()
28
+ .describe("The value to match against the specified attribute"),
29
+ tags: z
30
+ .array(z.string())
31
+ .optional()
32
+ .describe("Additional tags to match (only used when lookupType is 'tags')"),
33
+ matchAnyTag: z
34
+ .boolean()
35
+ .optional()
36
+ .describe("When true, match records that have ANY of the specified tags; " +
37
+ "when false (default), match records that have ALL tags"),
38
+ databaseName: z
39
+ .string()
40
+ .optional()
41
+ .describe("Limit lookup to this database; uses all open databases if omitted"),
42
+ limit: z
43
+ .number()
44
+ .int()
45
+ .positive()
46
+ .optional()
47
+ .describe("Maximum number of results to return"),
48
+ }),
49
+ run: async (args, executor) => {
50
+ const { lookupType, value, tags, matchAnyTag, databaseName, limit } = args;
51
+ // Merge value into tags list when lookupType is 'tags'
52
+ const tagList = lookupType === "tags" ? [value, ...(tags ?? [])] : (tags ?? []);
53
+ const script = `
54
+ ${JXA_APP}
55
+ var lookupType = ${jxaLiteral(lookupType)};
56
+ var value = ${jxaLiteral(value)};
57
+ var tagList = ${jxaLiteral(tagList)};
58
+ var matchAnyTag = ${jxaLiteral(matchAnyTag ?? false)};
59
+ var dbName = ${jxaLiteral(databaseName ?? null)};
60
+ var limit = ${jxaLiteral(limit ?? null)};
61
+
62
+ ${JXA_RESOLVE_DB}
63
+
64
+ var results = [];
65
+
66
+ if (lookupType === "filename") {
67
+ // Search by name across the scoped database or all databases
68
+ var searchQuery = "name:" + value;
69
+ var searchOpts = {};
70
+ if (db) searchOpts["in"] = db.root();
71
+ results = app.search(searchQuery, searchOpts);
72
+ // Further filter to exact filename matches
73
+ results = results.filter(function(r) {
74
+ return r.name() === value;
75
+ });
76
+
77
+ } else if (lookupType === "path") {
78
+ // Look up by filesystem path
79
+ if (db) {
80
+ var rec = app.getRecordAt(value, {in: db});
81
+ if (rec && rec.uuid()) results = [rec];
82
+ } else {
83
+ // Try each open database
84
+ var dbs = app.databases();
85
+ for (var i = 0; i < dbs.length; i++) {
86
+ try {
87
+ var r = app.getRecordAt(value, {in: dbs[i]});
88
+ if (r && r.uuid()) { results.push(r); break; }
89
+ } catch(e) {}
90
+ }
91
+ }
92
+
93
+ } else if (lookupType === "url") {
94
+ // Search by URL
95
+ var urlResults = app.lookupRecordsWithURL(value);
96
+ if (urlResults) results = urlResults;
97
+
98
+ } else if (lookupType === "tags") {
99
+ // Look up by tags using DEVONthink's tag lookup
100
+ if (matchAnyTag) {
101
+ // Union: results that match any of the tags
102
+ var seen = {};
103
+ for (var t = 0; t < tagList.length; t++) {
104
+ var tagResults = app.lookupRecordsWithTags([tagList[t]]);
105
+ if (tagResults) {
106
+ for (var j = 0; j < tagResults.length; j++) {
107
+ var u = tagResults[j].uuid();
108
+ if (!seen[u]) {
109
+ seen[u] = true;
110
+ results.push(tagResults[j]);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ } else {
116
+ // Intersection: results that match all of the tags
117
+ results = app.lookupRecordsWithTags(tagList) || [];
118
+ }
119
+
120
+ } else if (lookupType === "comment") {
121
+ // Search by comment using DEVONthink search
122
+ var commentQuery = "comment:" + value;
123
+ var commentOpts = {};
124
+ if (db) commentOpts["in"] = db.root();
125
+ results = app.search(commentQuery, commentOpts);
126
+ // Filter to actual comment matches
127
+ results = results.filter(function(r) {
128
+ var c = r.comment();
129
+ return c && c.indexOf(value) !== -1;
130
+ });
131
+
132
+ } else if (lookupType === "contentHash") {
133
+ // Look up by content hash (MD5/SHA)
134
+ var hashResults = app.lookupRecordsWithContentHash(value);
135
+ if (hashResults) results = hashResults;
136
+ }
137
+
138
+ // Filter by database if specified and not already scoped
139
+ if (dbName && lookupType !== "filename" && lookupType !== "path" && lookupType !== "comment") {
140
+ results = results.filter(function(r) {
141
+ try { return r.database().name() === dbName; } catch(e) { return false; }
142
+ });
143
+ }
144
+
145
+ // Apply limit
146
+ if (limit && limit > 0 && results.length > limit) {
147
+ results = results.slice(0, limit);
148
+ }
149
+
150
+ var summaries = results.map(function(record) {
151
+ return ${JXA_RECORD_SUMMARY};
152
+ });
153
+
154
+ JSON.stringify(summaries);
155
+ `;
156
+ const result = executor.run(script);
157
+ return JSON.parse(result.stdout);
158
+ },
159
+ });
160
+ //# sourceMappingURL=lookup-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup-record.js","sourceRoot":"","sources":["../../../src/tools/search/lookup-record.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EACL,OAAO,EACP,cAAc,EACd,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,kBAAkB,GAAG;IACzB,UAAU;IACV,MAAM;IACN,KAAK;IACL,MAAM;IACN,SAAS;IACT,aAAa;CACL,CAAC;AAEX,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAC;IACzC,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,wDAAwD;IACrE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,UAAU,EAAE,CAAC;aACV,IAAI,CAAC,kBAAkB,CAAC;aACxB,QAAQ,CAAC,6BAA6B,CAAC;QAC1C,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,QAAQ,CAAC,oDAAoD,CAAC;QACjE,IAAI,EAAE,CAAC;aACJ,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,EAAE;aACV,QAAQ,CAAC,gEAAgE,CAAC;QAC7E,WAAW,EAAE,CAAC;aACX,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CACP,gEAAgE;YAC9D,wDAAwD,CAC3D;QACH,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,mEAAmE,CAAC;QAChF,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,qCAAqC,CAAC;KACnD,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAC5B,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QAE3E,uDAAuD;QACvD,MAAM,OAAO,GAAG,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAEhF,MAAM,MAAM,GAAG;QACX,OAAO;yBACU,UAAU,CAAC,UAAU,CAAC;oBAC3B,UAAU,CAAC,KAAK,CAAC;sBACf,UAAU,CAAC,OAAO,CAAC;0BACf,UAAU,CAAC,WAAW,IAAI,KAAK,CAAC;qBACrC,UAAU,CAAC,YAAY,IAAI,IAAI,CAAC;oBACjC,UAAU,CAAC,KAAK,IAAI,IAAI,CAAC;;QAErC,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAyFL,kBAAkB;;;;KAI9B,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * search.ts — Search DEVONthink records by query string with optional scope.
3
+ *
4
+ * Supports scoping to a specific group (by UUID, id, or path+database),
5
+ * filtering by record type, specifying comparison mode, and limiting results.
6
+ * Wildcards (* and ?) in the query are preserved as valid search operators.
7
+ */
8
+ export declare const searchTool: import("../../jxa/types.js").McpTool;
@@ -0,0 +1,146 @@
1
+ /**
2
+ * search.ts — Search DEVONthink records by query string with optional scope.
3
+ *
4
+ * Supports scoping to a specific group (by UUID, id, or path+database),
5
+ * filtering by record type, specifying comparison mode, and limiting results.
6
+ * Wildcards (* and ?) in the query are preserved as valid search operators.
7
+ */
8
+ import { z } from "zod";
9
+ import { defineTool } from "../../jxa/types.js";
10
+ import { jxaLiteral } from "../../jxa/escape.js";
11
+ import { JXA_APP, JXA_RESOLVE_DB, JXA_RECORD_SUMMARY, } from "../../jxa/helpers.js";
12
+ const RECORD_TYPE_VALUES = [
13
+ "group",
14
+ "markdown",
15
+ "PDF",
16
+ "bookmark",
17
+ "formatted note",
18
+ "txt",
19
+ "rtf",
20
+ "rtfd",
21
+ "webarchive",
22
+ "quicktime",
23
+ "picture",
24
+ "smart group",
25
+ ];
26
+ const COMPARISON_VALUES = [
27
+ "no case",
28
+ "no umlauts",
29
+ "fuzzy",
30
+ "related",
31
+ ];
32
+ export const searchTool = defineTool({
33
+ name: "search",
34
+ description: 'Search DEVONthink records. Examples: {"query": "invoice"} or ' +
35
+ '{"query": "project review", "groupPath": "/Meetings", "databaseName": "MyDB"}. ' +
36
+ "Note: groupPath requires databaseName and must be database-relative " +
37
+ '(e.g., "/Meetings" not "/MyDB/Meetings").',
38
+ schema: z.object({
39
+ query: z.string().describe("Search query (wildcards * and ? are supported)"),
40
+ groupUuid: z
41
+ .string()
42
+ .optional()
43
+ .describe("UUID of the group to search within"),
44
+ groupId: z
45
+ .number()
46
+ .int()
47
+ .nonnegative()
48
+ .optional()
49
+ .describe("Numeric ID of the group to search within (requires databaseName)"),
50
+ groupPath: z
51
+ .string()
52
+ .optional()
53
+ .describe("Database-relative path of the group to search within (requires databaseName)"),
54
+ databaseName: z
55
+ .string()
56
+ .optional()
57
+ .describe("Database name (required for groupId or groupPath scoping)"),
58
+ useCurrentGroup: z
59
+ .boolean()
60
+ .optional()
61
+ .describe("Scope search to the currently selected group in DEVONthink"),
62
+ recordType: z
63
+ .enum(RECORD_TYPE_VALUES)
64
+ .optional()
65
+ .describe("Filter results to a specific record type"),
66
+ comparison: z
67
+ .enum(COMPARISON_VALUES)
68
+ .optional()
69
+ .describe("Comparison mode for the search"),
70
+ excludeSubgroups: z
71
+ .boolean()
72
+ .optional()
73
+ .describe("Exclude records from subgroups when scoping to a group"),
74
+ limit: z
75
+ .number()
76
+ .int()
77
+ .positive()
78
+ .optional()
79
+ .describe("Maximum number of results to return"),
80
+ }),
81
+ run: async (args, executor) => {
82
+ const { query, groupUuid, groupId, groupPath, databaseName, useCurrentGroup, recordType, comparison, excludeSubgroups, limit, } = args;
83
+ const script = `
84
+ ${JXA_APP}
85
+ var query = ${jxaLiteral(query)};
86
+ var groupUuid = ${jxaLiteral(groupUuid ?? null)};
87
+ var groupId = ${jxaLiteral(groupId ?? null)};
88
+ var groupPath = ${jxaLiteral(groupPath ?? null)};
89
+ var dbName = ${jxaLiteral(databaseName ?? null)};
90
+ var useCurrentGroup = ${jxaLiteral(useCurrentGroup ?? false)};
91
+ var recordType = ${jxaLiteral(recordType ?? null)};
92
+ var comparison = ${jxaLiteral(comparison ?? null)};
93
+ var excludeSubgroups = ${jxaLiteral(excludeSubgroups ?? false)};
94
+ var limit = ${jxaLiteral(limit ?? null)};
95
+
96
+ ${JXA_RESOLVE_DB}
97
+
98
+ // Resolve the search scope group if specified
99
+ var searchIn = null;
100
+ if (groupUuid) {
101
+ searchIn = app.getRecordWithUuid(groupUuid);
102
+ if (!searchIn || !searchIn.uuid()) throw new Error("Group not found for UUID: " + groupUuid);
103
+ } else if (typeof groupId === "number" && groupId >= 0) {
104
+ if (!db) throw new Error("databaseName is required when using groupId");
105
+ searchIn = db.getRecordAt(groupId);
106
+ if (!searchIn || !searchIn.uuid()) throw new Error("Group not found for ID: " + groupId);
107
+ } else if (groupPath) {
108
+ if (!db) throw new Error("databaseName is required when using groupPath");
109
+ searchIn = app.getRecordAt(groupPath, {in: db});
110
+ if (!searchIn || !searchIn.uuid()) throw new Error("Group not found at path: " + groupPath);
111
+ } else if (useCurrentGroup) {
112
+ searchIn = app.currentGroup();
113
+ }
114
+
115
+ // Build search options
116
+ var searchOpts = {};
117
+ if (searchIn) searchOpts["in"] = searchIn;
118
+ else if (db) searchOpts["in"] = db.root();
119
+ if (comparison) searchOpts["comparison"] = comparison;
120
+ if (excludeSubgroups) searchOpts["excludeSubgroups"] = true;
121
+
122
+ // Execute search
123
+ var results = app.search(query, searchOpts);
124
+
125
+ // Filter by record type if specified
126
+ if (recordType) {
127
+ results = results.filter(function(r) { return r.type() === recordType; });
128
+ }
129
+
130
+ // Apply limit
131
+ if (limit && limit > 0 && results.length > limit) {
132
+ results = results.slice(0, limit);
133
+ }
134
+
135
+ // Map to summaries
136
+ var summaries = results.map(function(record) {
137
+ return ${JXA_RECORD_SUMMARY};
138
+ });
139
+
140
+ JSON.stringify(summaries);
141
+ `;
142
+ const result = executor.run(script);
143
+ return JSON.parse(result.stdout);
144
+ },
145
+ });
146
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/tools/search/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * add-tags.ts — Add tags to a DEVONthink record.
3
+ *
4
+ * Retrieves the current tags on a record, merges the new tags (deduplicating),
5
+ * sets the updated tag list, and returns the record's updated tag state.
6
+ */
7
+ export declare const addTagsTool: import("../../jxa/types.js").McpTool;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * add-tags.ts — Add tags to a DEVONthink record.
3
+ *
4
+ * Retrieves the current tags on a record, merges the new tags (deduplicating),
5
+ * sets the updated tag list, and returns the record's updated tag state.
6
+ */
7
+ import { z } from "zod";
8
+ import { defineTool } from "../../jxa/types.js";
9
+ import { jxaLiteral } from "../../jxa/escape.js";
10
+ import { JXA_APP } from "../../jxa/helpers.js";
11
+ export const addTagsTool = defineTool({
12
+ name: "add_tags",
13
+ description: "Adds tags to a DEVONthink record.",
14
+ schema: z.object({
15
+ uuid: z.string().describe("UUID of the record to tag"),
16
+ tags: z.array(z.string()).min(1).describe("Tags to add to the record"),
17
+ }),
18
+ run: async (args, executor) => {
19
+ const { uuid, tags } = args;
20
+ const script = `
21
+ ${JXA_APP}
22
+ var uuid = ${jxaLiteral(uuid)};
23
+ var newTags = ${jxaLiteral(tags)};
24
+
25
+ var record = app.getRecordWithUuid(uuid);
26
+ if (!record || !record.uuid()) throw new Error("Record not found for UUID: " + uuid);
27
+
28
+ // Get current tags, merge new ones (deduplicating)
29
+ var currentTags = record.tags() || [];
30
+ var tagSet = {};
31
+ for (var i = 0; i < currentTags.length; i++) tagSet[currentTags[i]] = true;
32
+ for (var j = 0; j < newTags.length; j++) tagSet[newTags[j]] = true;
33
+ var merged = Object.keys(tagSet);
34
+
35
+ record.tags = merged;
36
+
37
+ JSON.stringify({
38
+ uuid: record.uuid(),
39
+ name: record.name(),
40
+ tags: record.tags()
41
+ });
42
+ `;
43
+ const result = executor.run(script);
44
+ return JSON.parse(result.stdout);
45
+ },
46
+ });
47
+ //# sourceMappingURL=add-tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-tags.js","sourceRoot":"","sources":["../../../src/tools/tags/add-tags.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;IACpC,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,mCAAmC;IAChD,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACtD,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;KACvE,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAC5B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QAE5B,MAAM,MAAM,GAAG;QACX,OAAO;mBACI,UAAU,CAAC,IAAI,CAAC;sBACb,UAAU,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;KAmBjC,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * remove-tags.ts — Remove tags from a DEVONthink record.
3
+ *
4
+ * Retrieves the current tags on a record, filters out the specified tags,
5
+ * sets the updated tag list, and returns the record's updated tag state.
6
+ */
7
+ export declare const removeTagsTool: import("../../jxa/types.js").McpTool;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * remove-tags.ts — Remove tags from a DEVONthink record.
3
+ *
4
+ * Retrieves the current tags on a record, filters out the specified tags,
5
+ * sets the updated tag list, and returns the record's updated tag state.
6
+ */
7
+ import { z } from "zod";
8
+ import { defineTool } from "../../jxa/types.js";
9
+ import { jxaLiteral } from "../../jxa/escape.js";
10
+ import { JXA_APP } from "../../jxa/helpers.js";
11
+ export const removeTagsTool = defineTool({
12
+ name: "remove_tags",
13
+ description: "Removes tags from a specific record in DEVONthink.",
14
+ schema: z.object({
15
+ uuid: z.string().describe("UUID of the record to remove tags from"),
16
+ tags: z.array(z.string()).min(1).describe("Tags to remove from the record"),
17
+ databaseName: z
18
+ .string()
19
+ .optional()
20
+ .describe("Database name (optional, for disambiguation)"),
21
+ }),
22
+ run: async (args, executor) => {
23
+ const { uuid, tags, databaseName } = args;
24
+ const script = `
25
+ ${JXA_APP}
26
+ var uuid = ${jxaLiteral(uuid)};
27
+ var tagsToRemove = ${jxaLiteral(tags)};
28
+ var dbName = ${jxaLiteral(databaseName ?? null)};
29
+
30
+ var record = app.getRecordWithUuid(uuid);
31
+ if (!record || !record.uuid()) throw new Error("Record not found for UUID: " + uuid);
32
+
33
+ // Build a set of tags to remove for O(1) lookup
34
+ var removeSet = {};
35
+ for (var i = 0; i < tagsToRemove.length; i++) removeSet[tagsToRemove[i]] = true;
36
+
37
+ // Filter current tags
38
+ var currentTags = record.tags() || [];
39
+ var updated = currentTags.filter(function(t) { return !removeSet[t]; });
40
+
41
+ record.tags = updated;
42
+
43
+ JSON.stringify({
44
+ uuid: record.uuid(),
45
+ name: record.name(),
46
+ tags: record.tags()
47
+ });
48
+ `;
49
+ const result = executor.run(script);
50
+ return JSON.parse(result.stdout);
51
+ },
52
+ });
53
+ //# sourceMappingURL=remove-tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove-tags.js","sourceRoot":"","sources":["../../../src/tools/tags/remove-tags.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CAAC;IACvC,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,oDAAoD;IACjE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;QACnE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,gCAAgC,CAAC;QAC3E,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,8CAA8C,CAAC;KAC5D,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAC5B,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QAE1C,MAAM,MAAM,GAAG;QACX,OAAO;mBACI,UAAU,CAAC,IAAI,CAAC;2BACR,UAAU,CAAC,IAAI,CAAC;qBACtB,UAAU,CAAC,YAAY,IAAI,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;KAoBhD,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * create-from-url.ts — Create a DEVONthink record from a web URL.
3
+ *
4
+ * Supports four capture formats: formatted_note, markdown, pdf, and web_document.
5
+ * Optionally places the new record in a specified group and supports readability
6
+ * mode, custom user-agent, referrer, and PDF pagination options.
7
+ */
8
+ export declare const createFromUrlTool: import("../../jxa/types.js").McpTool;