@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
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ Work with code and text, run processes, and automate tasks, going far beyond oth
|
|
|
16
16
|
<img width="380" height="200" src="https://glama.ai/mcp/servers/zempur9oh4/badge" alt="Desktop Commander MCP" />
|
|
17
17
|
</a>
|
|
18
18
|
|
|
19
|
+
## 👋 We’re hiring — come build with us: https://desktopcommander.app/careers/
|
|
20
|
+
|
|
19
21
|
## Table of Contents
|
|
20
22
|
- [Features](#features)
|
|
21
23
|
- [How to install](#how-to-install)
|
|
@@ -3,11 +3,34 @@ import { withTimeout } from '../utils/withTimeout.js';
|
|
|
3
3
|
import { createErrorResponse } from '../error-handlers.js';
|
|
4
4
|
import { configManager } from '../config-manager.js';
|
|
5
5
|
import { ReadFileArgsSchema, ReadMultipleFilesArgsSchema, WriteFileArgsSchema, CreateDirectoryArgsSchema, ListDirectoryArgsSchema, MoveFileArgsSchema, GetFileInfoArgsSchema, WritePdfArgsSchema } from '../tools/schemas.js';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import { buildUiToolMeta, FILE_PREVIEW_RESOURCE_URI } from '../ui/contracts.js';
|
|
9
|
+
import { resolvePreviewFileType } from '../ui/file-preview/shared/preview-file-types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Expand home directory (~) in a file path
|
|
12
|
+
*/
|
|
13
|
+
function expandHome(filePath) {
|
|
14
|
+
if (filePath === '~' || filePath.startsWith('~/') || filePath.startsWith(`~${path.sep}`)) {
|
|
15
|
+
return path.join(os.homedir(), filePath.slice(1));
|
|
16
|
+
}
|
|
17
|
+
return filePath;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a file path to an absolute path for use in structured content.
|
|
21
|
+
* This ensures "Open in folder" always has a valid absolute path.
|
|
22
|
+
*/
|
|
23
|
+
function resolveAbsolutePath(filePath) {
|
|
24
|
+
const expanded = expandHome(filePath);
|
|
25
|
+
return path.isAbsolute(expanded)
|
|
26
|
+
? path.resolve(expanded)
|
|
27
|
+
: path.resolve(process.cwd(), expanded);
|
|
28
|
+
}
|
|
6
29
|
/**
|
|
7
30
|
* Helper function to check if path contains an error
|
|
8
31
|
*/
|
|
9
|
-
function isErrorPath(
|
|
10
|
-
return
|
|
32
|
+
function isErrorPath(filePath) {
|
|
33
|
+
return filePath.startsWith('__ERROR__:');
|
|
11
34
|
}
|
|
12
35
|
/**
|
|
13
36
|
* Extract error message from error path
|
|
@@ -44,6 +67,10 @@ export async function handleReadFile(args) {
|
|
|
44
67
|
sheet: sheetParam,
|
|
45
68
|
range: parsed.range
|
|
46
69
|
};
|
|
70
|
+
// Resolve to absolute path for local files (not URLs) so "Open in folder" works
|
|
71
|
+
const resolvedFilePath = parsed.isUrl
|
|
72
|
+
? parsed.path
|
|
73
|
+
: resolveAbsolutePath(parsed.path);
|
|
47
74
|
const fileResult = await readFile(parsed.path, options);
|
|
48
75
|
// Handle PDF files
|
|
49
76
|
if (fileResult.metadata?.isPdf) {
|
|
@@ -68,28 +95,40 @@ export async function handleReadFile(args) {
|
|
|
68
95
|
text: `PDF file: ${parsed.path}${author}${title} (${meta?.totalPages} pages) \n`
|
|
69
96
|
},
|
|
70
97
|
...pdfContent
|
|
71
|
-
]
|
|
98
|
+
],
|
|
99
|
+
structuredContent: {
|
|
100
|
+
fileName: path.basename(resolvedFilePath),
|
|
101
|
+
filePath: resolvedFilePath,
|
|
102
|
+
fileType: 'unsupported',
|
|
103
|
+
content: ''
|
|
104
|
+
},
|
|
105
|
+
_meta: buildUiToolMeta(FILE_PREVIEW_RESOURCE_URI, true)
|
|
72
106
|
};
|
|
73
107
|
}
|
|
74
108
|
// Handle image files
|
|
75
109
|
if (fileResult.metadata?.isImage) {
|
|
76
|
-
// For image files,
|
|
77
|
-
//
|
|
110
|
+
// For image files, keep content payload text-only for broad host compatibility.
|
|
111
|
+
// The preview widget reads image bytes from structuredContent.
|
|
78
112
|
const imageData = typeof fileResult.content === 'string'
|
|
79
113
|
? fileResult.content
|
|
80
114
|
: fileResult.content.toString('base64');
|
|
115
|
+
const imageSummary = `Image file: ${parsed.path} (${fileResult.mimeType})\n`;
|
|
81
116
|
return {
|
|
82
117
|
content: [
|
|
83
118
|
{
|
|
84
119
|
type: "text",
|
|
85
|
-
text:
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
type: "image",
|
|
89
|
-
data: imageData,
|
|
90
|
-
mimeType: fileResult.mimeType
|
|
120
|
+
text: imageSummary
|
|
91
121
|
}
|
|
92
122
|
],
|
|
123
|
+
structuredContent: {
|
|
124
|
+
fileName: path.basename(resolvedFilePath),
|
|
125
|
+
filePath: resolvedFilePath,
|
|
126
|
+
fileType: 'image',
|
|
127
|
+
content: imageSummary,
|
|
128
|
+
imageData,
|
|
129
|
+
mimeType: fileResult.mimeType
|
|
130
|
+
},
|
|
131
|
+
_meta: buildUiToolMeta(FILE_PREVIEW_RESOURCE_URI, true)
|
|
93
132
|
};
|
|
94
133
|
}
|
|
95
134
|
else {
|
|
@@ -97,8 +136,16 @@ export async function handleReadFile(args) {
|
|
|
97
136
|
const textContent = typeof fileResult.content === 'string'
|
|
98
137
|
? fileResult.content
|
|
99
138
|
: fileResult.content.toString('utf8');
|
|
139
|
+
const previewFileType = resolvePreviewFileType(resolvedFilePath);
|
|
100
140
|
return {
|
|
101
141
|
content: [{ type: "text", text: textContent }],
|
|
142
|
+
structuredContent: {
|
|
143
|
+
fileName: path.basename(resolvedFilePath),
|
|
144
|
+
filePath: resolvedFilePath,
|
|
145
|
+
fileType: previewFileType,
|
|
146
|
+
content: textContent
|
|
147
|
+
},
|
|
148
|
+
_meta: buildUiToolMeta(FILE_PREVIEW_RESOURCE_URI, true)
|
|
102
149
|
};
|
|
103
150
|
}
|
|
104
151
|
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { ServerResult } from '../types.js';
|
|
2
|
+
type TrackUiEventParams = Record<string, string | number | boolean | null>;
|
|
3
|
+
export declare function buildTrackUiEventCapturePayload(event: string, component: string, params: TrackUiEventParams): Record<string, string | number | boolean | null>;
|
|
2
4
|
/**
|
|
3
5
|
* Handle get_recent_tool_calls command
|
|
4
6
|
*/
|
|
5
7
|
export declare function handleGetRecentToolCalls(args: unknown): Promise<ServerResult>;
|
|
8
|
+
/**
|
|
9
|
+
* Handle track_ui_event command
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleTrackUiEvent(args: unknown): Promise<ServerResult>;
|
|
12
|
+
export {};
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { toolHistory } from '../utils/toolHistory.js';
|
|
2
|
-
import { GetRecentToolCallsArgsSchema } from '../tools/schemas.js';
|
|
2
|
+
import { GetRecentToolCallsArgsSchema, TrackUiEventArgsSchema } from '../tools/schemas.js';
|
|
3
|
+
import { capture_ui_event } from '../utils/capture.js';
|
|
4
|
+
export function buildTrackUiEventCapturePayload(event, component, params) {
|
|
5
|
+
return {
|
|
6
|
+
...params,
|
|
7
|
+
component,
|
|
8
|
+
event
|
|
9
|
+
};
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* Handle get_recent_tool_calls command
|
|
5
13
|
*/
|
|
@@ -33,3 +41,27 @@ export async function handleGetRecentToolCalls(args) {
|
|
|
33
41
|
};
|
|
34
42
|
}
|
|
35
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Handle track_ui_event command
|
|
46
|
+
*/
|
|
47
|
+
export async function handleTrackUiEvent(args) {
|
|
48
|
+
try {
|
|
49
|
+
const parsed = TrackUiEventArgsSchema.parse(args);
|
|
50
|
+
await capture_ui_event('mcp_ui_event', buildTrackUiEventCapturePayload(parsed.event, parsed.component, parsed.params));
|
|
51
|
+
return {
|
|
52
|
+
content: [{
|
|
53
|
+
type: "text",
|
|
54
|
+
text: `Tracked UI event: ${parsed.event}`
|
|
55
|
+
}]
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
return {
|
|
60
|
+
content: [{
|
|
61
|
+
type: "text",
|
|
62
|
+
text: `Error tracking UI event: ${error instanceof Error ? error.message : String(error)}`
|
|
63
|
+
}],
|
|
64
|
+
isError: true
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
4
4
|
import { getSystemInfo, getOSSpecificGuidance, getPathGuidance, getDevelopmentToolGuidance } from './utils/system-info.js';
|
|
5
5
|
// Get system information once at startup
|
|
@@ -21,6 +21,8 @@ import { handleWelcomePageOnboarding } from './utils/welcome-onboarding.js';
|
|
|
21
21
|
import { VERSION } from './version.js';
|
|
22
22
|
import { capture, capture_call_tool } from "./utils/capture.js";
|
|
23
23
|
import { logToStderr, logger } from './utils/logger.js';
|
|
24
|
+
import { buildUiToolMeta, FILE_PREVIEW_RESOURCE_URI } from './ui/contracts.js';
|
|
25
|
+
import { listUiResources, readUiResource } from './ui/resources.js';
|
|
24
26
|
// Store startup messages to send after initialization
|
|
25
27
|
const deferredMessages = [];
|
|
26
28
|
function deferLog(level, message) {
|
|
@@ -47,11 +49,18 @@ export const server = new Server({
|
|
|
47
49
|
});
|
|
48
50
|
// Add handler for resources/list method
|
|
49
51
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
50
|
-
// Return an empty list of resources
|
|
51
52
|
return {
|
|
52
|
-
resources:
|
|
53
|
+
resources: listUiResources(),
|
|
53
54
|
};
|
|
54
55
|
});
|
|
56
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
57
|
+
const { uri } = request.params;
|
|
58
|
+
const response = await readUiResource(uri);
|
|
59
|
+
if (response) {
|
|
60
|
+
return response;
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
63
|
+
});
|
|
55
64
|
// Add handler for prompts/list method
|
|
56
65
|
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
57
66
|
// Return an empty list of prompts
|
|
@@ -237,6 +246,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
237
246
|
${PATH_GUIDANCE}
|
|
238
247
|
${CMD_PREFIX_DESCRIPTION}`,
|
|
239
248
|
inputSchema: zodToJsonSchema(ReadFileArgsSchema),
|
|
249
|
+
_meta: buildUiToolMeta(FILE_PREVIEW_RESOURCE_URI, true),
|
|
240
250
|
annotations: {
|
|
241
251
|
title: "Read File or URL",
|
|
242
252
|
readOnlyHint: true,
|
|
@@ -1179,6 +1189,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1179
1189
|
};
|
|
1180
1190
|
}
|
|
1181
1191
|
break;
|
|
1192
|
+
case "track_ui_event":
|
|
1193
|
+
try {
|
|
1194
|
+
result = await handlers.handleTrackUiEvent(args);
|
|
1195
|
+
}
|
|
1196
|
+
catch (error) {
|
|
1197
|
+
capture('server_request_error', { message: `Error in track_ui_event handler: ${error}` });
|
|
1198
|
+
result = {
|
|
1199
|
+
content: [{ type: "text", text: `Error: Failed to track UI event` }],
|
|
1200
|
+
isError: true,
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
break;
|
|
1182
1204
|
case "give_feedback_to_desktop_commander":
|
|
1183
1205
|
try {
|
|
1184
1206
|
result = await giveFeedbackToDesktopCommander(args);
|
|
@@ -1265,12 +1287,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1265
1287
|
// Add tool call to history (exclude only get_recent_tool_calls to prevent recursion)
|
|
1266
1288
|
const duration = Date.now() - startTime;
|
|
1267
1289
|
const EXCLUDED_TOOLS = [
|
|
1268
|
-
'get_recent_tool_calls'
|
|
1290
|
+
'get_recent_tool_calls',
|
|
1291
|
+
'track_ui_event'
|
|
1269
1292
|
];
|
|
1270
1293
|
if (!EXCLUDED_TOOLS.includes(name)) {
|
|
1271
1294
|
toolHistory.addCall(name, args, result, duration);
|
|
1272
1295
|
}
|
|
1273
1296
|
// Track success or failure based on result
|
|
1297
|
+
if (name === 'track_ui_event') {
|
|
1298
|
+
return result;
|
|
1299
|
+
}
|
|
1274
1300
|
if (result.isError) {
|
|
1275
1301
|
await usageTracker.trackFailure(name);
|
|
1276
1302
|
console.log(`[FEEDBACK DEBUG] Tool ${name} failed, not checking feedback`);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML → DOCX Conversion (html-to-docx)
|
|
3
|
+
*
|
|
4
|
+
* Converts processed HTML content into a DOCX buffer, injecting the original
|
|
5
|
+
* document's default font and font size so unstyled text keeps its appearance.
|
|
6
|
+
*
|
|
7
|
+
* @module docx/builders/html-builder
|
|
8
|
+
*/
|
|
9
|
+
import type { DocxBuildOptions } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Create a DOCX Buffer from HTML content.
|
|
12
|
+
*
|
|
13
|
+
* @param html - HTML content to convert
|
|
14
|
+
* @param options - Build options (baseDir, documentDefaults, etc.)
|
|
15
|
+
* @returns DOCX file as a Buffer
|
|
16
|
+
*/
|
|
17
|
+
export declare function createDocxFromHtml(html: string, options?: DocxBuildOptions): Promise<Buffer>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML → DOCX Conversion (html-to-docx)
|
|
3
|
+
*
|
|
4
|
+
* Converts processed HTML content into a DOCX buffer, injecting the original
|
|
5
|
+
* document's default font and font size so unstyled text keeps its appearance.
|
|
6
|
+
*
|
|
7
|
+
* @module docx/builders/html-builder
|
|
8
|
+
*/
|
|
9
|
+
import { createRequire } from 'module';
|
|
10
|
+
import { DocxError, DocxErrorCode, withErrorContext } from '../errors.js';
|
|
11
|
+
import { DEFAULT_BUILD_OPTIONS, HTML_WRAPPER_TEMPLATE } from '../constants.js';
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const HTMLtoDOCX = require('html-to-docx');
|
|
14
|
+
// ─── HTML Structure Helpers ──────────────────────────────────────────────────
|
|
15
|
+
/** Build a `<style>` tag with the original document's default font/size as CSS `body` rules. */
|
|
16
|
+
function buildDefaultStyleTag(defaults) {
|
|
17
|
+
if (!defaults)
|
|
18
|
+
return '';
|
|
19
|
+
const rules = [];
|
|
20
|
+
if (defaults.font)
|
|
21
|
+
rules.push(`font-family: '${defaults.font}'`);
|
|
22
|
+
if (defaults.fontSize)
|
|
23
|
+
rules.push(`font-size: ${defaults.fontSize}pt`);
|
|
24
|
+
if (rules.length === 0)
|
|
25
|
+
return '';
|
|
26
|
+
return `<style>body { ${rules.join('; ')}; }</style>`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Ensure the HTML has a proper structure (DOCTYPE, `<html>`, `<head>`, `<body>`).
|
|
30
|
+
* Injects the document-default CSS into `<head>` when available.
|
|
31
|
+
*/
|
|
32
|
+
function ensureHtmlStructure(html, defaults) {
|
|
33
|
+
const trimmed = html.trim();
|
|
34
|
+
const styleTag = buildDefaultStyleTag(defaults);
|
|
35
|
+
if (!trimmed) {
|
|
36
|
+
const wrapped = HTML_WRAPPER_TEMPLATE.split('{content}').join('');
|
|
37
|
+
return styleTag ? wrapped.replace('</head>', `${styleTag}\n</head>`) : wrapped;
|
|
38
|
+
}
|
|
39
|
+
const lower = trimmed.toLowerCase();
|
|
40
|
+
const hasDoctype = lower.startsWith('<!doctype');
|
|
41
|
+
const hasHtml = lower.includes('<html');
|
|
42
|
+
const hasBody = lower.includes('<body');
|
|
43
|
+
// Already complete — inject styles only
|
|
44
|
+
if (hasDoctype && hasHtml && hasBody) {
|
|
45
|
+
if (styleTag && trimmed.includes('</head>')) {
|
|
46
|
+
return trimmed.replace('</head>', `${styleTag}\n</head>`);
|
|
47
|
+
}
|
|
48
|
+
return trimmed;
|
|
49
|
+
}
|
|
50
|
+
// Partial structure — add DOCTYPE, inject styles
|
|
51
|
+
if (hasHtml || hasBody) {
|
|
52
|
+
const result = `<!DOCTYPE html>\n${trimmed}`;
|
|
53
|
+
return styleTag && result.includes('</head>')
|
|
54
|
+
? result.replace('</head>', `${styleTag}\n</head>`)
|
|
55
|
+
: result;
|
|
56
|
+
}
|
|
57
|
+
// Plain fragment — wrap fully
|
|
58
|
+
// Use split/join instead of replace to avoid $-pattern interpretation in base64 data URLs
|
|
59
|
+
const wrapped = HTML_WRAPPER_TEMPLATE.split('{content}').join(trimmed);
|
|
60
|
+
return styleTag ? wrapped.replace('</head>', `${styleTag}\n</head>`) : wrapped;
|
|
61
|
+
}
|
|
62
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
63
|
+
/**
|
|
64
|
+
* Create a DOCX Buffer from HTML content.
|
|
65
|
+
*
|
|
66
|
+
* @param html - HTML content to convert
|
|
67
|
+
* @param options - Build options (baseDir, documentDefaults, etc.)
|
|
68
|
+
* @returns DOCX file as a Buffer
|
|
69
|
+
*/
|
|
70
|
+
export async function createDocxFromHtml(html, options = {}) {
|
|
71
|
+
return withErrorContext(async () => {
|
|
72
|
+
if (!html?.trim()) {
|
|
73
|
+
throw new DocxError('HTML content cannot be empty', DocxErrorCode.DOCX_CREATE_FAILED, { htmlLength: 0 });
|
|
74
|
+
}
|
|
75
|
+
const defaults = options.documentDefaults;
|
|
76
|
+
const processedHtml = ensureHtmlStructure(html, defaults);
|
|
77
|
+
const docxOptions = {
|
|
78
|
+
table: { row: { cantSplit: true } },
|
|
79
|
+
footer: DEFAULT_BUILD_OPTIONS.footer,
|
|
80
|
+
pageNumber: DEFAULT_BUILD_OPTIONS.pageNumber,
|
|
81
|
+
font: defaults?.font || DEFAULT_BUILD_OPTIONS.font,
|
|
82
|
+
fontSize: defaults?.fontSize || DEFAULT_BUILD_OPTIONS.fontSize,
|
|
83
|
+
orientation: DEFAULT_BUILD_OPTIONS.orientation,
|
|
84
|
+
margins: { ...DEFAULT_BUILD_OPTIONS.margins },
|
|
85
|
+
};
|
|
86
|
+
const docxBuffer = await HTMLtoDOCX(processedHtml, null, docxOptions);
|
|
87
|
+
if (!docxBuffer || docxBuffer.length === 0) {
|
|
88
|
+
throw new DocxError('Failed to generate DOCX: empty buffer', DocxErrorCode.DOCX_CREATE_FAILED, { htmlLength: html.length });
|
|
89
|
+
}
|
|
90
|
+
return Buffer.from(docxBuffer);
|
|
91
|
+
}, DocxErrorCode.DOCX_CREATE_FAILED, { htmlLength: html.length });
|
|
92
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image builder — creates w:drawing elements and manages image relationships.
|
|
3
|
+
*/
|
|
4
|
+
import PizZip from 'pizzip';
|
|
5
|
+
import type { DocxContentImage, InsertImageOp } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Build an image element and add it to the ZIP archive.
|
|
8
|
+
*
|
|
9
|
+
* @param doc The XML document
|
|
10
|
+
* @param zip The DOCX ZIP archive
|
|
11
|
+
* @param spec The image specification (from content or operation)
|
|
12
|
+
* @returns A w:p element containing the image drawing
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildImageElement(doc: Document, zip: PizZip, spec: DocxContentImage | InsertImageOp): Promise<Element>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Image builder — creates w:drawing elements and manages image relationships.
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'fs/promises';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { DOMParser } from '@xmldom/xmldom';
|
|
7
|
+
import { addImageRelationship, ensureContentType } from '../relationships.js';
|
|
8
|
+
import { escapeXmlAttr } from './utils.js';
|
|
9
|
+
import { pixelsToEmu, DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, NAMESPACES } from '../constants.js';
|
|
10
|
+
/**
|
|
11
|
+
* Build an image element and add it to the ZIP archive.
|
|
12
|
+
*
|
|
13
|
+
* @param doc The XML document
|
|
14
|
+
* @param zip The DOCX ZIP archive
|
|
15
|
+
* @param spec The image specification (from content or operation)
|
|
16
|
+
* @returns A w:p element containing the image drawing
|
|
17
|
+
*/
|
|
18
|
+
export async function buildImageElement(doc, zip, spec) {
|
|
19
|
+
// Validate image exists
|
|
20
|
+
try {
|
|
21
|
+
await fs.access(spec.imagePath);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new Error(`Image file not found: ${spec.imagePath}`);
|
|
25
|
+
}
|
|
26
|
+
// Read image
|
|
27
|
+
const imgBuffer = await fs.readFile(spec.imagePath);
|
|
28
|
+
const ext = path.extname(spec.imagePath).toLowerCase();
|
|
29
|
+
const baseName = path.basename(spec.imagePath);
|
|
30
|
+
// Find next available media filename
|
|
31
|
+
let mediaIndex = 1;
|
|
32
|
+
while (zip.file(`word/media/image${mediaIndex}${ext}`)) {
|
|
33
|
+
mediaIndex++;
|
|
34
|
+
}
|
|
35
|
+
const mediaFileName = `image${mediaIndex}${ext}`;
|
|
36
|
+
// Add image to ZIP
|
|
37
|
+
zip.file(`word/media/${mediaFileName}`, imgBuffer);
|
|
38
|
+
// Add relationship
|
|
39
|
+
const rId = addImageRelationship(zip, mediaFileName);
|
|
40
|
+
// Ensure Content_Types entry
|
|
41
|
+
ensureContentType(zip, ext);
|
|
42
|
+
// Compute dimensions (EMU)
|
|
43
|
+
const widthPx = spec.width ?? DEFAULT_IMAGE_WIDTH;
|
|
44
|
+
const heightPx = spec.height ?? DEFAULT_IMAGE_HEIGHT;
|
|
45
|
+
const widthEmu = pixelsToEmu(widthPx);
|
|
46
|
+
const heightEmu = pixelsToEmu(heightPx);
|
|
47
|
+
// Build drawing XML
|
|
48
|
+
const altText = spec.altText ?? baseName;
|
|
49
|
+
const drawingXmlStr = buildDrawingXml(rId, widthEmu, heightEmu, altText, mediaFileName);
|
|
50
|
+
// Parse drawing XML into a paragraph
|
|
51
|
+
const drawingFragment = new DOMParser().parseFromString(`<w:p xmlns:w="${NAMESPACES.W}">` +
|
|
52
|
+
`<w:r>${drawingXmlStr}</w:r></w:p>`, 'application/xml');
|
|
53
|
+
return doc.importNode(drawingFragment.documentElement, true);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build the inline w:drawing XML for an image reference.
|
|
57
|
+
*/
|
|
58
|
+
function buildDrawingXml(rId, widthEmu, heightEmu, altText, fileName) {
|
|
59
|
+
return (`<w:drawing xmlns:w="${NAMESPACES.W}">` +
|
|
60
|
+
`<wp:inline distT="0" distB="0" distL="0" distR="0" ` +
|
|
61
|
+
`xmlns:wp="${NAMESPACES.WP}">` +
|
|
62
|
+
`<wp:extent cx="${widthEmu}" cy="${heightEmu}"/>` +
|
|
63
|
+
`<wp:docPr id="1" name="${fileName}" descr="${escapeXmlAttr(altText)}"/>` +
|
|
64
|
+
`<a:graphic xmlns:a="${NAMESPACES.A}">` +
|
|
65
|
+
`<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">` +
|
|
66
|
+
`<pic:pic xmlns:pic="${NAMESPACES.PIC}">` +
|
|
67
|
+
`<pic:nvPicPr>` +
|
|
68
|
+
`<pic:cNvPr id="0" name="${fileName}" descr="${escapeXmlAttr(altText)}"/>` +
|
|
69
|
+
`<pic:cNvPicPr/>` +
|
|
70
|
+
`</pic:nvPicPr>` +
|
|
71
|
+
`<pic:blipFill>` +
|
|
72
|
+
`<a:blip r:embed="${rId}" xmlns:r="${NAMESPACES.R}"/>` +
|
|
73
|
+
`<a:stretch><a:fillRect/></a:stretch>` +
|
|
74
|
+
`</pic:blipFill>` +
|
|
75
|
+
`<pic:spPr>` +
|
|
76
|
+
`<a:xfrm><a:off x="0" y="0"/><a:ext cx="${widthEmu}" cy="${heightEmu}"/></a:xfrm>` +
|
|
77
|
+
`<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>` +
|
|
78
|
+
`</pic:spPr>` +
|
|
79
|
+
`</pic:pic>` +
|
|
80
|
+
`</a:graphicData>` +
|
|
81
|
+
`</a:graphic>` +
|
|
82
|
+
`</wp:inline>` +
|
|
83
|
+
`</w:drawing>`);
|
|
84
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX element builders — Single Responsibility: build XML elements
|
|
3
|
+
* for paragraphs, tables, and images.
|
|
4
|
+
*
|
|
5
|
+
* These builders are shared between create.ts and ops/ modules to
|
|
6
|
+
* eliminate code duplication and ensure consistency.
|
|
7
|
+
*/
|
|
8
|
+
export { buildParagraph } from './paragraph.js';
|
|
9
|
+
export { buildTable } from './table.js';
|
|
10
|
+
export { buildImageElement } from './image.js';
|
|
11
|
+
export { escapeXml, escapeXmlAttr } from './utils.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX element builders — Single Responsibility: build XML elements
|
|
3
|
+
* for paragraphs, tables, and images.
|
|
4
|
+
*
|
|
5
|
+
* These builders are shared between create.ts and ops/ modules to
|
|
6
|
+
* eliminate code duplication and ensure consistency.
|
|
7
|
+
*/
|
|
8
|
+
export { buildParagraph } from './paragraph.js';
|
|
9
|
+
export { buildTable } from './table.js';
|
|
10
|
+
export { buildImageElement } from './image.js';
|
|
11
|
+
export { escapeXml, escapeXmlAttr } from './utils.js';
|