@wonderwhy-er/desktop-commander 0.2.34 → 0.2.36
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 +2 -0
- package/dist/handlers/filesystem-handlers.js +58 -11
- package/dist/handlers/history-handlers.d.ts +7 -0
- package/dist/handlers/history-handlers.js +33 -1
- package/dist/server.js +30 -4
- package/dist/tools/docx/builders/html-builder.d.ts +17 -0
- package/dist/tools/docx/builders/html-builder.js +92 -0
- package/dist/tools/docx/builders/image.d.ts +14 -0
- package/dist/tools/docx/builders/image.js +84 -0
- package/dist/tools/docx/builders/index.d.ts +11 -0
- package/dist/tools/docx/builders/index.js +11 -0
- package/dist/tools/docx/builders/markdown-builder.d.ts +2 -0
- package/dist/tools/docx/builders/markdown-builder.js +260 -0
- package/dist/tools/docx/builders/paragraph.d.ts +12 -0
- package/dist/tools/docx/builders/paragraph.js +29 -0
- package/dist/tools/docx/builders/table.d.ts +8 -0
- package/dist/tools/docx/builders/table.js +94 -0
- package/dist/tools/docx/builders/utils.d.ts +5 -0
- package/dist/tools/docx/builders/utils.js +18 -0
- package/dist/tools/docx/constants.d.ts +32 -0
- package/dist/tools/docx/constants.js +61 -0
- package/dist/tools/docx/converters/markdown-to-html.d.ts +17 -0
- package/dist/tools/docx/converters/markdown-to-html.js +111 -0
- package/dist/tools/docx/create.d.ts +21 -0
- package/dist/tools/docx/create.js +386 -0
- package/dist/tools/docx/dom.d.ts +66 -0
- package/dist/tools/docx/dom.js +228 -0
- package/dist/tools/docx/errors.d.ts +28 -0
- package/dist/tools/docx/errors.js +48 -0
- package/dist/tools/docx/extractors/images.d.ts +14 -0
- package/dist/tools/docx/extractors/images.js +40 -0
- package/dist/tools/docx/extractors/metadata.d.ts +14 -0
- package/dist/tools/docx/extractors/metadata.js +64 -0
- package/dist/tools/docx/extractors/sections.d.ts +14 -0
- package/dist/tools/docx/extractors/sections.js +61 -0
- package/dist/tools/docx/html.d.ts +17 -0
- package/dist/tools/docx/html.js +111 -0
- package/dist/tools/docx/index.d.ts +10 -0
- package/dist/tools/docx/index.js +10 -0
- package/dist/tools/docx/markdown.d.ts +84 -0
- package/dist/tools/docx/markdown.js +507 -0
- package/dist/tools/docx/modify.d.ts +28 -0
- package/dist/tools/docx/modify.js +271 -0
- package/dist/tools/docx/operations/handlers/index.d.ts +39 -0
- package/dist/tools/docx/operations/handlers/index.js +152 -0
- package/dist/tools/docx/operations/html-manipulator.d.ts +24 -0
- package/dist/tools/docx/operations/html-manipulator.js +352 -0
- package/dist/tools/docx/operations/index.d.ts +14 -0
- package/dist/tools/docx/operations/index.js +61 -0
- package/dist/tools/docx/operations/operation-handlers.d.ts +3 -0
- package/dist/tools/docx/operations/operation-handlers.js +67 -0
- package/dist/tools/docx/operations/preprocessor.d.ts +14 -0
- package/dist/tools/docx/operations/preprocessor.js +44 -0
- package/dist/tools/docx/operations/xml-replacer.d.ts +9 -0
- package/dist/tools/docx/operations/xml-replacer.js +35 -0
- package/dist/tools/docx/operations.d.ts +13 -0
- package/dist/tools/docx/operations.js +13 -0
- package/dist/tools/docx/ops/delete-paragraph-at-body-index.d.ts +11 -0
- package/dist/tools/docx/ops/delete-paragraph-at-body-index.js +23 -0
- package/dist/tools/docx/ops/header-replace-text-exact.d.ts +13 -0
- package/dist/tools/docx/ops/header-replace-text-exact.js +55 -0
- package/dist/tools/docx/ops/index.d.ts +17 -0
- package/dist/tools/docx/ops/index.js +67 -0
- package/dist/tools/docx/ops/insert-image-after-text.d.ts +24 -0
- package/dist/tools/docx/ops/insert-image-after-text.js +128 -0
- package/dist/tools/docx/ops/insert-paragraph-after-text.d.ts +12 -0
- package/dist/tools/docx/ops/insert-paragraph-after-text.js +74 -0
- package/dist/tools/docx/ops/insert-table-after-text.d.ts +19 -0
- package/dist/tools/docx/ops/insert-table-after-text.js +57 -0
- package/dist/tools/docx/ops/replace-hyperlink-url.d.ts +12 -0
- package/dist/tools/docx/ops/replace-hyperlink-url.js +37 -0
- package/dist/tools/docx/ops/replace-paragraph-at-body-index.d.ts +9 -0
- package/dist/tools/docx/ops/replace-paragraph-at-body-index.js +25 -0
- package/dist/tools/docx/ops/replace-paragraph-text-exact.d.ts +9 -0
- package/dist/tools/docx/ops/replace-paragraph-text-exact.js +21 -0
- package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +8 -0
- package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +23 -0
- package/dist/tools/docx/ops/set-color-for-style.d.ts +9 -0
- package/dist/tools/docx/ops/set-color-for-style.js +27 -0
- package/dist/tools/docx/ops/set-paragraph-style-at-body-index.d.ts +8 -0
- package/dist/tools/docx/ops/set-paragraph-style-at-body-index.js +57 -0
- package/dist/tools/docx/ops/table-set-cell-text.d.ts +9 -0
- package/dist/tools/docx/ops/table-set-cell-text.js +72 -0
- package/dist/tools/docx/parsers/image-extractor.d.ts +18 -0
- package/dist/tools/docx/parsers/image-extractor.js +61 -0
- package/dist/tools/docx/parsers/index.d.ts +9 -0
- package/dist/tools/docx/parsers/index.js +9 -0
- package/dist/tools/docx/parsers/paragraph-parser.d.ts +2 -0
- package/dist/tools/docx/parsers/paragraph-parser.js +88 -0
- package/dist/tools/docx/parsers/table-parser.d.ts +9 -0
- package/dist/tools/docx/parsers/table-parser.js +72 -0
- package/dist/tools/docx/parsers/xml-parser.d.ts +25 -0
- package/dist/tools/docx/parsers/xml-parser.js +71 -0
- package/dist/tools/docx/parsers/zip-reader.d.ts +23 -0
- package/dist/tools/docx/parsers/zip-reader.js +52 -0
- package/dist/tools/docx/read.d.ts +27 -0
- package/dist/tools/docx/read.js +188 -0
- package/dist/tools/docx/relationships.d.ts +22 -0
- package/dist/tools/docx/relationships.js +76 -0
- package/dist/tools/docx/structure.d.ts +25 -0
- package/dist/tools/docx/structure.js +102 -0
- package/dist/tools/docx/styled-html-parser.d.ts +23 -0
- package/dist/tools/docx/styled-html-parser.js +1262 -0
- package/dist/tools/docx/types.d.ts +184 -0
- package/dist/tools/docx/types.js +5 -0
- package/dist/tools/docx/utils/escaping.d.ts +13 -0
- package/dist/tools/docx/utils/escaping.js +26 -0
- package/dist/tools/docx/utils/images.d.ts +9 -0
- package/dist/tools/docx/utils/images.js +26 -0
- package/dist/tools/docx/utils/index.d.ts +12 -0
- package/dist/tools/docx/utils/index.js +17 -0
- package/dist/tools/docx/utils/markdown.d.ts +13 -0
- package/dist/tools/docx/utils/markdown.js +32 -0
- package/dist/tools/docx/utils/paths.d.ts +15 -0
- package/dist/tools/docx/utils/paths.js +27 -0
- package/dist/tools/docx/utils/versioning.d.ts +25 -0
- package/dist/tools/docx/utils/versioning.js +55 -0
- package/dist/tools/docx/utils.d.ts +101 -0
- package/dist/tools/docx/utils.js +299 -0
- package/dist/tools/docx/validate.d.ts +33 -0
- package/dist/tools/docx/validate.js +49 -0
- package/dist/tools/docx/validators.d.ts +13 -0
- package/dist/tools/docx/validators.js +40 -0
- package/dist/tools/docx/write.d.ts +17 -0
- package/dist/tools/docx/write.js +88 -0
- package/dist/tools/docx/zip.d.ts +21 -0
- package/dist/tools/docx/zip.js +35 -0
- package/dist/tools/schemas.d.ts +13 -0
- package/dist/tools/schemas.js +5 -0
- package/dist/types.d.ts +10 -0
- package/dist/ui/contracts.d.ts +14 -0
- package/dist/ui/contracts.js +18 -0
- package/dist/ui/file-preview/index.html +16 -0
- package/dist/ui/file-preview/preview-runtime.js +13977 -0
- package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
- package/dist/ui/file-preview/shared/preview-file-types.js +57 -0
- package/dist/ui/file-preview/src/app.d.ts +4 -0
- package/dist/ui/file-preview/src/app.js +800 -0
- package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
- package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
- package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
- package/dist/ui/file-preview/src/components/highlighting.js +54 -0
- package/dist/ui/file-preview/src/components/html-renderer.d.ts +9 -0
- package/dist/ui/file-preview/src/components/html-renderer.js +63 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.js +21 -0
- package/dist/ui/file-preview/src/components/toolbar.d.ts +6 -0
- package/dist/ui/file-preview/src/components/toolbar.js +75 -0
- package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
- package/dist/ui/file-preview/src/image-preview.js +21 -0
- package/dist/ui/file-preview/src/main.d.ts +1 -0
- package/dist/ui/file-preview/src/main.js +5 -0
- package/dist/ui/file-preview/src/types.d.ts +1 -0
- package/dist/ui/file-preview/src/types.js +1 -0
- package/dist/ui/file-preview/styles.css +764 -0
- package/dist/ui/resources.d.ts +21 -0
- package/dist/ui/resources.js +72 -0
- package/dist/ui/shared/escape-html.d.ts +4 -0
- package/dist/ui/shared/escape-html.js +11 -0
- package/dist/ui/shared/host-lifecycle.d.ts +16 -0
- package/dist/ui/shared/host-lifecycle.js +35 -0
- package/dist/ui/shared/rpc-client.d.ts +14 -0
- package/dist/ui/shared/rpc-client.js +72 -0
- package/dist/ui/shared/theme-adaptation.d.ts +10 -0
- package/dist/ui/shared/theme-adaptation.js +118 -0
- package/dist/ui/shared/tool-header.d.ts +9 -0
- package/dist/ui/shared/tool-header.js +25 -0
- package/dist/ui/shared/tool-shell.d.ts +16 -0
- package/dist/ui/shared/tool-shell.js +65 -0
- package/dist/ui/shared/widget-state.d.ts +28 -0
- package/dist/ui/shared/widget-state.js +60 -0
- package/dist/utils/capture.d.ts +1 -0
- package/dist/utils/capture.js +10 -4
- package/dist/utils/files/docx.d.ts +34 -0
- package/dist/utils/files/docx.js +145 -0
- package/dist/utils/files/text.js +9 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX Utility Functions
|
|
3
|
+
* Helper functions for DOCX operations, validation, and data transformation
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'fs/promises';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
// Import types from docx for image handling
|
|
8
|
+
// @ts-ignore - docx library has incomplete type definitions but exports exist at runtime
|
|
9
|
+
import * as docx from 'docx';
|
|
10
|
+
const { ImageRun, } = docx;
|
|
11
|
+
import { DocxError, DocxErrorCode, withErrorContext } from './errors.js';
|
|
12
|
+
/**
|
|
13
|
+
* Check if a string is a valid data URL
|
|
14
|
+
*/
|
|
15
|
+
export function isDataUrl(src) {
|
|
16
|
+
return src.startsWith('data:') && src.includes('base64,');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check if a source is a URL (http/https)
|
|
20
|
+
*/
|
|
21
|
+
export function isUrl(src) {
|
|
22
|
+
return src.startsWith('http://') || src.startsWith('https://');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse data URL into buffer
|
|
26
|
+
* @returns Buffer if successful, null if invalid
|
|
27
|
+
*/
|
|
28
|
+
export function parseDataUrl(dataUrl) {
|
|
29
|
+
try {
|
|
30
|
+
const match = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
|
|
31
|
+
if (!match)
|
|
32
|
+
return null;
|
|
33
|
+
return Buffer.from(match[2], 'base64');
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Resolve image path relative to base directory
|
|
41
|
+
*/
|
|
42
|
+
export function resolveImagePath(imagePath, baseDir) {
|
|
43
|
+
if (path.isAbsolute(imagePath) || isUrl(imagePath) || isDataUrl(imagePath)) {
|
|
44
|
+
return imagePath;
|
|
45
|
+
}
|
|
46
|
+
if (!baseDir) {
|
|
47
|
+
return path.resolve(imagePath);
|
|
48
|
+
}
|
|
49
|
+
return path.join(baseDir, imagePath);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check if a file exists
|
|
53
|
+
*/
|
|
54
|
+
export async function fileExists(filePath) {
|
|
55
|
+
try {
|
|
56
|
+
await fs.access(filePath);
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Validate image file
|
|
65
|
+
*/
|
|
66
|
+
export async function validateImageFile(imagePath) {
|
|
67
|
+
if (isDataUrl(imagePath)) {
|
|
68
|
+
const buffer = parseDataUrl(imagePath);
|
|
69
|
+
if (!buffer) {
|
|
70
|
+
return { valid: false, error: 'Invalid data URL format' };
|
|
71
|
+
}
|
|
72
|
+
return { valid: true };
|
|
73
|
+
}
|
|
74
|
+
if (isUrl(imagePath)) {
|
|
75
|
+
// For URLs, we'll validate during fetch
|
|
76
|
+
return { valid: true };
|
|
77
|
+
}
|
|
78
|
+
const exists = await fileExists(imagePath);
|
|
79
|
+
if (!exists) {
|
|
80
|
+
return { valid: false, error: `Image file not found: ${imagePath}` };
|
|
81
|
+
}
|
|
82
|
+
// Check file extension
|
|
83
|
+
const ext = path.extname(imagePath).toLowerCase();
|
|
84
|
+
const validExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.svg'];
|
|
85
|
+
if (!validExtensions.includes(ext)) {
|
|
86
|
+
return { valid: false, error: `Unsupported image format: ${ext}` };
|
|
87
|
+
}
|
|
88
|
+
return { valid: true };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Escape special regex characters for literal string matching
|
|
92
|
+
*/
|
|
93
|
+
export function escapeRegExp(str) {
|
|
94
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate markdown table format
|
|
98
|
+
*/
|
|
99
|
+
export function isValidMarkdownTable(markdown) {
|
|
100
|
+
const lines = markdown.trim().split('\n');
|
|
101
|
+
if (lines.length < 2)
|
|
102
|
+
return false;
|
|
103
|
+
// Check header row
|
|
104
|
+
const headerLine = lines[0].trim();
|
|
105
|
+
if (!headerLine.startsWith('|') || !headerLine.endsWith('|'))
|
|
106
|
+
return false;
|
|
107
|
+
// Check separator row
|
|
108
|
+
const separatorLine = lines[1].trim();
|
|
109
|
+
if (!separatorLine.startsWith('|') || !separatorLine.endsWith('|'))
|
|
110
|
+
return false;
|
|
111
|
+
// Verify separator contains dashes
|
|
112
|
+
const separatorPattern = /^(\|\s*:?-{2,}\s*:?\s*)+\|$/;
|
|
113
|
+
if (!separatorPattern.test(separatorLine))
|
|
114
|
+
return false;
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Build a markdown table from a 2D array of rows
|
|
119
|
+
*/
|
|
120
|
+
export function buildMarkdownTableFromRows(rows) {
|
|
121
|
+
if (!rows || rows.length === 0) {
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
const header = rows[0];
|
|
125
|
+
const dataRows = rows.slice(1);
|
|
126
|
+
const headerLine = `| ${header.join(' | ')} |`;
|
|
127
|
+
const separatorLine = `| ${header.map(() => '---').join(' | ')} |`;
|
|
128
|
+
const dataLines = dataRows.map((r) => `| ${r.join(' | ')} |`);
|
|
129
|
+
return [headerLine, separatorLine, ...dataLines].join('\n');
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Parse markdown table into 2D array
|
|
133
|
+
*/
|
|
134
|
+
export function parseMarkdownTable(markdown) {
|
|
135
|
+
if (!isValidMarkdownTable(markdown)) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const lines = markdown.trim().split('\n');
|
|
139
|
+
const rows = [];
|
|
140
|
+
for (let i = 0; i < lines.length; i++) {
|
|
141
|
+
// Skip separator line
|
|
142
|
+
if (i === 1)
|
|
143
|
+
continue;
|
|
144
|
+
const line = lines[i].trim();
|
|
145
|
+
const cells = line
|
|
146
|
+
.replace(/^\|/, '')
|
|
147
|
+
.replace(/\|$/, '')
|
|
148
|
+
.split('|')
|
|
149
|
+
.map(cell => cell.trim());
|
|
150
|
+
rows.push(cells);
|
|
151
|
+
}
|
|
152
|
+
return rows;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get MIME type from file extension or data URL
|
|
156
|
+
*/
|
|
157
|
+
export function getMimeType(source) {
|
|
158
|
+
if (isDataUrl(source)) {
|
|
159
|
+
const match = source.match(/^data:([^;]+);/);
|
|
160
|
+
return match ? match[1] : null;
|
|
161
|
+
}
|
|
162
|
+
const ext = path.extname(source).toLowerCase();
|
|
163
|
+
const mimeTypes = {
|
|
164
|
+
'.png': 'image/png',
|
|
165
|
+
'.jpg': 'image/jpeg',
|
|
166
|
+
'.jpeg': 'image/jpeg',
|
|
167
|
+
'.gif': 'image/gif',
|
|
168
|
+
'.bmp': 'image/bmp',
|
|
169
|
+
'.webp': 'image/webp',
|
|
170
|
+
'.svg': 'image/svg+xml',
|
|
171
|
+
};
|
|
172
|
+
return mimeTypes[ext] || null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Format file size in human-readable format
|
|
176
|
+
*/
|
|
177
|
+
export function formatFileSize(bytes) {
|
|
178
|
+
if (bytes === 0)
|
|
179
|
+
return '0 Bytes';
|
|
180
|
+
const k = 1024;
|
|
181
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
182
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
183
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Normalize line endings to \n
|
|
187
|
+
*/
|
|
188
|
+
export function normalizeLineEndings(text) {
|
|
189
|
+
return text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Split markdown into lines, preserving empty lines
|
|
193
|
+
*/
|
|
194
|
+
export function splitMarkdownLines(markdown) {
|
|
195
|
+
return normalizeLineEndings(markdown).split('\n');
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Validate DOCX file path
|
|
199
|
+
*/
|
|
200
|
+
export function isDocxPath(filePath) {
|
|
201
|
+
return filePath.toLowerCase().endsWith('.docx');
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Extract file name without extension
|
|
205
|
+
*/
|
|
206
|
+
export function getFileNameWithoutExtension(filePath) {
|
|
207
|
+
const basename = path.basename(filePath);
|
|
208
|
+
return basename.replace(/\.docx$/i, '');
|
|
209
|
+
}
|
|
210
|
+
// Re-export error handling from errors module
|
|
211
|
+
export { DocxError, DocxErrorCode, withErrorContext } from './errors.js';
|
|
212
|
+
/**
|
|
213
|
+
* Load and prepare an image for DOCX embedding
|
|
214
|
+
* Handles both local files and data URLs
|
|
215
|
+
*
|
|
216
|
+
* @param imagePath - Path to image file or data URL
|
|
217
|
+
* @param altText - Alternative text for the image
|
|
218
|
+
* @param baseDir - Base directory for resolving relative paths
|
|
219
|
+
* @returns Prepared image data ready for embedding
|
|
220
|
+
*/
|
|
221
|
+
export async function prepareImageForDocx(imagePath, altText = '', baseDir) {
|
|
222
|
+
return withErrorContext(async () => {
|
|
223
|
+
let buffer;
|
|
224
|
+
let mimeType = 'image/png'; // Default
|
|
225
|
+
// Handle data URL
|
|
226
|
+
if (isDataUrl(imagePath)) {
|
|
227
|
+
const parsed = parseDataUrl(imagePath);
|
|
228
|
+
if (!parsed) {
|
|
229
|
+
throw new DocxError('Invalid data URL format', DocxErrorCode.INVALID_IMAGE_DATA_URL, { imagePath: imagePath.substring(0, 50) });
|
|
230
|
+
}
|
|
231
|
+
buffer = parsed;
|
|
232
|
+
// Extract MIME type from data URL
|
|
233
|
+
const mimeMatch = imagePath.match(/^data:([^;]+);/);
|
|
234
|
+
if (mimeMatch) {
|
|
235
|
+
mimeType = mimeMatch[1];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Handle file path
|
|
240
|
+
const resolved = resolveImagePath(imagePath, baseDir);
|
|
241
|
+
// Validate image file
|
|
242
|
+
const validation = await validateImageFile(resolved);
|
|
243
|
+
if (!validation.valid) {
|
|
244
|
+
throw new DocxError(validation.error || 'Invalid image file', DocxErrorCode.INVALID_IMAGE_FILE, { imagePath: resolved });
|
|
245
|
+
}
|
|
246
|
+
// Read image file
|
|
247
|
+
try {
|
|
248
|
+
buffer = await fs.readFile(resolved);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
throw new DocxError(`Failed to read image file: ${error instanceof Error ? error.message : String(error)}`, DocxErrorCode.IMAGE_READ_FAILED, { imagePath: resolved });
|
|
252
|
+
}
|
|
253
|
+
// Determine MIME type from file extension
|
|
254
|
+
const ext = path.extname(resolved).toLowerCase();
|
|
255
|
+
const mimeTypes = {
|
|
256
|
+
'.png': 'image/png',
|
|
257
|
+
'.jpg': 'image/jpeg',
|
|
258
|
+
'.jpeg': 'image/jpeg',
|
|
259
|
+
'.gif': 'image/gif',
|
|
260
|
+
'.bmp': 'image/bmp',
|
|
261
|
+
'.webp': 'image/webp',
|
|
262
|
+
};
|
|
263
|
+
mimeType = mimeTypes[ext] || 'image/png';
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
buffer,
|
|
267
|
+
altText: altText || path.basename(imagePath),
|
|
268
|
+
mimeType,
|
|
269
|
+
// Default dimensions - can be customized
|
|
270
|
+
width: 600,
|
|
271
|
+
height: 400,
|
|
272
|
+
};
|
|
273
|
+
}, DocxErrorCode.IMAGE_PREPARATION_FAILED, { imagePath });
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Create an ImageRun instance for embedding in DOCX paragraphs
|
|
277
|
+
* This is a lower-level utility for direct image insertion
|
|
278
|
+
*
|
|
279
|
+
* @param imageData - Prepared image data
|
|
280
|
+
* @returns ImageRun instance ready to be added to a paragraph
|
|
281
|
+
*/
|
|
282
|
+
export function createImageRun(imageData) {
|
|
283
|
+
try {
|
|
284
|
+
return new ImageRun({
|
|
285
|
+
data: imageData.buffer,
|
|
286
|
+
transformation: {
|
|
287
|
+
width: imageData.width || 600,
|
|
288
|
+
height: imageData.height || 400,
|
|
289
|
+
},
|
|
290
|
+
altText: {
|
|
291
|
+
title: imageData.altText,
|
|
292
|
+
description: imageData.altText,
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
throw new DocxError(`Failed to create image run: ${error instanceof Error ? error.message : String(error)}`, DocxErrorCode.IMAGE_RUN_CREATION_FAILED);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant validation for DOCX write operations.
|
|
3
|
+
*
|
|
4
|
+
* Single Responsibility: capture a structural snapshot of w:body and
|
|
5
|
+
* compare before / after snapshots to guarantee no accidental breakage.
|
|
6
|
+
*/
|
|
7
|
+
import type { BodySnapshot } from './types.js';
|
|
8
|
+
export interface ValidationOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Expected change in w:body direct child count.
|
|
11
|
+
* Positive = inserts, negative = deletes.
|
|
12
|
+
* Default 0 (no structural changes expected).
|
|
13
|
+
*/
|
|
14
|
+
expectedChildDelta?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Expected change in w:tbl count.
|
|
17
|
+
* Default 0 (no table additions/removals expected).
|
|
18
|
+
*/
|
|
19
|
+
expectedTableDelta?: number;
|
|
20
|
+
}
|
|
21
|
+
/** Take a snapshot of the body's structural invariants. */
|
|
22
|
+
export declare function captureSnapshot(body: Element): BodySnapshot;
|
|
23
|
+
/**
|
|
24
|
+
* Compare before / after snapshots.
|
|
25
|
+
* Throws a descriptive error if any invariant has been violated,
|
|
26
|
+
* preventing the output file from being written.
|
|
27
|
+
*
|
|
28
|
+
* When `expectedChildDelta` is non-zero (structural ops like insert or
|
|
29
|
+
* delete), signature validation is skipped because the body structure
|
|
30
|
+
* is *expected* to change. Child count is still validated against
|
|
31
|
+
* the expected delta, and table count must remain unchanged.
|
|
32
|
+
*/
|
|
33
|
+
export declare function validateInvariants(before: BodySnapshot, after: BodySnapshot, options?: ValidationOptions): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invariant validation for DOCX write operations.
|
|
3
|
+
*
|
|
4
|
+
* Single Responsibility: capture a structural snapshot of w:body and
|
|
5
|
+
* compare before / after snapshots to guarantee no accidental breakage.
|
|
6
|
+
*/
|
|
7
|
+
import { getBodyChildren, bodySignature, countTables } from './dom.js';
|
|
8
|
+
// ─── Capture ─────────────────────────────────────────────────────────
|
|
9
|
+
/** Take a snapshot of the body's structural invariants. */
|
|
10
|
+
export function captureSnapshot(body) {
|
|
11
|
+
const children = getBodyChildren(body);
|
|
12
|
+
return {
|
|
13
|
+
bodyChildCount: children.length,
|
|
14
|
+
tableCount: countTables(children),
|
|
15
|
+
signature: bodySignature(children),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
// ─── Validate ────────────────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Compare before / after snapshots.
|
|
21
|
+
* Throws a descriptive error if any invariant has been violated,
|
|
22
|
+
* preventing the output file from being written.
|
|
23
|
+
*
|
|
24
|
+
* When `expectedChildDelta` is non-zero (structural ops like insert or
|
|
25
|
+
* delete), signature validation is skipped because the body structure
|
|
26
|
+
* is *expected* to change. Child count is still validated against
|
|
27
|
+
* the expected delta, and table count must remain unchanged.
|
|
28
|
+
*/
|
|
29
|
+
export function validateInvariants(before, after, options) {
|
|
30
|
+
const delta = options?.expectedChildDelta ?? 0;
|
|
31
|
+
const tableDelta = options?.expectedTableDelta ?? 0;
|
|
32
|
+
const expectedChildCount = before.bodyChildCount + delta;
|
|
33
|
+
const expectedTableCount = before.tableCount + tableDelta;
|
|
34
|
+
const errors = [];
|
|
35
|
+
if (expectedChildCount !== after.bodyChildCount) {
|
|
36
|
+
errors.push(`Body child count mismatch: expected ${expectedChildCount} (before ${before.bodyChildCount} + delta ${delta}), got ${after.bodyChildCount}`);
|
|
37
|
+
}
|
|
38
|
+
if (expectedTableCount !== after.tableCount) {
|
|
39
|
+
errors.push(`Table count mismatch: expected ${expectedTableCount} (before ${before.tableCount} + delta ${tableDelta}), got ${after.tableCount}`);
|
|
40
|
+
}
|
|
41
|
+
// Only enforce signature stability when no structural ops changed the body
|
|
42
|
+
if (delta === 0 && before.signature !== after.signature) {
|
|
43
|
+
errors.push(`Body signature changed:\n before: ${before.signature}\n after: ${after.signature}`);
|
|
44
|
+
}
|
|
45
|
+
if (errors.length > 0) {
|
|
46
|
+
throw new Error('DOCX structural validation failed — output NOT written.\n' +
|
|
47
|
+
errors.join('\n'));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Input validation for paths, operations arrays, and image dimensions.
|
|
5
|
+
*
|
|
6
|
+
* @module docx/validators
|
|
7
|
+
*/
|
|
8
|
+
/** Validate that a DOCX file path is a non-empty string ending in `.docx`. */
|
|
9
|
+
export declare function validateDocxPath(path: string): void;
|
|
10
|
+
/** Validate that an operations array is a non-empty array. */
|
|
11
|
+
export declare function validateOperations(operations: unknown[]): void;
|
|
12
|
+
/** Validate optional image width and height (must be positive and finite). */
|
|
13
|
+
export declare function validateImageDimensions(width?: number, height?: number): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Input validation for paths, operations arrays, and image dimensions.
|
|
5
|
+
*
|
|
6
|
+
* @module docx/validators
|
|
7
|
+
*/
|
|
8
|
+
import { DocxError, DocxErrorCode } from './errors.js';
|
|
9
|
+
import { isDocxPath } from './utils/paths.js';
|
|
10
|
+
/** Validate that a DOCX file path is a non-empty string ending in `.docx`. */
|
|
11
|
+
export function validateDocxPath(path) {
|
|
12
|
+
if (!path || typeof path !== 'string') {
|
|
13
|
+
throw new DocxError('DOCX path must be a non-empty string', DocxErrorCode.INVALID_PATH, { path });
|
|
14
|
+
}
|
|
15
|
+
const normalised = path.trim();
|
|
16
|
+
if (!normalised) {
|
|
17
|
+
throw new DocxError('DOCX path cannot be empty', DocxErrorCode.INVALID_PATH, { path });
|
|
18
|
+
}
|
|
19
|
+
if (!isDocxPath(normalised)) {
|
|
20
|
+
throw new DocxError('Invalid DOCX path: must end with .docx', DocxErrorCode.INVALID_PATH, { path: normalised });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Validate that an operations array is a non-empty array. */
|
|
24
|
+
export function validateOperations(operations) {
|
|
25
|
+
if (!Array.isArray(operations)) {
|
|
26
|
+
throw new DocxError('Operations must be an array', DocxErrorCode.OPERATION_FAILED, { operations });
|
|
27
|
+
}
|
|
28
|
+
if (operations.length === 0) {
|
|
29
|
+
throw new DocxError('Operations array cannot be empty', DocxErrorCode.OPERATION_FAILED, { operations });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Validate optional image width and height (must be positive and finite). */
|
|
33
|
+
export function validateImageDimensions(width, height) {
|
|
34
|
+
if (width !== undefined && (typeof width !== 'number' || width <= 0 || !Number.isFinite(width))) {
|
|
35
|
+
throw new DocxError('Image width must be a positive finite number', DocxErrorCode.INVALID_IMAGE_FILE, { width });
|
|
36
|
+
}
|
|
37
|
+
if (height !== undefined && (typeof height !== 'number' || height <= 0 || !Number.isFinite(height))) {
|
|
38
|
+
throw new DocxError('Image height must be a positive finite number', DocxErrorCode.INVALID_IMAGE_FILE, { height });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* writeDocxPatched - the patch-based "update" orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Single Responsibility: coordinate the full update pipeline:
|
|
5
|
+
* 1. Open DOCX ZIP
|
|
6
|
+
* 2. Parse word/document.xml
|
|
7
|
+
* 3. Snapshot before
|
|
8
|
+
* 4. Apply operations (pass zip for ops that touch auxiliary files)
|
|
9
|
+
* 5. Snapshot after
|
|
10
|
+
* 6. Validate invariants (accounting for structural deltas)
|
|
11
|
+
* 7. Serialize and save
|
|
12
|
+
*
|
|
13
|
+
* Each step delegates to a single-purpose module, keeping this file
|
|
14
|
+
* a pure orchestrator with no direct DOM/XML/ZIP logic.
|
|
15
|
+
*/
|
|
16
|
+
import type { DocxOp, WriteDocxResult } from './types.js';
|
|
17
|
+
export declare function writeDocxPatched(inputPath: string, outputPath: string, ops: DocxOp[]): Promise<WriteDocxResult>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* writeDocxPatched - the patch-based "update" orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Single Responsibility: coordinate the full update pipeline:
|
|
5
|
+
* 1. Open DOCX ZIP
|
|
6
|
+
* 2. Parse word/document.xml
|
|
7
|
+
* 3. Snapshot before
|
|
8
|
+
* 4. Apply operations (pass zip for ops that touch auxiliary files)
|
|
9
|
+
* 5. Snapshot after
|
|
10
|
+
* 6. Validate invariants (accounting for structural deltas)
|
|
11
|
+
* 7. Serialize and save
|
|
12
|
+
*
|
|
13
|
+
* Each step delegates to a single-purpose module, keeping this file
|
|
14
|
+
* a pure orchestrator with no direct DOM/XML/ZIP logic.
|
|
15
|
+
*/
|
|
16
|
+
import { loadDocxZip, getDocumentXml, saveDocxZip } from './zip.js';
|
|
17
|
+
import { parseXml, serializeXml, getBody } from './dom.js';
|
|
18
|
+
import { captureSnapshot, validateInvariants } from './validate.js';
|
|
19
|
+
import { applyOp } from './ops/index.js';
|
|
20
|
+
/** Structural op types that add/remove body children. */
|
|
21
|
+
const STRUCTURAL_INSERT_OPS = new Set([
|
|
22
|
+
'insert_paragraph_after_text',
|
|
23
|
+
'insert_table',
|
|
24
|
+
'insert_image',
|
|
25
|
+
]);
|
|
26
|
+
const STRUCTURAL_DELETE_OPS = new Set(['delete_paragraph_at_body_index']);
|
|
27
|
+
export async function writeDocxPatched(inputPath, outputPath, ops) {
|
|
28
|
+
// 1. Load ZIP
|
|
29
|
+
const zip = await loadDocxZip(inputPath);
|
|
30
|
+
// 2. Parse document.xml
|
|
31
|
+
const xmlStr = getDocumentXml(zip);
|
|
32
|
+
const doc = parseXml(xmlStr);
|
|
33
|
+
const body = getBody(doc);
|
|
34
|
+
// 3. Before-snapshot
|
|
35
|
+
const before = captureSnapshot(body);
|
|
36
|
+
// 4. Apply ops — pass zip for ops that modify auxiliary files
|
|
37
|
+
const results = [];
|
|
38
|
+
const warnings = [];
|
|
39
|
+
for (const op of ops) {
|
|
40
|
+
try {
|
|
41
|
+
const result = applyOp(body, op, zip);
|
|
42
|
+
results.push(result);
|
|
43
|
+
if (result.status === 'skipped') {
|
|
44
|
+
warnings.push(`Op ${op.type} skipped: ${result.reason ?? 'unknown'}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
49
|
+
warnings.push(`Op ${op.type} failed: ${msg}`);
|
|
50
|
+
results.push({
|
|
51
|
+
op,
|
|
52
|
+
status: 'skipped',
|
|
53
|
+
matched: 0,
|
|
54
|
+
reason: `error: ${msg}`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// 5. Compute expected structural delta from applied ops
|
|
59
|
+
let expectedChildDelta = 0;
|
|
60
|
+
let expectedTableDelta = 0;
|
|
61
|
+
for (const r of results) {
|
|
62
|
+
if (r.status !== 'applied')
|
|
63
|
+
continue;
|
|
64
|
+
if (STRUCTURAL_INSERT_OPS.has(r.op.type))
|
|
65
|
+
expectedChildDelta += 1;
|
|
66
|
+
if (STRUCTURAL_DELETE_OPS.has(r.op.type))
|
|
67
|
+
expectedChildDelta -= 1;
|
|
68
|
+
if (r.op.type === 'insert_table')
|
|
69
|
+
expectedTableDelta += 1;
|
|
70
|
+
}
|
|
71
|
+
// 6. After-snapshot
|
|
72
|
+
const after = captureSnapshot(body);
|
|
73
|
+
// 7. Validate — throws if structural invariants are broken
|
|
74
|
+
validateInvariants(before, after, { expectedChildDelta, expectedTableDelta });
|
|
75
|
+
// 8. Serialize and save (document.xml + any zip-level changes)
|
|
76
|
+
const newXml = serializeXml(doc);
|
|
77
|
+
await saveDocxZip(zip, newXml, outputPath);
|
|
78
|
+
// 9. Build stats
|
|
79
|
+
const stats = {
|
|
80
|
+
tablesBefore: before.tableCount,
|
|
81
|
+
tablesAfter: after.tableCount,
|
|
82
|
+
bodyChildrenBefore: before.bodyChildCount,
|
|
83
|
+
bodyChildrenAfter: after.bodyChildCount,
|
|
84
|
+
bodySignatureBefore: before.signature,
|
|
85
|
+
bodySignatureAfter: after.signature,
|
|
86
|
+
};
|
|
87
|
+
return { outputPath, results, stats, warnings };
|
|
88
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX ZIP I/O — Single Responsibility: file ↔ zip ↔ xml.
|
|
3
|
+
*
|
|
4
|
+
* Every other module depends on these three functions for disk I/O;
|
|
5
|
+
* none of them touch the file system directly.
|
|
6
|
+
*/
|
|
7
|
+
import PizZip from 'pizzip';
|
|
8
|
+
/**
|
|
9
|
+
* Read a .docx file from disk and return a PizZip instance.
|
|
10
|
+
*/
|
|
11
|
+
export declare function loadDocxZip(filePath: string): Promise<PizZip>;
|
|
12
|
+
/**
|
|
13
|
+
* Extract the raw XML string from word/document.xml inside the zip.
|
|
14
|
+
* Throws if the entry is missing.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDocumentXml(zip: PizZip): string;
|
|
17
|
+
/**
|
|
18
|
+
* Replace word/document.xml in the zip with new XML,
|
|
19
|
+
* then write the whole archive to outputPath.
|
|
20
|
+
*/
|
|
21
|
+
export declare function saveDocxZip(zip: PizZip, newDocumentXml: string, outputPath: string): Promise<void>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX ZIP I/O — Single Responsibility: file ↔ zip ↔ xml.
|
|
3
|
+
*
|
|
4
|
+
* Every other module depends on these three functions for disk I/O;
|
|
5
|
+
* none of them touch the file system directly.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'fs/promises';
|
|
8
|
+
import PizZip from 'pizzip';
|
|
9
|
+
/**
|
|
10
|
+
* Read a .docx file from disk and return a PizZip instance.
|
|
11
|
+
*/
|
|
12
|
+
export async function loadDocxZip(filePath) {
|
|
13
|
+
const buf = await fs.readFile(filePath);
|
|
14
|
+
return new PizZip(buf);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Extract the raw XML string from word/document.xml inside the zip.
|
|
18
|
+
* Throws if the entry is missing.
|
|
19
|
+
*/
|
|
20
|
+
export function getDocumentXml(zip) {
|
|
21
|
+
const entry = zip.file('word/document.xml');
|
|
22
|
+
if (!entry) {
|
|
23
|
+
throw new Error('Invalid DOCX: missing word/document.xml');
|
|
24
|
+
}
|
|
25
|
+
return entry.asText();
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Replace word/document.xml in the zip with new XML,
|
|
29
|
+
* then write the whole archive to outputPath.
|
|
30
|
+
*/
|
|
31
|
+
export async function saveDocxZip(zip, newDocumentXml, outputPath) {
|
|
32
|
+
zip.file('word/document.xml', newDocumentXml);
|
|
33
|
+
const buf = zip.generate({ type: 'nodebuffer' });
|
|
34
|
+
await fs.writeFile(outputPath, buf);
|
|
35
|
+
}
|
package/dist/tools/schemas.d.ts
CHANGED
|
@@ -401,3 +401,16 @@ export declare const GetRecentToolCallsArgsSchema: z.ZodObject<{
|
|
|
401
401
|
toolName?: string | undefined;
|
|
402
402
|
since?: string | undefined;
|
|
403
403
|
}>;
|
|
404
|
+
export declare const TrackUiEventArgsSchema: z.ZodObject<{
|
|
405
|
+
event: z.ZodString;
|
|
406
|
+
component: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
407
|
+
params: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>>>;
|
|
408
|
+
}, "strip", z.ZodTypeAny, {
|
|
409
|
+
params: Record<string, string | number | boolean | null>;
|
|
410
|
+
event: string;
|
|
411
|
+
component: string;
|
|
412
|
+
}, {
|
|
413
|
+
event: string;
|
|
414
|
+
params?: Record<string, string | number | boolean | null> | undefined;
|
|
415
|
+
component?: string | undefined;
|
|
416
|
+
}>;
|
package/dist/tools/schemas.js
CHANGED
|
@@ -175,3 +175,8 @@ export const GetRecentToolCallsArgsSchema = z.object({
|
|
|
175
175
|
toolName: z.string().optional(),
|
|
176
176
|
since: z.string().datetime().optional(),
|
|
177
177
|
});
|
|
178
|
+
export const TrackUiEventArgsSchema = z.object({
|
|
179
|
+
event: z.string().min(1).max(80),
|
|
180
|
+
component: z.string().optional().default('file_preview'),
|
|
181
|
+
params: z.record(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional().default({}),
|
|
182
|
+
});
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ChildProcess } from 'child_process';
|
|
2
2
|
import { FilteredStdioServerTransport } from './custom-stdio.js';
|
|
3
|
+
import type { PreviewFileType } from './ui/file-preview/shared/preview-file-types.js';
|
|
3
4
|
declare global {
|
|
4
5
|
var mcpTransport: FilteredStdioServerTransport | undefined;
|
|
5
6
|
var disableOnboarding: boolean | undefined;
|
|
@@ -60,8 +61,17 @@ export interface ServerResponseContent {
|
|
|
60
61
|
data?: string;
|
|
61
62
|
mimeType?: string;
|
|
62
63
|
}
|
|
64
|
+
export interface FilePreviewStructuredContent {
|
|
65
|
+
fileName: string;
|
|
66
|
+
filePath: string;
|
|
67
|
+
fileType: PreviewFileType;
|
|
68
|
+
content: string;
|
|
69
|
+
imageData?: string;
|
|
70
|
+
mimeType?: string;
|
|
71
|
+
}
|
|
63
72
|
export interface ServerResult {
|
|
64
73
|
content: ServerResponseContent[];
|
|
74
|
+
structuredContent?: FilePreviewStructuredContent | Record<string, unknown>;
|
|
65
75
|
isError?: boolean;
|
|
66
76
|
_meta?: Record<string, unknown>;
|
|
67
77
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central constants and shape contracts for UI resource identifiers. It gives one source of truth for URIs/tool metadata shared between server handlers and UI loaders.
|
|
3
|
+
*/
|
|
4
|
+
export declare const FILE_PREVIEW_RESOURCE_URI = "ui://desktop-commander/file-preview";
|
|
5
|
+
export declare const CONFIG_EDITOR_RESOURCE_URI = "ui://desktop-commander/config-editor";
|
|
6
|
+
export interface UiToolMeta extends Record<string, unknown> {
|
|
7
|
+
'ui/resourceUri': string;
|
|
8
|
+
'openai/outputTemplate': string;
|
|
9
|
+
ui: {
|
|
10
|
+
resourceUri: string;
|
|
11
|
+
};
|
|
12
|
+
'openai/widgetAccessible'?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function buildUiToolMeta(resourceUri: string, widgetAccessible?: boolean): UiToolMeta;
|