@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.
Files changed (179) hide show
  1. package/README.md +2 -0
  2. package/dist/handlers/filesystem-handlers.js +58 -11
  3. package/dist/handlers/history-handlers.d.ts +7 -0
  4. package/dist/handlers/history-handlers.js +33 -1
  5. package/dist/server.js +30 -4
  6. package/dist/tools/docx/builders/html-builder.d.ts +17 -0
  7. package/dist/tools/docx/builders/html-builder.js +92 -0
  8. package/dist/tools/docx/builders/image.d.ts +14 -0
  9. package/dist/tools/docx/builders/image.js +84 -0
  10. package/dist/tools/docx/builders/index.d.ts +11 -0
  11. package/dist/tools/docx/builders/index.js +11 -0
  12. package/dist/tools/docx/builders/markdown-builder.d.ts +2 -0
  13. package/dist/tools/docx/builders/markdown-builder.js +260 -0
  14. package/dist/tools/docx/builders/paragraph.d.ts +12 -0
  15. package/dist/tools/docx/builders/paragraph.js +29 -0
  16. package/dist/tools/docx/builders/table.d.ts +8 -0
  17. package/dist/tools/docx/builders/table.js +94 -0
  18. package/dist/tools/docx/builders/utils.d.ts +5 -0
  19. package/dist/tools/docx/builders/utils.js +18 -0
  20. package/dist/tools/docx/constants.d.ts +32 -0
  21. package/dist/tools/docx/constants.js +61 -0
  22. package/dist/tools/docx/converters/markdown-to-html.d.ts +17 -0
  23. package/dist/tools/docx/converters/markdown-to-html.js +111 -0
  24. package/dist/tools/docx/create.d.ts +21 -0
  25. package/dist/tools/docx/create.js +386 -0
  26. package/dist/tools/docx/dom.d.ts +66 -0
  27. package/dist/tools/docx/dom.js +228 -0
  28. package/dist/tools/docx/errors.d.ts +28 -0
  29. package/dist/tools/docx/errors.js +48 -0
  30. package/dist/tools/docx/extractors/images.d.ts +14 -0
  31. package/dist/tools/docx/extractors/images.js +40 -0
  32. package/dist/tools/docx/extractors/metadata.d.ts +14 -0
  33. package/dist/tools/docx/extractors/metadata.js +64 -0
  34. package/dist/tools/docx/extractors/sections.d.ts +14 -0
  35. package/dist/tools/docx/extractors/sections.js +61 -0
  36. package/dist/tools/docx/html.d.ts +17 -0
  37. package/dist/tools/docx/html.js +111 -0
  38. package/dist/tools/docx/index.d.ts +10 -0
  39. package/dist/tools/docx/index.js +10 -0
  40. package/dist/tools/docx/markdown.d.ts +84 -0
  41. package/dist/tools/docx/markdown.js +507 -0
  42. package/dist/tools/docx/modify.d.ts +28 -0
  43. package/dist/tools/docx/modify.js +271 -0
  44. package/dist/tools/docx/operations/handlers/index.d.ts +39 -0
  45. package/dist/tools/docx/operations/handlers/index.js +152 -0
  46. package/dist/tools/docx/operations/html-manipulator.d.ts +24 -0
  47. package/dist/tools/docx/operations/html-manipulator.js +352 -0
  48. package/dist/tools/docx/operations/index.d.ts +14 -0
  49. package/dist/tools/docx/operations/index.js +61 -0
  50. package/dist/tools/docx/operations/operation-handlers.d.ts +3 -0
  51. package/dist/tools/docx/operations/operation-handlers.js +67 -0
  52. package/dist/tools/docx/operations/preprocessor.d.ts +14 -0
  53. package/dist/tools/docx/operations/preprocessor.js +44 -0
  54. package/dist/tools/docx/operations/xml-replacer.d.ts +9 -0
  55. package/dist/tools/docx/operations/xml-replacer.js +35 -0
  56. package/dist/tools/docx/operations.d.ts +13 -0
  57. package/dist/tools/docx/operations.js +13 -0
  58. package/dist/tools/docx/ops/delete-paragraph-at-body-index.d.ts +11 -0
  59. package/dist/tools/docx/ops/delete-paragraph-at-body-index.js +23 -0
  60. package/dist/tools/docx/ops/header-replace-text-exact.d.ts +13 -0
  61. package/dist/tools/docx/ops/header-replace-text-exact.js +55 -0
  62. package/dist/tools/docx/ops/index.d.ts +17 -0
  63. package/dist/tools/docx/ops/index.js +67 -0
  64. package/dist/tools/docx/ops/insert-image-after-text.d.ts +24 -0
  65. package/dist/tools/docx/ops/insert-image-after-text.js +128 -0
  66. package/dist/tools/docx/ops/insert-paragraph-after-text.d.ts +12 -0
  67. package/dist/tools/docx/ops/insert-paragraph-after-text.js +74 -0
  68. package/dist/tools/docx/ops/insert-table-after-text.d.ts +19 -0
  69. package/dist/tools/docx/ops/insert-table-after-text.js +57 -0
  70. package/dist/tools/docx/ops/replace-hyperlink-url.d.ts +12 -0
  71. package/dist/tools/docx/ops/replace-hyperlink-url.js +37 -0
  72. package/dist/tools/docx/ops/replace-paragraph-at-body-index.d.ts +9 -0
  73. package/dist/tools/docx/ops/replace-paragraph-at-body-index.js +25 -0
  74. package/dist/tools/docx/ops/replace-paragraph-text-exact.d.ts +9 -0
  75. package/dist/tools/docx/ops/replace-paragraph-text-exact.js +21 -0
  76. package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +8 -0
  77. package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +23 -0
  78. package/dist/tools/docx/ops/set-color-for-style.d.ts +9 -0
  79. package/dist/tools/docx/ops/set-color-for-style.js +27 -0
  80. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.d.ts +8 -0
  81. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.js +57 -0
  82. package/dist/tools/docx/ops/table-set-cell-text.d.ts +9 -0
  83. package/dist/tools/docx/ops/table-set-cell-text.js +72 -0
  84. package/dist/tools/docx/parsers/image-extractor.d.ts +18 -0
  85. package/dist/tools/docx/parsers/image-extractor.js +61 -0
  86. package/dist/tools/docx/parsers/index.d.ts +9 -0
  87. package/dist/tools/docx/parsers/index.js +9 -0
  88. package/dist/tools/docx/parsers/paragraph-parser.d.ts +2 -0
  89. package/dist/tools/docx/parsers/paragraph-parser.js +88 -0
  90. package/dist/tools/docx/parsers/table-parser.d.ts +9 -0
  91. package/dist/tools/docx/parsers/table-parser.js +72 -0
  92. package/dist/tools/docx/parsers/xml-parser.d.ts +25 -0
  93. package/dist/tools/docx/parsers/xml-parser.js +71 -0
  94. package/dist/tools/docx/parsers/zip-reader.d.ts +23 -0
  95. package/dist/tools/docx/parsers/zip-reader.js +52 -0
  96. package/dist/tools/docx/read.d.ts +27 -0
  97. package/dist/tools/docx/read.js +188 -0
  98. package/dist/tools/docx/relationships.d.ts +22 -0
  99. package/dist/tools/docx/relationships.js +76 -0
  100. package/dist/tools/docx/structure.d.ts +25 -0
  101. package/dist/tools/docx/structure.js +102 -0
  102. package/dist/tools/docx/styled-html-parser.d.ts +23 -0
  103. package/dist/tools/docx/styled-html-parser.js +1262 -0
  104. package/dist/tools/docx/types.d.ts +184 -0
  105. package/dist/tools/docx/types.js +5 -0
  106. package/dist/tools/docx/utils/escaping.d.ts +13 -0
  107. package/dist/tools/docx/utils/escaping.js +26 -0
  108. package/dist/tools/docx/utils/images.d.ts +9 -0
  109. package/dist/tools/docx/utils/images.js +26 -0
  110. package/dist/tools/docx/utils/index.d.ts +12 -0
  111. package/dist/tools/docx/utils/index.js +17 -0
  112. package/dist/tools/docx/utils/markdown.d.ts +13 -0
  113. package/dist/tools/docx/utils/markdown.js +32 -0
  114. package/dist/tools/docx/utils/paths.d.ts +15 -0
  115. package/dist/tools/docx/utils/paths.js +27 -0
  116. package/dist/tools/docx/utils/versioning.d.ts +25 -0
  117. package/dist/tools/docx/utils/versioning.js +55 -0
  118. package/dist/tools/docx/utils.d.ts +101 -0
  119. package/dist/tools/docx/utils.js +299 -0
  120. package/dist/tools/docx/validate.d.ts +33 -0
  121. package/dist/tools/docx/validate.js +49 -0
  122. package/dist/tools/docx/validators.d.ts +13 -0
  123. package/dist/tools/docx/validators.js +40 -0
  124. package/dist/tools/docx/write.d.ts +17 -0
  125. package/dist/tools/docx/write.js +88 -0
  126. package/dist/tools/docx/zip.d.ts +21 -0
  127. package/dist/tools/docx/zip.js +35 -0
  128. package/dist/tools/schemas.d.ts +13 -0
  129. package/dist/tools/schemas.js +5 -0
  130. package/dist/types.d.ts +10 -0
  131. package/dist/ui/contracts.d.ts +14 -0
  132. package/dist/ui/contracts.js +18 -0
  133. package/dist/ui/file-preview/index.html +16 -0
  134. package/dist/ui/file-preview/preview-runtime.js +13977 -0
  135. package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
  136. package/dist/ui/file-preview/shared/preview-file-types.js +57 -0
  137. package/dist/ui/file-preview/src/app.d.ts +4 -0
  138. package/dist/ui/file-preview/src/app.js +800 -0
  139. package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
  140. package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
  141. package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
  142. package/dist/ui/file-preview/src/components/highlighting.js +54 -0
  143. package/dist/ui/file-preview/src/components/html-renderer.d.ts +9 -0
  144. package/dist/ui/file-preview/src/components/html-renderer.js +63 -0
  145. package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
  146. package/dist/ui/file-preview/src/components/markdown-renderer.js +21 -0
  147. package/dist/ui/file-preview/src/components/toolbar.d.ts +6 -0
  148. package/dist/ui/file-preview/src/components/toolbar.js +75 -0
  149. package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
  150. package/dist/ui/file-preview/src/image-preview.js +21 -0
  151. package/dist/ui/file-preview/src/main.d.ts +1 -0
  152. package/dist/ui/file-preview/src/main.js +5 -0
  153. package/dist/ui/file-preview/src/types.d.ts +1 -0
  154. package/dist/ui/file-preview/src/types.js +1 -0
  155. package/dist/ui/file-preview/styles.css +764 -0
  156. package/dist/ui/resources.d.ts +21 -0
  157. package/dist/ui/resources.js +72 -0
  158. package/dist/ui/shared/escape-html.d.ts +4 -0
  159. package/dist/ui/shared/escape-html.js +11 -0
  160. package/dist/ui/shared/host-lifecycle.d.ts +16 -0
  161. package/dist/ui/shared/host-lifecycle.js +35 -0
  162. package/dist/ui/shared/rpc-client.d.ts +14 -0
  163. package/dist/ui/shared/rpc-client.js +72 -0
  164. package/dist/ui/shared/theme-adaptation.d.ts +10 -0
  165. package/dist/ui/shared/theme-adaptation.js +118 -0
  166. package/dist/ui/shared/tool-header.d.ts +9 -0
  167. package/dist/ui/shared/tool-header.js +25 -0
  168. package/dist/ui/shared/tool-shell.d.ts +16 -0
  169. package/dist/ui/shared/tool-shell.js +65 -0
  170. package/dist/ui/shared/widget-state.d.ts +28 -0
  171. package/dist/ui/shared/widget-state.js +60 -0
  172. package/dist/utils/capture.d.ts +1 -0
  173. package/dist/utils/capture.js +10 -4
  174. package/dist/utils/files/docx.d.ts +34 -0
  175. package/dist/utils/files/docx.js +145 -0
  176. package/dist/utils/files/text.js +9 -1
  177. package/dist/version.d.ts +1 -1
  178. package/dist/version.js +1 -1
  179. 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(path) {
10
- return path.startsWith('__ERROR__:');
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, return as an image content type
77
- // Content should already be base64-encoded string from handler
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: `Image file: ${parsed.path} (${fileResult.mimeType})\n`
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';
@@ -0,0 +1,2 @@
1
+ import type { DocxBuildOptions } from '../types.js';
2
+ export declare function createDocxFromMarkdown(markdown: string, options?: DocxBuildOptions): Promise<Buffer>;