@tekmidian/devonthink-mcp 2.0.0 → 2.0.2
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 +383 -20
- package/dist/tools/columnLayout.d.ts +20 -24
- package/dist/tools/columnLayout.js +284 -191
- package/dist/tools/columnLayout.js.map +1 -1
- package/dist/tools/listSmartGroups.d.ts +28 -4
- package/dist/tools/listSmartGroups.js +150 -56
- package/dist/tools/listSmartGroups.js.map +1 -1
- package/dist/tools/listSmartRules.d.ts +9 -6
- package/dist/tools/listSmartRules.js +64 -62
- package/dist/tools/listSmartRules.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,48 +117,408 @@ Example prompts:
|
|
|
117
117
|
|
|
118
118
|
## Custom tools
|
|
119
119
|
|
|
120
|
+
These five tools extend the upstream `mcp-server-devonthink` capabilities. They are not part of the original package.
|
|
121
|
+
|
|
122
|
+
> **Key limitation:** Smart groups and smart rules are **not accessible via the DEVONthink AppleScript scripting dictionary**. The `list_smart_groups` and `list_smart_rules` tools are the only programmatic way to enumerate them. They work by reading the plist files directly.
|
|
123
|
+
|
|
120
124
|
### `list_smart_groups`
|
|
121
125
|
|
|
122
|
-
Parses `~/Library/Application Support/DEVONthink/SmartGroups.plist` and returns all smart groups with their name, UUID,
|
|
126
|
+
Parses `~/Library/Application Support/DEVONthink/SmartGroups.plist` and returns all smart groups with their name, UUID, sync date, and `UseUUIDKey` flag.
|
|
127
|
+
|
|
128
|
+
**Parameters:** none
|
|
129
|
+
|
|
130
|
+
**Returns:**
|
|
131
|
+
|
|
132
|
+
| Field | Type | Description |
|
|
133
|
+
|-------|------|-------------|
|
|
134
|
+
| `success` | boolean | Whether the operation succeeded |
|
|
135
|
+
| `smartGroups` | array | List of smart group entries |
|
|
136
|
+
| `totalCount` | number | Total number of smart groups found |
|
|
123
137
|
|
|
124
|
-
|
|
138
|
+
Each entry in `smartGroups`:
|
|
139
|
+
|
|
140
|
+
| Field | Type | Description |
|
|
141
|
+
|-------|------|-------------|
|
|
142
|
+
| `name` | string | Display name of the smart group |
|
|
143
|
+
| `uuid` | string | UUID from the `sync.UUID` field — use this with the `search` tool |
|
|
144
|
+
| `syncDate` | string \| null | Last sync date (ISO 8601) |
|
|
145
|
+
| `useUuidKey` | boolean \| null | Whether DEVONthink uses UUID as the key internally |
|
|
146
|
+
|
|
147
|
+
**Example:**
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
list_smart_groups
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"success": true,
|
|
156
|
+
"totalCount": 4,
|
|
157
|
+
"smartGroups": [
|
|
158
|
+
{
|
|
159
|
+
"name": "Jobs - To Review",
|
|
160
|
+
"uuid": "4A469368-94FD-46D3-9A62-ED7C24D822D8",
|
|
161
|
+
"syncDate": "2024-11-15T10:23:00Z",
|
|
162
|
+
"useUuidKey": true
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Use the `uuid` with the `search` tool's `groupUuid` parameter to query the contents of that smart group.
|
|
169
|
+
|
|
170
|
+
---
|
|
125
171
|
|
|
126
172
|
### `list_smart_rules`
|
|
127
173
|
|
|
128
|
-
|
|
174
|
+
Parses `~/Library/Application Support/DEVONthink/SmartRules.plist` and returns all smart rules with name, UUID, enabled state, execution metadata, and sync date.
|
|
175
|
+
|
|
176
|
+
**Parameters:** none
|
|
177
|
+
|
|
178
|
+
**Returns:**
|
|
179
|
+
|
|
180
|
+
| Field | Type | Description |
|
|
181
|
+
|-------|------|-------------|
|
|
182
|
+
| `success` | boolean | Whether the operation succeeded |
|
|
183
|
+
| `smartRules` | array | List of smart rule entries |
|
|
184
|
+
| `totalCount` | number | Total number of smart rules found |
|
|
185
|
+
|
|
186
|
+
Each entry in `smartRules`:
|
|
187
|
+
|
|
188
|
+
| Field | Type | Description |
|
|
189
|
+
|-------|------|-------------|
|
|
190
|
+
| `name` | string | Display name of the smart rule |
|
|
191
|
+
| `uuid` | string | UUID from the `sync.UUID` field |
|
|
192
|
+
| `enabled` | boolean \| null | Whether the rule is currently enabled |
|
|
193
|
+
| `indexOffset` | number \| null | Order index within the rules list |
|
|
194
|
+
| `lastExecution` | number \| null | CFAbsoluteTime timestamp of last execution |
|
|
195
|
+
| `syncDate` | string \| null | Last sync date (ISO 8601) |
|
|
196
|
+
| `useUuidKey` | boolean \| null | Whether DEVONthink uses UUID as the key internally |
|
|
197
|
+
|
|
198
|
+
**Example:**
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
list_smart_rules
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"success": true,
|
|
207
|
+
"totalCount": 2,
|
|
208
|
+
"smartRules": [
|
|
209
|
+
{
|
|
210
|
+
"name": "Auto-tag Invoices",
|
|
211
|
+
"uuid": "B1234567-ABCD-EF01-2345-67890ABCDEF0",
|
|
212
|
+
"enabled": true,
|
|
213
|
+
"indexOffset": 0,
|
|
214
|
+
"lastExecution": 756000000,
|
|
215
|
+
"syncDate": "2024-12-01T08:00:00Z",
|
|
216
|
+
"useUuidKey": false
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
129
223
|
|
|
130
224
|
### `parse_eml_headers`
|
|
131
225
|
|
|
132
|
-
Reads an RFC 2822 `.eml` file and extracts
|
|
226
|
+
Reads an RFC 2822 `.eml` file and extracts the MIME headers needed for email thread correlation.
|
|
227
|
+
|
|
228
|
+
Handles CRLF and LF line endings, folded headers (continuation lines), and RFC 2047 encoded words in Subject, From, and To fields.
|
|
229
|
+
|
|
230
|
+
Only reads the first 64 KB of the file since headers are always at the start.
|
|
231
|
+
|
|
232
|
+
**Parameters:**
|
|
233
|
+
|
|
234
|
+
| Parameter | Type | Required | Description |
|
|
235
|
+
|-----------|------|----------|-------------|
|
|
236
|
+
| `filePath` | string | yes | Absolute path to the `.eml` file |
|
|
237
|
+
|
|
238
|
+
**Returns:**
|
|
133
239
|
|
|
134
|
-
| Field | Description |
|
|
135
|
-
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
143
|
-
| `
|
|
240
|
+
| Field | Type | Description |
|
|
241
|
+
|-------|------|-------------|
|
|
242
|
+
| `success` | boolean | Whether parsing succeeded |
|
|
243
|
+
| `filePath` | string | The path that was read |
|
|
244
|
+
| `messageId` | string \| null | The `Message-ID` header value |
|
|
245
|
+
| `inReplyTo` | string \| null | The `In-Reply-To` header value |
|
|
246
|
+
| `references` | string[] | Array of message IDs parsed from the `References` header |
|
|
247
|
+
| `subject` | string \| null | Decoded subject line |
|
|
248
|
+
| `from` | string \| null | Sender address(es) |
|
|
249
|
+
| `to` | string \| null | Recipient address(es) |
|
|
250
|
+
| `cc` | string \| null | CC address(es) |
|
|
251
|
+
| `date` | string \| null | Date string from the header |
|
|
144
252
|
|
|
145
|
-
|
|
253
|
+
**Example:**
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"filePath": "/path/to/email.eml"
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"success": true,
|
|
264
|
+
"filePath": "/path/to/email.eml",
|
|
265
|
+
"messageId": "<abc123@mail.example.com>",
|
|
266
|
+
"inReplyTo": "<xyz789@mail.example.com>",
|
|
267
|
+
"references": [
|
|
268
|
+
"<original@mail.example.com>",
|
|
269
|
+
"<xyz789@mail.example.com>"
|
|
270
|
+
],
|
|
271
|
+
"subject": "Re: Contract renewal discussion",
|
|
272
|
+
"from": "Jane Smith <jane@example.com>",
|
|
273
|
+
"to": "John Doe <john@example.com>",
|
|
274
|
+
"cc": null,
|
|
275
|
+
"date": "Mon, 15 Jan 2024 14:32:00 +0100"
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
---
|
|
146
280
|
|
|
147
281
|
### `get_column_layout`
|
|
148
282
|
|
|
149
|
-
Reads the column layout for a named smart group or smart rule from `~/Library/Preferences/com.devon-technologies.think.plist
|
|
283
|
+
Reads the column layout for a named smart group or smart rule from `~/Library/Preferences/com.devon-technologies.think.plist`.
|
|
284
|
+
|
|
285
|
+
Returns the ordered visible columns, all table view columns (visible and hidden), and column widths. Supports partial name matching — if only one partial match exists, it is used automatically.
|
|
286
|
+
|
|
287
|
+
DEVONthink stores layouts under three related plist keys per smart group: the visible column order, all columns, and column widths.
|
|
288
|
+
|
|
289
|
+
**Parameters:**
|
|
290
|
+
|
|
291
|
+
| Parameter | Type | Required | Description |
|
|
292
|
+
|-----------|------|----------|-------------|
|
|
293
|
+
| `name` | string | yes | Display name of the smart group or smart rule |
|
|
294
|
+
| `uuid` | string | no | UUID of the smart group (fallback if name lookup fails — DEVONthink sometimes stores layouts under the UUID) |
|
|
295
|
+
|
|
296
|
+
**Returns:**
|
|
297
|
+
|
|
298
|
+
| Field | Type | Description |
|
|
299
|
+
|-------|------|-------------|
|
|
300
|
+
| `success` | boolean | Whether a layout was found |
|
|
301
|
+
| `name` | string | The name that was searched |
|
|
302
|
+
| `resolvedKey` | string | The actual plist key used (may be UUID if name was not found directly) |
|
|
303
|
+
| `columns` | string[] \| null | Visible columns in display order |
|
|
304
|
+
| `tableViewColumns` | string[] \| null | All column identifiers (visible + hidden) |
|
|
305
|
+
| `widths` | object \| null | Map of column identifier to width (float) |
|
|
306
|
+
| `keysFound` | string[] | Which of the three plist keys were present |
|
|
307
|
+
|
|
308
|
+
On failure, the response includes `exampleNames` (a list of names with saved layouts) and `partialMatches` when multiple fuzzy matches are found.
|
|
309
|
+
|
|
310
|
+
**Example:**
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"name": "Jobs - To Review"
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
```json
|
|
319
|
+
{
|
|
320
|
+
"success": true,
|
|
321
|
+
"name": "Jobs - To Review",
|
|
322
|
+
"resolvedKey": "Jobs - To Review",
|
|
323
|
+
"columns": ["name", "date", "from", "subject"],
|
|
324
|
+
"tableViewColumns": ["name", "date", "from", "subject", "tags", "size"],
|
|
325
|
+
"widths": { "name": 280.0, "date": 120.0, "from": 180.0, "subject": 320.0 },
|
|
326
|
+
"keysFound": [
|
|
327
|
+
"ListColumnsHorizontal-Jobs - To Review",
|
|
328
|
+
"TableView Columns ListColumnsHorizontal-Jobs - To Review",
|
|
329
|
+
"TableView Column Widths ListColumnsHorizontal-Jobs - To Review"
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
150
335
|
|
|
151
336
|
### `copy_column_layout`
|
|
152
337
|
|
|
153
|
-
Copies the column layout from one smart group or smart rule to another.
|
|
338
|
+
Copies the column layout (visible columns, all columns, and column widths) from one smart group or smart rule to another. All three layout keys are written atomically using Python's `plistlib` so the binary plist format is preserved correctly.
|
|
339
|
+
|
|
340
|
+
Supports partial name matching for both source and target. DEVONthink must be restarted (or the smart group window closed and reopened) for the change to take effect.
|
|
341
|
+
|
|
342
|
+
**Parameters:**
|
|
343
|
+
|
|
344
|
+
| Parameter | Type | Required | Description |
|
|
345
|
+
|-----------|------|----------|-------------|
|
|
346
|
+
| `sourceName` | string | yes | Name of the source smart group or smart rule (must have a saved layout) |
|
|
347
|
+
| `targetName` | string | yes | Name of the target smart group or smart rule |
|
|
348
|
+
| `sourceUuid` | string | no | UUID fallback for the source (used if name lookup fails) |
|
|
349
|
+
| `targetUuid` | string | no | UUID of the target — if supplied, the layout is written under the UUID key |
|
|
350
|
+
|
|
351
|
+
**Returns:**
|
|
352
|
+
|
|
353
|
+
| Field | Type | Description |
|
|
354
|
+
|-------|------|-------------|
|
|
355
|
+
| `success` | boolean | Whether the copy succeeded |
|
|
356
|
+
| `sourceName` | string | The source name provided |
|
|
357
|
+
| `targetName` | string | The target name provided |
|
|
358
|
+
| `resolvedSourceKey` | string | The plist key used for the source |
|
|
359
|
+
| `resolvedTargetKey` | string | The plist key used for the target |
|
|
360
|
+
| `keysCopied` | string[] | The plist keys that were written |
|
|
361
|
+
| `message` | string | Human-readable summary including the column names that were copied |
|
|
362
|
+
|
|
363
|
+
**Example:**
|
|
364
|
+
|
|
365
|
+
```json
|
|
366
|
+
{
|
|
367
|
+
"sourceName": "Archivieren - Jobs",
|
|
368
|
+
"targetName": "Jobs - To Review"
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
```json
|
|
373
|
+
{
|
|
374
|
+
"success": true,
|
|
375
|
+
"sourceName": "Archivieren - Jobs",
|
|
376
|
+
"targetName": "Jobs - To Review",
|
|
377
|
+
"resolvedSourceKey": "Archivieren - Jobs",
|
|
378
|
+
"resolvedTargetKey": "Jobs - To Review",
|
|
379
|
+
"keysCopied": [
|
|
380
|
+
"ListColumnsHorizontal-Jobs - To Review",
|
|
381
|
+
"TableView Columns ListColumnsHorizontal-Jobs - To Review",
|
|
382
|
+
"TableView Column Widths ListColumnsHorizontal-Jobs - To Review"
|
|
383
|
+
],
|
|
384
|
+
"message": "Copied column layout from \"Archivieren - Jobs\" to \"Jobs - To Review\". Columns: [name, date, from, subject]. Restart DEVONthink or close/reopen the smart group window for the change to take effect."
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Workflows
|
|
391
|
+
|
|
392
|
+
### Smart group discovery and content querying
|
|
393
|
+
|
|
394
|
+
Smart groups are virtual views defined by search criteria — they have no physical location in the database. Because they are not part of the AppleScript scripting dictionary, you cannot list them through normal MCP or JXA calls. Use this two-step pattern instead:
|
|
395
|
+
|
|
396
|
+
**Step 1:** Enumerate all smart groups to find the UUID of the one you want.
|
|
397
|
+
|
|
398
|
+
```
|
|
399
|
+
list_smart_groups
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Response includes each smart group's `name` and `uuid`.
|
|
403
|
+
|
|
404
|
+
**Step 2:** Query the contents of that smart group using the `search` tool with `groupUuid`.
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
search
|
|
408
|
+
query: ""
|
|
409
|
+
groupUuid: "4A469368-94FD-46D3-9A62-ED7C24D822D8"
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
This returns all records that match the smart group's criteria. The `search` tool sorts by relevance by default; add a `sortBy` parameter if you need date ordering.
|
|
413
|
+
|
|
414
|
+
**Important:** `list_group_content` with a smart group UUID returns email Message-IDs in the `uuid` field (not DEVONthink record UUIDs). Use `search` with `groupUuid` instead — it returns proper records with dates and correct UUIDs that work with `get_record_properties` and `get_record_content`.
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
### Email thread correlation
|
|
419
|
+
|
|
420
|
+
To link a live Gmail thread back to its archived copy in DEVONthink, use a three-tier matching strategy:
|
|
421
|
+
|
|
422
|
+
**Tier 1 — Thread ID match (highest precision)**
|
|
423
|
+
|
|
424
|
+
Get the file path for the archived record:
|
|
425
|
+
|
|
426
|
+
```
|
|
427
|
+
get_record_properties
|
|
428
|
+
uuid: <record_uuid>
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Extract the `path` field, then parse the EML headers:
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
parse_eml_headers
|
|
435
|
+
filePath: "/path/to/archived/email.eml"
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Use the `messageId`, `inReplyTo`, and `references` values to correlate precisely with Gmail thread headers.
|
|
439
|
+
|
|
440
|
+
**Tier 2 — Subject and sender match**
|
|
441
|
+
|
|
442
|
+
```
|
|
443
|
+
search
|
|
444
|
+
query: "kind:email subject:\"Contract renewal\" from:jane@example.com"
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Strip `Re:`, `Fwd:`, `AW:`, `WG:` prefixes before searching.
|
|
448
|
+
|
|
449
|
+
**Tier 3 — Subject only (broadest)**
|
|
450
|
+
|
|
451
|
+
```
|
|
452
|
+
search
|
|
453
|
+
query: "kind:email subject:\"Contract renewal\""
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Always try Tier 1 first when the EML path is available. Report which tier matched so confidence is clear.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
### Column layout management
|
|
461
|
+
|
|
462
|
+
When you create a new smart group and want it to display the same columns as an existing one:
|
|
463
|
+
|
|
464
|
+
**Step 1:** Read the layout of the source smart group to see what columns it uses.
|
|
465
|
+
|
|
466
|
+
```
|
|
467
|
+
get_column_layout
|
|
468
|
+
name: "Archivieren - Jobs"
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Step 2:** Copy that layout to the new smart group.
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
copy_column_layout
|
|
475
|
+
sourceName: "Archivieren - Jobs"
|
|
476
|
+
targetName: "New Smart Group"
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
If DEVONthink stores layouts by UUID rather than display name, supply the UUID as a fallback:
|
|
480
|
+
|
|
481
|
+
```
|
|
482
|
+
copy_column_layout
|
|
483
|
+
sourceName: "Archivieren - Jobs"
|
|
484
|
+
targetName: "New Smart Group"
|
|
485
|
+
targetUuid: "4A469368-94FD-46D3-9A62-ED7C24D822D8"
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Close and reopen the smart group window (or restart DEVONthink) after copying for the change to take effect.
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## DEVONthink search syntax
|
|
493
|
+
|
|
494
|
+
The upstream `search` tool supports these operators:
|
|
495
|
+
|
|
496
|
+
| Operator | Example | Description |
|
|
497
|
+
|----------|---------|-------------|
|
|
498
|
+
| `kind:` | `kind:email` | Filter by record type |
|
|
499
|
+
| `name:` | `name:"offer letter"` | Match filename or subject |
|
|
500
|
+
| `subject:` | `subject:"interview"` | Email subject field |
|
|
501
|
+
| `from:` | `from:recruiter@co.com` | Sender address |
|
|
502
|
+
| `to:` | `to:user@example.com` | Recipient address |
|
|
503
|
+
| `text:` | `text:"stock options"` | Full-text content search |
|
|
504
|
+
| `tags:` | `tags:jobs` | Tagged records |
|
|
505
|
+
| `date:` | `date:2024-01-01~` | Date range (`~` = after) |
|
|
506
|
+
| Quotes | `"exact phrase"` | Exact phrase match |
|
|
507
|
+
| AND/OR | `from:x OR from:y` | Boolean operators |
|
|
508
|
+
|
|
509
|
+
Combining operators:
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
kind:email from:@company.com subject:"compensation" date:2023-01-01~2024-12-31
|
|
513
|
+
```
|
|
154
514
|
|
|
155
515
|
---
|
|
156
516
|
|
|
157
517
|
## How it works
|
|
158
518
|
|
|
159
|
-
`devonthink-mcp` runs as an in-process MCP server built on `@modelcontextprotocol/sdk`. It imports all upstream tool objects from `mcp-server-devonthink` and adds custom tools, then serves them through a single unified `ListTools` / `CallTool` handler.
|
|
519
|
+
`devonthink-mcp` runs as an in-process MCP server built on `@modelcontextprotocol/sdk`. It imports all upstream tool objects from `mcp-server-devonthink` and adds the five custom tools, then serves them through a single unified `ListTools` / `CallTool` handler.
|
|
160
520
|
|
|
161
|
-
The upstream tools communicate with DEVONthink via JXA (JavaScript for Automation) over the macOS Scripting Bridge.
|
|
521
|
+
The upstream tools communicate with DEVONthink via JXA (JavaScript for Automation) over the macOS Scripting Bridge. The custom tools use `plutil`, `PlistBuddy`, and Python's `plistlib` to read DEVONthink preference and data files directly.
|
|
162
522
|
|
|
163
523
|
---
|
|
164
524
|
|
|
@@ -179,7 +539,10 @@ Open at least one DEVONthink database before using the MCP tools.
|
|
|
179
539
|
Grant Claude Code (or Terminal) Automation permissions in System Settings > Privacy & Security > Automation.
|
|
180
540
|
|
|
181
541
|
**`list_smart_groups` returns no results or error**
|
|
182
|
-
The plist format varies between DEVONthink versions. If the tool
|
|
542
|
+
The plist format varies between DEVONthink versions. If the tool cannot parse the structure, use `plutil -p ~/Library/Application\ Support/DEVONthink/SmartGroups.plist` to inspect the raw format and report an issue.
|
|
543
|
+
|
|
544
|
+
**`get_column_layout` returns "no layout found"**
|
|
545
|
+
The smart group does not yet have a custom column layout saved — it uses DEVONthink defaults. Use `copy_column_layout` to copy a layout from another smart group that already has one configured.
|
|
183
546
|
|
|
184
547
|
---
|
|
185
548
|
|
|
@@ -2,29 +2,24 @@
|
|
|
2
2
|
* columnLayout.ts — Read and copy DEVONthink column layouts for smart groups/rules.
|
|
3
3
|
*
|
|
4
4
|
* Column layouts for list views are stored in
|
|
5
|
-
* ~/Library/Preferences/com.devon-technologies.think.plist under
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* ~/Library/Preferences/com.devon-technologies.think.plist under three related keys
|
|
6
|
+
* per smart group or rule (keyed by name or UUID):
|
|
7
|
+
*
|
|
8
|
+
* ListColumnsHorizontal-{name}
|
|
9
|
+
* → Array of visible column identifiers in display order
|
|
10
|
+
*
|
|
11
|
+
* TableView Columns ListColumnsHorizontal-{name}
|
|
12
|
+
* → Array of ALL column identifiers (visible + hidden)
|
|
13
|
+
*
|
|
14
|
+
* TableView Column Widths ListColumnsHorizontal-{name}
|
|
15
|
+
* → Dict of { columnIdentifier: widthFloat }
|
|
16
|
+
*
|
|
17
|
+
* The plist may use a smart group's UUID instead of its display name.
|
|
8
18
|
*
|
|
9
19
|
* Tools exported:
|
|
10
20
|
* get_column_layout — Read columns for a named smart group or rule
|
|
11
21
|
* copy_column_layout — Copy column layout from one smart group/rule to another
|
|
12
22
|
*/
|
|
13
|
-
interface ColumnEntry {
|
|
14
|
-
identifier: string | null;
|
|
15
|
-
title: string | null;
|
|
16
|
-
width: number | null;
|
|
17
|
-
visible: boolean | null;
|
|
18
|
-
position: number | null;
|
|
19
|
-
}
|
|
20
|
-
interface GetColumnLayoutResult {
|
|
21
|
-
success: boolean;
|
|
22
|
-
name?: string;
|
|
23
|
-
plistKey?: string;
|
|
24
|
-
columns?: ColumnEntry[];
|
|
25
|
-
rawValue?: string;
|
|
26
|
-
error?: string;
|
|
27
|
-
}
|
|
28
23
|
export declare const getColumnLayoutTool: {
|
|
29
24
|
name: string;
|
|
30
25
|
description: string;
|
|
@@ -35,21 +30,22 @@ export declare const getColumnLayoutTool: {
|
|
|
35
30
|
type: string;
|
|
36
31
|
description: string;
|
|
37
32
|
};
|
|
38
|
-
|
|
33
|
+
uuid: {
|
|
39
34
|
type: string;
|
|
40
35
|
description: string;
|
|
41
36
|
};
|
|
42
37
|
};
|
|
43
38
|
required: string[];
|
|
44
39
|
};
|
|
45
|
-
run: (args: Record<string, unknown>) => Promise<
|
|
40
|
+
run: (args: Record<string, unknown>) => Promise<unknown>;
|
|
46
41
|
};
|
|
47
42
|
interface CopyColumnLayoutResult {
|
|
48
43
|
success: boolean;
|
|
49
44
|
sourceName?: string;
|
|
50
45
|
targetName?: string;
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
resolvedSourceKey?: string;
|
|
47
|
+
resolvedTargetKey?: string;
|
|
48
|
+
keysCopied?: string[];
|
|
53
49
|
message?: string;
|
|
54
50
|
error?: string;
|
|
55
51
|
}
|
|
@@ -67,11 +63,11 @@ export declare const copyColumnLayoutTool: {
|
|
|
67
63
|
type: string;
|
|
68
64
|
description: string;
|
|
69
65
|
};
|
|
70
|
-
|
|
66
|
+
sourceUuid: {
|
|
71
67
|
type: string;
|
|
72
68
|
description: string;
|
|
73
69
|
};
|
|
74
|
-
|
|
70
|
+
targetUuid: {
|
|
75
71
|
type: string;
|
|
76
72
|
description: string;
|
|
77
73
|
};
|