@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
package/dist/setup.js ADDED
@@ -0,0 +1,323 @@
1
+ /**
2
+ * setup.ts — Interactive first-time setup for devon
3
+ *
4
+ * Run with: npx @tekmidian/devon setup
5
+ *
6
+ * Walks the user through:
7
+ * 1. Prerequisites check (macOS, Node version, DEVONthink installed)
8
+ * 2. Update ~/.claude.json mcpServers
9
+ * 3. Update ~/.claude/settings.json enabledMcpjsonServers (if present)
10
+ * 4. Done summary with next steps
11
+ */
12
+ import { createInterface } from "node:readline";
13
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
14
+ import { homedir, platform } from "node:os";
15
+ import { join, dirname } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+ import { execSync } from "node:child_process";
18
+ // ---------------------------------------------------------------------------
19
+ // ANSI color helpers (no external deps)
20
+ // ---------------------------------------------------------------------------
21
+ const RESET = "\x1b[0m";
22
+ const BOLD = "\x1b[1m";
23
+ const GREEN = "\x1b[32m";
24
+ const RED = "\x1b[31m";
25
+ const YELLOW = "\x1b[33m";
26
+ const CYAN = "\x1b[36m";
27
+ const DIM = "\x1b[2m";
28
+ function bold(s) {
29
+ return `${BOLD}${s}${RESET}`;
30
+ }
31
+ function green(s) {
32
+ return `${GREEN}${s}${RESET}`;
33
+ }
34
+ function red(s) {
35
+ return `${RED}${s}${RESET}`;
36
+ }
37
+ function yellow(s) {
38
+ return `${YELLOW}${s}${RESET}`;
39
+ }
40
+ function cyan(s) {
41
+ return `${CYAN}${s}${RESET}`;
42
+ }
43
+ function dim(s) {
44
+ return `${DIM}${s}${RESET}`;
45
+ }
46
+ function ok(msg) {
47
+ process.stdout.write(` ${green("✓")} ${msg}\n`);
48
+ }
49
+ function fail(msg) {
50
+ process.stdout.write(` ${red("✗")} ${msg}\n`);
51
+ }
52
+ function warn(msg) {
53
+ process.stdout.write(` ${yellow("!")} ${msg}\n`);
54
+ }
55
+ function info(msg) {
56
+ process.stdout.write(` ${dim("·")} ${msg}\n`);
57
+ }
58
+ function header(title) {
59
+ process.stdout.write(`\n${bold(title)}\n`);
60
+ process.stdout.write("─".repeat(title.length) + "\n");
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Readline helpers
64
+ // ---------------------------------------------------------------------------
65
+ let rl = null;
66
+ function getReadline() {
67
+ if (!rl) {
68
+ rl = createInterface({ input: process.stdin, output: process.stdout });
69
+ rl.on("close", () => { });
70
+ }
71
+ return rl;
72
+ }
73
+ function closeReadline() {
74
+ if (rl) {
75
+ rl.close();
76
+ rl = null;
77
+ }
78
+ }
79
+ function prompt(question) {
80
+ return new Promise((resolve) => {
81
+ getReadline().question(question, (answer) => resolve(answer.trim()));
82
+ });
83
+ }
84
+ async function promptYesNo(question, defaultYes = true) {
85
+ const hint = defaultYes ? "[Y/n]" : "[y/N]";
86
+ const answer = await prompt(` ${question} ${dim(hint)}: `);
87
+ if (answer === "")
88
+ return defaultYes;
89
+ return answer.toLowerCase().startsWith("y");
90
+ }
91
+ // ---------------------------------------------------------------------------
92
+ // Resolve the path to this package's dist/index.js
93
+ // ---------------------------------------------------------------------------
94
+ function getIndexJsPath() {
95
+ const __filename = fileURLToPath(import.meta.url);
96
+ const distDir = dirname(__filename);
97
+ return join(distDir, "index.js");
98
+ }
99
+ function checkDevonThinkInstalled() {
100
+ const candidates = [
101
+ "/Applications/DEVONthink 3.app",
102
+ "/Applications/DEVONthink Pro.app",
103
+ "/Applications/DEVONthink Personal.app",
104
+ "/Applications/DEVONthink.app",
105
+ ];
106
+ for (const candidate of candidates) {
107
+ if (existsSync(candidate)) {
108
+ return { installed: true, path: candidate };
109
+ }
110
+ }
111
+ // Try mdfind as a fallback
112
+ try {
113
+ const result = execSync('mdfind "kMDItemCFBundleIdentifier == \'com.devon-technologies.think3\'" 2>/dev/null', { encoding: "utf-8", timeout: 5000 }).trim();
114
+ if (result) {
115
+ const firstPath = result.split("\n")[0];
116
+ return { installed: true, path: firstPath ?? null };
117
+ }
118
+ }
119
+ catch {
120
+ // mdfind failed or not available
121
+ }
122
+ return { installed: false, path: null };
123
+ }
124
+ async function stepPrerequisites() {
125
+ header("Step 1: Prerequisites");
126
+ const isMacOS = platform() === "darwin";
127
+ const nodeVersion = process.version;
128
+ if (isMacOS) {
129
+ ok("macOS detected");
130
+ }
131
+ else {
132
+ fail(`Platform: ${platform()} — DEVONthink is macOS-only`);
133
+ warn("Devon requires macOS with DEVONthink installed.");
134
+ warn("This setup cannot continue on non-macOS platforms.");
135
+ throw new Error("Devon requires macOS.");
136
+ }
137
+ const nodeOk = nodeVersion.startsWith("v") && parseInt(nodeVersion.slice(1)) >= 18;
138
+ if (nodeOk) {
139
+ ok(`Node ${nodeVersion} — supported`);
140
+ }
141
+ else {
142
+ warn(`Node ${nodeVersion} may be too old. Node 18+ recommended.`);
143
+ }
144
+ const { installed, path: devonthinkPath } = checkDevonThinkInstalled();
145
+ if (installed) {
146
+ ok(`DEVONthink found: ${cyan(devonthinkPath ?? "yes")}`);
147
+ }
148
+ else {
149
+ fail("DEVONthink 3 not found in /Applications");
150
+ warn("Install DEVONthink from https://www.devontechnologies.com/apps/devonthink");
151
+ warn("Note: The MCP server still works if DEVONthink is installed elsewhere.");
152
+ }
153
+ return { isMacOS, nodeVersion, devonthinkInstalled: installed, devonthinkPath };
154
+ }
155
+ // ---------------------------------------------------------------------------
156
+ // Step 2: Update ~/.claude.json
157
+ // ---------------------------------------------------------------------------
158
+ async function stepUpdateClaudeJson(indexJsPath) {
159
+ header("Step 2: Configure Claude Code (/.claude.json)");
160
+ const claudeJsonPath = join(homedir(), ".claude.json");
161
+ if (!existsSync(claudeJsonPath)) {
162
+ warn("~/.claude.json not found.");
163
+ warn("This file is created the first time you run Claude Code. Run Claude Code once, then re-run setup.");
164
+ return false;
165
+ }
166
+ let parsed;
167
+ try {
168
+ const raw = readFileSync(claudeJsonPath, "utf-8");
169
+ parsed = JSON.parse(raw);
170
+ }
171
+ catch (err) {
172
+ warn(`Could not parse ~/.claude.json: ${err}`);
173
+ return false;
174
+ }
175
+ const mcpServers = parsed["mcpServers"] ?? {};
176
+ // Check if already configured
177
+ const existingEntry = mcpServers["devonthink"];
178
+ if (existingEntry) {
179
+ const currentArgs = existingEntry["args"] ?? [];
180
+ const currentCmd = existingEntry["command"] ?? "";
181
+ info(`Existing entry: ${cyan([currentCmd, ...currentArgs].join(" "))}`);
182
+ info(`Proposed entry: ${cyan(`node ${indexJsPath} serve`)}`);
183
+ process.stdout.write("\n");
184
+ const doUpdate = await promptYesNo("Update the existing devonthink entry to use this installation?", true);
185
+ if (!doUpdate) {
186
+ warn("Skipping ~/.claude.json update");
187
+ return false;
188
+ }
189
+ }
190
+ else {
191
+ info(`Will add: ${cyan(`devonthink`)}`);
192
+ info(`Command: ${cyan(`node ${indexJsPath} serve`)}`);
193
+ process.stdout.write("\n");
194
+ const doAdd = await promptYesNo('Add "devonthink" MCP server to ~/.claude.json?', true);
195
+ if (!doAdd) {
196
+ warn("Skipping ~/.claude.json update");
197
+ return false;
198
+ }
199
+ }
200
+ // Update the mcpServers entry
201
+ const updatedServers = { ...mcpServers };
202
+ updatedServers["devonthink"] = {
203
+ type: "stdio",
204
+ command: "node",
205
+ args: [indexJsPath, "serve"],
206
+ env: {},
207
+ };
208
+ parsed["mcpServers"] = updatedServers;
209
+ try {
210
+ writeFileSync(claudeJsonPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
211
+ ok(`Updated ~/.claude.json — "devonthink" MCP server configured`);
212
+ }
213
+ catch (err) {
214
+ throw new Error(`Failed to write ~/.claude.json: ${err}`);
215
+ }
216
+ return true;
217
+ }
218
+ // ---------------------------------------------------------------------------
219
+ // Step 3: Update ~/.claude/settings.json (enabledMcpjsonServers)
220
+ // ---------------------------------------------------------------------------
221
+ async function stepUpdateSettings() {
222
+ header("Step 3: Enable in Claude Code Settings");
223
+ const settingsPath = join(homedir(), ".claude", "settings.json");
224
+ if (!existsSync(settingsPath)) {
225
+ info("~/.claude/settings.json not found — skipping");
226
+ info("(This file is optional; Claude Code creates it when needed)");
227
+ return false;
228
+ }
229
+ let parsed;
230
+ try {
231
+ const raw = readFileSync(settingsPath, "utf-8");
232
+ parsed = JSON.parse(raw);
233
+ }
234
+ catch (err) {
235
+ warn(`Could not parse ~/.claude/settings.json: ${err}`);
236
+ return false;
237
+ }
238
+ const enabled = parsed["enabledMcpjsonServers"] ?? [];
239
+ if (enabled.includes("devonthink")) {
240
+ ok('"devonthink" is already in enabledMcpjsonServers');
241
+ return true;
242
+ }
243
+ const disabled = parsed["disabledMcpjsonServers"] ?? [];
244
+ const doEnable = await promptYesNo('Add "devonthink" to enabledMcpjsonServers in ~/.claude/settings.json?', true);
245
+ if (!doEnable) {
246
+ warn("Skipping settings.json update");
247
+ return false;
248
+ }
249
+ parsed["enabledMcpjsonServers"] = [...enabled, "devonthink"];
250
+ // Remove from disabled list if present
251
+ if (disabled.includes("devonthink")) {
252
+ parsed["disabledMcpjsonServers"] = disabled.filter((s) => s !== "devonthink");
253
+ info('Removed "devonthink" from disabledMcpjsonServers');
254
+ }
255
+ try {
256
+ writeFileSync(settingsPath, JSON.stringify(parsed, null, 2) + "\n", "utf-8");
257
+ ok('Added "devonthink" to enabledMcpjsonServers in ~/.claude/settings.json');
258
+ }
259
+ catch (err) {
260
+ throw new Error(`Failed to write ~/.claude/settings.json: ${err}`);
261
+ }
262
+ return true;
263
+ }
264
+ // ---------------------------------------------------------------------------
265
+ // Step 4: Done summary
266
+ // ---------------------------------------------------------------------------
267
+ function stepDone(opts) {
268
+ header("Setup Complete!");
269
+ const { claudeJsonUpdated, settingsUpdated, indexJsPath } = opts;
270
+ process.stdout.write("\n");
271
+ if (claudeJsonUpdated || settingsUpdated) {
272
+ ok('DEVONthink MCP server is now configured for Claude Code');
273
+ warn("Restart Claude Code to load the new MCP server.");
274
+ }
275
+ else {
276
+ info("Configuration was not updated. You can run setup again or configure manually.");
277
+ process.stdout.write("\n");
278
+ process.stdout.write(bold(" Manual configuration:\n"));
279
+ process.stdout.write(" Add this to the mcpServers section of ~/.claude.json:\n\n");
280
+ process.stdout.write(` "devonthink": {\n "type": "stdio",\n "command": "node",\n "args": ["${indexJsPath}", "serve"],\n "env": {}\n }\n`);
281
+ }
282
+ process.stdout.write("\n");
283
+ process.stdout.write(bold(" What this MCP server provides:\n"));
284
+ process.stdout.write(" · Search and browse DEVONthink databases\n");
285
+ process.stdout.write(" · Read document content\n");
286
+ process.stdout.write(" · Create, update, and organize records\n");
287
+ process.stdout.write(" · Add tags, classify, and manage metadata\n");
288
+ process.stdout.write(" · Cross-reference emails and documents\n");
289
+ process.stdout.write("\n");
290
+ process.stdout.write(bold(" Requires:\n"));
291
+ process.stdout.write(" · DEVONthink 3 running on macOS\n");
292
+ process.stdout.write(" · One or more open databases\n");
293
+ process.stdout.write("\n");
294
+ }
295
+ // ---------------------------------------------------------------------------
296
+ // Main entry point
297
+ // ---------------------------------------------------------------------------
298
+ export async function runSetup() {
299
+ process.stdout.write("\n");
300
+ process.stdout.write(bold("devon setup") + "\n");
301
+ process.stdout.write("===========\n");
302
+ process.stdout.write(dim("Configure Devon for Claude Code. Press Ctrl+C to abort.\n"));
303
+ const indexJsPath = getIndexJsPath();
304
+ try {
305
+ // Step 1: Prerequisites
306
+ await stepPrerequisites();
307
+ // Step 2: Update ~/.claude.json
308
+ const claudeJsonUpdated = await stepUpdateClaudeJson(indexJsPath);
309
+ // Step 3: Update ~/.claude/settings.json
310
+ const settingsUpdated = await stepUpdateSettings();
311
+ // Step 4: Done
312
+ stepDone({ claudeJsonUpdated, settingsUpdated, indexJsPath });
313
+ }
314
+ catch (err) {
315
+ const msg = err instanceof Error ? err.message : String(err);
316
+ process.stdout.write(`\n${red("Setup failed:")} ${msg}\n`);
317
+ process.exit(1);
318
+ }
319
+ finally {
320
+ closeReadline();
321
+ }
322
+ }
323
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * parser.ts — Plist XML parsing utilities.
3
+ *
4
+ * Migrated from the original listSmartGroups.ts to be shared across tools.
5
+ * Provides depth-aware extraction of top-level <dict> blocks and typed
6
+ * value extractors for common plist types.
7
+ */
8
+ /**
9
+ * Extract top-level <dict>...</dict> blocks from an XML string, respecting nesting.
10
+ * Returns the INNER content of each top-level dict (not including the <dict> tags).
11
+ */
12
+ export declare function extractTopLevelDicts(xml: string): string[];
13
+ /** Escape special regex characters in a string. */
14
+ export declare function escapeRegex(str: string): string;
15
+ /** Extract <string> value after <key>keyName</key> */
16
+ export declare function extractStringAfterKey(content: string, keyName: string): string | null;
17
+ /** Extract <date> value after <key>keyName</key> */
18
+ export declare function extractDateAfterKey(content: string, keyName: string): string | null;
19
+ /** Extract <true/> or <false/> after <key>keyName</key> */
20
+ export declare function extractBoolAfterKey(content: string, keyName: string): boolean | null;
21
+ /** Extract <integer> value after <key>keyName</key> */
22
+ export declare function extractIntegerAfterKey(content: string, keyName: string): number | null;
23
+ /** Extract <real> value after <key>keyName</key> */
24
+ export declare function extractRealAfterKey(content: string, keyName: string): number | null;
25
+ /**
26
+ * Extract the inner content of the <dict> block after <key>keyName</key>,
27
+ * respecting nesting depth.
28
+ */
29
+ export declare function extractSubDictAfterKey(content: string, keyName: string): string | null;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * parser.ts — Plist XML parsing utilities.
3
+ *
4
+ * Migrated from the original listSmartGroups.ts to be shared across tools.
5
+ * Provides depth-aware extraction of top-level <dict> blocks and typed
6
+ * value extractors for common plist types.
7
+ */
8
+ /**
9
+ * Extract top-level <dict>...</dict> blocks from an XML string, respecting nesting.
10
+ * Returns the INNER content of each top-level dict (not including the <dict> tags).
11
+ */
12
+ export function extractTopLevelDicts(xml) {
13
+ const results = [];
14
+ let pos = 0;
15
+ while (pos < xml.length) {
16
+ const openIdx = xml.indexOf("<dict>", pos);
17
+ if (openIdx === -1)
18
+ break;
19
+ let depth = 1;
20
+ let cur = openIdx + 6;
21
+ while (cur < xml.length && depth > 0) {
22
+ const nextOpen = xml.indexOf("<dict>", cur);
23
+ const nextClose = xml.indexOf("</dict>", cur);
24
+ if (nextClose === -1)
25
+ break;
26
+ if (nextOpen !== -1 && nextOpen < nextClose) {
27
+ depth++;
28
+ cur = nextOpen + 6;
29
+ }
30
+ else {
31
+ depth--;
32
+ if (depth === 0) {
33
+ results.push(xml.slice(openIdx + 6, nextClose));
34
+ pos = nextClose + 7;
35
+ break;
36
+ }
37
+ cur = nextClose + 7;
38
+ }
39
+ }
40
+ if (depth !== 0)
41
+ break;
42
+ }
43
+ return results;
44
+ }
45
+ /** Escape special regex characters in a string. */
46
+ export function escapeRegex(str) {
47
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
48
+ }
49
+ /** Extract <string> value after <key>keyName</key> */
50
+ export function extractStringAfterKey(content, keyName) {
51
+ const pattern = new RegExp(`<key>${escapeRegex(keyName)}</key>\\s*<string>([^<]*)<\\/string>`);
52
+ const m = pattern.exec(content);
53
+ return m ? m[1].trim() : null;
54
+ }
55
+ /** Extract <date> value after <key>keyName</key> */
56
+ export function extractDateAfterKey(content, keyName) {
57
+ const pattern = new RegExp(`<key>${escapeRegex(keyName)}</key>\\s*<date>([^<]*)<\\/date>`);
58
+ const m = pattern.exec(content);
59
+ return m ? m[1].trim() : null;
60
+ }
61
+ /** Extract <true/> or <false/> after <key>keyName</key> */
62
+ export function extractBoolAfterKey(content, keyName) {
63
+ const pattern = new RegExp(`<key>${escapeRegex(keyName)}</key>\\s*<(true|false)\\/>`);
64
+ const m = pattern.exec(content);
65
+ if (!m)
66
+ return null;
67
+ return m[1] === "true";
68
+ }
69
+ /** Extract <integer> value after <key>keyName</key> */
70
+ export function extractIntegerAfterKey(content, keyName) {
71
+ const pattern = new RegExp(`<key>${escapeRegex(keyName)}</key>\\s*<integer>([^<]*)<\\/integer>`);
72
+ const m = pattern.exec(content);
73
+ return m ? parseInt(m[1].trim(), 10) : null;
74
+ }
75
+ /** Extract <real> value after <key>keyName</key> */
76
+ export function extractRealAfterKey(content, keyName) {
77
+ const pattern = new RegExp(`<key>${escapeRegex(keyName)}</key>\\s*<real>([^<]*)<\\/real>`);
78
+ const m = pattern.exec(content);
79
+ return m ? parseFloat(m[1].trim()) : null;
80
+ }
81
+ /**
82
+ * Extract the inner content of the <dict> block after <key>keyName</key>,
83
+ * respecting nesting depth.
84
+ */
85
+ export function extractSubDictAfterKey(content, keyName) {
86
+ const keyPattern = new RegExp(`<key>${escapeRegex(keyName)}</key>\\s*<dict>`);
87
+ const keyMatch = keyPattern.exec(content);
88
+ if (!keyMatch)
89
+ return null;
90
+ let depth = 1;
91
+ let pos = keyMatch.index + keyMatch[0].length;
92
+ const startPos = pos;
93
+ while (pos < content.length && depth > 0) {
94
+ const openIdx = content.indexOf("<dict>", pos);
95
+ const closeIdx = content.indexOf("</dict>", pos);
96
+ if (closeIdx === -1)
97
+ break;
98
+ if (openIdx !== -1 && openIdx < closeIdx) {
99
+ depth++;
100
+ pos = openIdx + 6;
101
+ }
102
+ else {
103
+ depth--;
104
+ if (depth === 0) {
105
+ return content.slice(startPos, closeIdx);
106
+ }
107
+ pos = closeIdx + 7;
108
+ }
109
+ }
110
+ return null;
111
+ }
112
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/shared/plist/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * reader.ts — Plist reading/writing utilities using PlistBuddy and Python plistlib.
3
+ *
4
+ * Migrated from columnLayout.ts to be shared across tools.
5
+ */
6
+ /**
7
+ * Run PlistBuddy with a command against a plist file.
8
+ * Returns trimmed stdout, or null if the key does not exist.
9
+ */
10
+ export declare function plistRead(plistPath: string, command: string): string | null;
11
+ /**
12
+ * Parse a PlistBuddy "Array { ... }" output into a string array.
13
+ */
14
+ export declare function parsePlistBuddyArray(raw: string): string[];
15
+ /**
16
+ * Parse a PlistBuddy "Dict { key = value ... }" output into a Record.
17
+ */
18
+ export declare function parsePlistBuddyDict(raw: string): Record<string, number>;
19
+ /**
20
+ * Get all plist keys matching a prefix pattern using Python plistlib.
21
+ * Returns extracted base names (portion after the prefix).
22
+ */
23
+ export declare function getPlistKeysByPrefix(plistPath: string, prefixes: string[], limit?: number): string[];
24
+ /**
25
+ * Copy plist keys from source to target using Python plistlib (atomic read/write).
26
+ */
27
+ export declare function copyPlistKeys(plistPath: string, suffixes: string[], sourceBaseName: string, targetBaseName: string): {
28
+ ok: boolean;
29
+ keysCopied: string[];
30
+ error?: string;
31
+ };
@@ -0,0 +1,127 @@
1
+ /**
2
+ * reader.ts — Plist reading/writing utilities using PlistBuddy and Python plistlib.
3
+ *
4
+ * Migrated from columnLayout.ts to be shared across tools.
5
+ */
6
+ import { execSync } from "node:child_process";
7
+ import { shellQuote } from "../shell.js";
8
+ const PLISTBUDDY = "/usr/libexec/PlistBuddy";
9
+ /**
10
+ * Run PlistBuddy with a command against a plist file.
11
+ * Returns trimmed stdout, or null if the key does not exist.
12
+ */
13
+ export function plistRead(plistPath, command) {
14
+ try {
15
+ const result = execSync(`${PLISTBUDDY} -c ${shellQuote(command)} ${shellQuote(plistPath)}`, { encoding: "utf-8", timeout: 10_000 });
16
+ return result.trim();
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ /**
23
+ * Parse a PlistBuddy "Array { ... }" output into a string array.
24
+ */
25
+ export function parsePlistBuddyArray(raw) {
26
+ return raw
27
+ .split("\n")
28
+ .map((l) => l.trim())
29
+ .filter((l) => l !== "" && l !== "Array {" && l !== "}");
30
+ }
31
+ /**
32
+ * Parse a PlistBuddy "Dict { key = value ... }" output into a Record.
33
+ */
34
+ export function parsePlistBuddyDict(raw) {
35
+ const result = {};
36
+ const lines = raw
37
+ .split("\n")
38
+ .map((l) => l.trim())
39
+ .filter((l) => l !== "" && l !== "Dict {" && l !== "}");
40
+ for (const line of lines) {
41
+ const match = line.match(/^(\S+)\s*=\s*(.+)$/);
42
+ if (match) {
43
+ result[match[1]] = parseFloat(match[2]);
44
+ }
45
+ }
46
+ return result;
47
+ }
48
+ /**
49
+ * Get all plist keys matching a prefix pattern using Python plistlib.
50
+ * Returns extracted base names (portion after the prefix).
51
+ */
52
+ export function getPlistKeysByPrefix(plistPath, prefixes, limit = 200) {
53
+ const prefixesPy = prefixes.map((p) => `'${p.replace(/'/g, "\\'")}'`).join(", ");
54
+ const script = `
55
+ import plistlib, sys
56
+ with open('${plistPath}', 'rb') as f:
57
+ data = plistlib.load(f)
58
+ prefixes = [${prefixesPy}]
59
+ names = set()
60
+ for k in data:
61
+ for p in prefixes:
62
+ if k.startswith(p):
63
+ names.add(k[len(p):])
64
+ names = [n for n in names if not n.startswith('Outline')]
65
+ names.sort()
66
+ print('\\n'.join(names[:${limit}]))
67
+ `.trim();
68
+ try {
69
+ const result = execSync(`python3 -c ${shellQuote(script)}`, {
70
+ encoding: "utf-8",
71
+ timeout: 10_000,
72
+ });
73
+ return result.trim().split("\n").filter(Boolean);
74
+ }
75
+ catch {
76
+ return [];
77
+ }
78
+ }
79
+ /**
80
+ * Copy plist keys from source to target using Python plistlib (atomic read/write).
81
+ */
82
+ export function copyPlistKeys(plistPath, suffixes, sourceBaseName, targetBaseName) {
83
+ const suffixesPy = suffixes.map((s) => `'${s.replace(/'/g, "\\'")}'`).join(", ");
84
+ const script = `
85
+ import plistlib, sys, copy
86
+
87
+ plist_path = '${plistPath}'
88
+ source = '${sourceBaseName.replace(/'/g, "\\'")}'
89
+ target = '${targetBaseName.replace(/'/g, "\\'")}'
90
+ suffixes = [${suffixesPy}]
91
+
92
+ with open(plist_path, 'rb') as f:
93
+ data = plistlib.load(f)
94
+
95
+ copied = []
96
+ for suffix in suffixes:
97
+ src_key = suffix + '-' + source
98
+ tgt_key = suffix + '-' + target
99
+ if src_key in data:
100
+ data[tgt_key] = copy.deepcopy(data[src_key])
101
+ copied.append(tgt_key)
102
+
103
+ if not copied:
104
+ print('ERROR: no source keys found for: ' + source, file=sys.stderr)
105
+ sys.exit(1)
106
+
107
+ with open(plist_path, 'wb') as f:
108
+ plistlib.dump(data, f, fmt=plistlib.FMT_BINARY)
109
+
110
+ print('\\n'.join(copied))
111
+ `.trim();
112
+ try {
113
+ const result = execSync(`python3 -c ${shellQuote(script)}`, {
114
+ encoding: "utf-8",
115
+ timeout: 15_000,
116
+ });
117
+ return { ok: true, keysCopied: result.trim().split("\n").filter(Boolean) };
118
+ }
119
+ catch (err) {
120
+ return {
121
+ ok: false,
122
+ keysCopied: [],
123
+ error: err instanceof Error ? err.message : String(err),
124
+ };
125
+ }
126
+ }
127
+ //# sourceMappingURL=reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../src/shared/plist/reader.ts"],"names":[],"mappings":"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"}