@wonderwhy-er/desktop-commander 0.2.23 → 0.2.25
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 +14 -55
- package/dist/config-manager.d.ts +5 -0
- package/dist/config-manager.js +9 -0
- package/dist/custom-stdio.d.ts +1 -0
- package/dist/custom-stdio.js +19 -0
- package/dist/handlers/filesystem-handlers.d.ts +4 -0
- package/dist/handlers/filesystem-handlers.js +120 -14
- package/dist/handlers/node-handlers.d.ts +6 -0
- package/dist/handlers/node-handlers.js +73 -0
- package/dist/index.js +5 -3
- package/dist/search-manager.d.ts +25 -0
- package/dist/search-manager.js +212 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +188 -73
- package/dist/terminal-manager.d.ts +56 -2
- package/dist/terminal-manager.js +169 -13
- package/dist/tools/edit.d.ts +28 -4
- package/dist/tools/edit.js +87 -4
- package/dist/tools/filesystem.d.ts +23 -12
- package/dist/tools/filesystem.js +201 -416
- package/dist/tools/improved-process-tools.d.ts +2 -2
- package/dist/tools/improved-process-tools.js +244 -214
- package/dist/tools/mime-types.d.ts +1 -0
- package/dist/tools/mime-types.js +7 -0
- package/dist/tools/pdf/extract-images.d.ts +34 -0
- package/dist/tools/pdf/extract-images.js +132 -0
- package/dist/tools/pdf/index.d.ts +6 -0
- package/dist/tools/pdf/index.js +3 -0
- package/dist/tools/pdf/lib/pdf2md.d.ts +36 -0
- package/dist/tools/pdf/lib/pdf2md.js +76 -0
- package/dist/tools/pdf/manipulations.d.ts +13 -0
- package/dist/tools/pdf/manipulations.js +96 -0
- package/dist/tools/pdf/markdown.d.ts +7 -0
- package/dist/tools/pdf/markdown.js +37 -0
- package/dist/tools/pdf/utils.d.ts +12 -0
- package/dist/tools/pdf/utils.js +34 -0
- package/dist/tools/schemas.d.ts +167 -12
- package/dist/tools/schemas.js +54 -5
- package/dist/types.d.ts +2 -1
- package/dist/utils/ab-test.d.ts +8 -0
- package/dist/utils/ab-test.js +76 -0
- package/dist/utils/capture.js +5 -0
- package/dist/utils/feature-flags.js +7 -4
- package/dist/utils/files/base.d.ts +167 -0
- package/dist/utils/files/base.js +5 -0
- package/dist/utils/files/binary.d.ts +21 -0
- package/dist/utils/files/binary.js +65 -0
- package/dist/utils/files/excel.d.ts +24 -0
- package/dist/utils/files/excel.js +416 -0
- package/dist/utils/files/factory.d.ts +40 -0
- package/dist/utils/files/factory.js +101 -0
- package/dist/utils/files/image.d.ts +21 -0
- package/dist/utils/files/image.js +78 -0
- package/dist/utils/files/index.d.ts +10 -0
- package/dist/utils/files/index.js +13 -0
- package/dist/utils/files/pdf.d.ts +32 -0
- package/dist/utils/files/pdf.js +142 -0
- package/dist/utils/files/text.d.ts +63 -0
- package/dist/utils/files/text.js +357 -0
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.js +43 -0
- package/dist/utils/ripgrep-resolver.js +3 -2
- package/dist/utils/system-info.d.ts +5 -0
- package/dist/utils/system-info.js +71 -3
- package/dist/utils/usageTracker.js +6 -0
- package/dist/utils/welcome-onboarding.d.ts +9 -0
- package/dist/utils/welcome-onboarding.js +37 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -3
package/dist/terminal-manager.js
CHANGED
|
@@ -156,7 +156,8 @@ export class TerminalManager {
|
|
|
156
156
|
const session = {
|
|
157
157
|
pid: childProcess.pid,
|
|
158
158
|
process: childProcess,
|
|
159
|
-
|
|
159
|
+
outputLines: [], // Line-based buffer
|
|
160
|
+
lastReadIndex: 0, // Track where "new" output starts
|
|
160
161
|
isBlocked: false,
|
|
161
162
|
startTime: new Date()
|
|
162
163
|
};
|
|
@@ -201,7 +202,8 @@ export class TerminalManager {
|
|
|
201
202
|
firstOutputTime = now;
|
|
202
203
|
lastOutputTime = now;
|
|
203
204
|
output += text;
|
|
204
|
-
|
|
205
|
+
// Append to line-based buffer
|
|
206
|
+
this.appendToLineBuffer(session, text);
|
|
205
207
|
// Record output event if collecting timing
|
|
206
208
|
if (collectTiming) {
|
|
207
209
|
outputEvents.push({
|
|
@@ -233,7 +235,8 @@ export class TerminalManager {
|
|
|
233
235
|
firstOutputTime = now;
|
|
234
236
|
lastOutputTime = now;
|
|
235
237
|
output += text;
|
|
236
|
-
|
|
238
|
+
// Append to line-based buffer
|
|
239
|
+
this.appendToLineBuffer(session, text);
|
|
237
240
|
// Record output event if collecting timing
|
|
238
241
|
if (collectTiming) {
|
|
239
242
|
outputEvents.push({
|
|
@@ -275,7 +278,7 @@ export class TerminalManager {
|
|
|
275
278
|
// Store completed session before removing active session
|
|
276
279
|
this.completedSessions.set(childProcess.pid, {
|
|
277
280
|
pid: childProcess.pid,
|
|
278
|
-
|
|
281
|
+
outputLines: [...session.outputLines], // Copy line buffer
|
|
279
282
|
exitCode: code,
|
|
280
283
|
startTime: session.startTime,
|
|
281
284
|
endTime: new Date()
|
|
@@ -296,26 +299,179 @@ export class TerminalManager {
|
|
|
296
299
|
});
|
|
297
300
|
});
|
|
298
301
|
}
|
|
299
|
-
|
|
302
|
+
/**
|
|
303
|
+
* Append text to a session's line buffer
|
|
304
|
+
* Handles partial lines and newline splitting
|
|
305
|
+
*/
|
|
306
|
+
appendToLineBuffer(session, text) {
|
|
307
|
+
if (!text)
|
|
308
|
+
return;
|
|
309
|
+
// Split text into lines, keeping track of whether text ends with newline
|
|
310
|
+
const lines = text.split('\n');
|
|
311
|
+
for (let i = 0; i < lines.length; i++) {
|
|
312
|
+
const line = lines[i];
|
|
313
|
+
const isLastFragment = i === lines.length - 1;
|
|
314
|
+
const endsWithNewline = text.endsWith('\n');
|
|
315
|
+
if (session.outputLines.length === 0) {
|
|
316
|
+
// First line ever
|
|
317
|
+
session.outputLines.push(line);
|
|
318
|
+
}
|
|
319
|
+
else if (i === 0) {
|
|
320
|
+
// First fragment - append to last line (might be partial)
|
|
321
|
+
session.outputLines[session.outputLines.length - 1] += line;
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
// Subsequent lines - add as new lines
|
|
325
|
+
session.outputLines.push(line);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Read process output with pagination (like file reading)
|
|
331
|
+
* @param pid Process ID
|
|
332
|
+
* @param offset Line offset: 0=from lastReadIndex, positive=absolute, negative=tail
|
|
333
|
+
* @param length Max lines to return
|
|
334
|
+
* @param updateReadIndex Whether to update lastReadIndex (default: true for offset=0)
|
|
335
|
+
*/
|
|
336
|
+
readOutputPaginated(pid, offset = 0, length = 1000) {
|
|
300
337
|
// First check active sessions
|
|
301
338
|
const session = this.sessions.get(pid);
|
|
302
339
|
if (session) {
|
|
303
|
-
|
|
304
|
-
session.lastOutput = '';
|
|
305
|
-
return output;
|
|
340
|
+
return this.readFromLineBuffer(session.outputLines, offset, length, session.lastReadIndex, (newIndex) => { session.lastReadIndex = newIndex; }, false, undefined);
|
|
306
341
|
}
|
|
307
342
|
// Then check completed sessions
|
|
308
343
|
const completedSession = this.completedSessions.get(pid);
|
|
309
344
|
if (completedSession) {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
345
|
+
const runtimeMs = completedSession.endTime.getTime() - completedSession.startTime.getTime();
|
|
346
|
+
return this.readFromLineBuffer(completedSession.outputLines, offset, length, 0, // Completed sessions don't track read position
|
|
347
|
+
() => { }, // No-op for completed sessions
|
|
348
|
+
true, completedSession.exitCode, runtimeMs);
|
|
349
|
+
}
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Internal helper to read from a line buffer with offset/length
|
|
354
|
+
*/
|
|
355
|
+
readFromLineBuffer(lines, offset, length, lastReadIndex, updateLastRead, isComplete, exitCode, runtimeMs) {
|
|
356
|
+
const totalLines = lines.length;
|
|
357
|
+
let startIndex;
|
|
358
|
+
let linesToRead;
|
|
359
|
+
if (offset < 0) {
|
|
360
|
+
// Negative offset = start position from end, then read 'length' lines forward
|
|
361
|
+
// e.g., offset=-50, length=10 means: start 50 lines from end, read 10 lines
|
|
362
|
+
const fromEnd = Math.abs(offset);
|
|
363
|
+
startIndex = Math.max(0, totalLines - fromEnd);
|
|
364
|
+
linesToRead = lines.slice(startIndex, startIndex + length);
|
|
365
|
+
// Don't update lastReadIndex for tail reads
|
|
366
|
+
}
|
|
367
|
+
else if (offset === 0) {
|
|
368
|
+
// offset=0 means "from where I last read" (like getNewOutput)
|
|
369
|
+
startIndex = lastReadIndex;
|
|
370
|
+
linesToRead = lines.slice(startIndex, startIndex + length);
|
|
371
|
+
// Update lastReadIndex for "new output" behavior
|
|
372
|
+
updateLastRead(Math.min(startIndex + linesToRead.length, totalLines));
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
// Positive offset = absolute position
|
|
376
|
+
startIndex = offset;
|
|
377
|
+
linesToRead = lines.slice(startIndex, startIndex + length);
|
|
378
|
+
// Don't update lastReadIndex for absolute position reads
|
|
379
|
+
}
|
|
380
|
+
const readCount = linesToRead.length;
|
|
381
|
+
const endIndex = startIndex + readCount;
|
|
382
|
+
const remaining = Math.max(0, totalLines - endIndex);
|
|
383
|
+
return {
|
|
384
|
+
lines: linesToRead,
|
|
385
|
+
totalLines,
|
|
386
|
+
readFrom: startIndex,
|
|
387
|
+
readCount,
|
|
388
|
+
remaining,
|
|
389
|
+
isComplete,
|
|
390
|
+
exitCode,
|
|
391
|
+
runtimeMs
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Get total line count for a process
|
|
396
|
+
*/
|
|
397
|
+
getOutputLineCount(pid) {
|
|
398
|
+
const session = this.sessions.get(pid);
|
|
399
|
+
if (session) {
|
|
400
|
+
return session.outputLines.length;
|
|
401
|
+
}
|
|
402
|
+
const completedSession = this.completedSessions.get(pid);
|
|
403
|
+
if (completedSession) {
|
|
404
|
+
return completedSession.outputLines.length;
|
|
405
|
+
}
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Legacy method for backward compatibility
|
|
410
|
+
* Returns all new output since last read
|
|
411
|
+
* @param maxLines Maximum lines to return (default: 1000 for context protection)
|
|
412
|
+
* @deprecated Use readOutputPaginated instead
|
|
413
|
+
*/
|
|
414
|
+
getNewOutput(pid, maxLines = 1000) {
|
|
415
|
+
const result = this.readOutputPaginated(pid, 0, maxLines);
|
|
416
|
+
if (!result)
|
|
417
|
+
return null;
|
|
418
|
+
const output = result.lines.join('\n').trim();
|
|
419
|
+
// For completed sessions, append completion info with runtime
|
|
420
|
+
if (result.isComplete) {
|
|
421
|
+
const runtimeStr = result.runtimeMs !== undefined
|
|
422
|
+
? `\nRuntime: ${(result.runtimeMs / 1000).toFixed(2)}s`
|
|
423
|
+
: '';
|
|
313
424
|
if (output) {
|
|
314
|
-
return `${output}\n\nProcess completed with exit code ${
|
|
425
|
+
return `${output}\n\nProcess completed with exit code ${result.exitCode}${runtimeStr}`;
|
|
315
426
|
}
|
|
316
427
|
else {
|
|
317
|
-
return `Process completed with exit code ${
|
|
428
|
+
return `Process completed with exit code ${result.exitCode}${runtimeStr}\n(No output produced)`;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// Add truncation warning if there's more output
|
|
432
|
+
if (result.remaining > 0) {
|
|
433
|
+
return `${output}\n\n[Output truncated: ${result.remaining} more lines available. Use read_process_output with offset/length for full output.]`;
|
|
434
|
+
}
|
|
435
|
+
return output || null;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Capture a snapshot of current output state for interaction tracking.
|
|
439
|
+
* Used by interactWithProcess to know what output existed before sending input.
|
|
440
|
+
*/
|
|
441
|
+
captureOutputSnapshot(pid) {
|
|
442
|
+
const session = this.sessions.get(pid);
|
|
443
|
+
if (session) {
|
|
444
|
+
const fullOutput = session.outputLines.join('\n');
|
|
445
|
+
return {
|
|
446
|
+
totalChars: fullOutput.length,
|
|
447
|
+
lineCount: session.outputLines.length
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Get output that appeared since a snapshot was taken.
|
|
454
|
+
* This handles the case where output is appended to the last line (REPL prompts).
|
|
455
|
+
* Also checks completed sessions in case process finished between snapshot and poll.
|
|
456
|
+
*/
|
|
457
|
+
getOutputSinceSnapshot(pid, snapshot) {
|
|
458
|
+
// Check active session first
|
|
459
|
+
const session = this.sessions.get(pid);
|
|
460
|
+
if (session) {
|
|
461
|
+
const fullOutput = session.outputLines.join('\n');
|
|
462
|
+
if (fullOutput.length <= snapshot.totalChars) {
|
|
463
|
+
return ''; // No new output
|
|
464
|
+
}
|
|
465
|
+
return fullOutput.substring(snapshot.totalChars);
|
|
466
|
+
}
|
|
467
|
+
// Fallback to completed sessions - process may have finished between snapshot and poll
|
|
468
|
+
const completedSession = this.completedSessions.get(pid);
|
|
469
|
+
if (completedSession) {
|
|
470
|
+
const fullOutput = completedSession.outputLines.join('\n');
|
|
471
|
+
if (fullOutput.length <= snapshot.totalChars) {
|
|
472
|
+
return ''; // No new output
|
|
318
473
|
}
|
|
474
|
+
return fullOutput.substring(snapshot.totalChars);
|
|
319
475
|
}
|
|
320
476
|
return null;
|
|
321
477
|
}
|
package/dist/tools/edit.d.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text file editing via search/replace with fuzzy matching support.
|
|
3
|
+
*
|
|
4
|
+
* TECHNICAL DEBT / ARCHITECTURAL NOTE:
|
|
5
|
+
* This file contains text editing logic that should ideally live in TextFileHandler.editRange()
|
|
6
|
+
* to be consistent with how Excel editing works (ExcelFileHandler.editRange()).
|
|
7
|
+
*
|
|
8
|
+
* Current inconsistency:
|
|
9
|
+
* - Excel: edit_block → ExcelFileHandler.editRange() ✓ uses file handler
|
|
10
|
+
* - Text: edit_block → performSearchReplace() here → bypasses TextFileHandler
|
|
11
|
+
*
|
|
12
|
+
* Future refactor should:
|
|
13
|
+
* 1. Move performSearchReplace() + fuzzy logic into TextFileHandler.editRange()
|
|
14
|
+
* 2. Make this file a thin dispatch layer that routes to appropriate FileHandler
|
|
15
|
+
* 3. Unify the editRange() signature to handle both text search/replace and structured edits
|
|
16
|
+
*/
|
|
1
17
|
import { ServerResult } from '../types.js';
|
|
2
18
|
interface SearchReplace {
|
|
3
19
|
search: string;
|
|
@@ -5,10 +21,18 @@ interface SearchReplace {
|
|
|
5
21
|
}
|
|
6
22
|
export declare function performSearchReplace(filePath: string, block: SearchReplace, expectedReplacements?: number): Promise<ServerResult>;
|
|
7
23
|
/**
|
|
8
|
-
* Handle edit_block command
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
24
|
+
* Handle edit_block command
|
|
25
|
+
*
|
|
26
|
+
* 1. Text files: String replacement (old_string/new_string)
|
|
27
|
+
* - Uses fuzzy matching for resilience
|
|
28
|
+
* - Handles expected_replacements parameter
|
|
29
|
+
*
|
|
30
|
+
* 2. Structured files (Excel): Range rewrite (range + content)
|
|
31
|
+
* - Bulk updates to cell ranges (e.g., "Sheet1!A1:C10")
|
|
32
|
+
* - Whole sheet replacement (e.g., "Sheet1")
|
|
33
|
+
* - More powerful and simpler than surgical location-based edits
|
|
34
|
+
* - Supports chunking for large datasets (e.g., 1000 rows at a time)
|
|
35
|
+
|
|
12
36
|
*/
|
|
13
37
|
export declare function handleEditBlock(args: unknown): Promise<ServerResult>;
|
|
14
38
|
export {};
|
package/dist/tools/edit.js
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text file editing via search/replace with fuzzy matching support.
|
|
3
|
+
*
|
|
4
|
+
* TECHNICAL DEBT / ARCHITECTURAL NOTE:
|
|
5
|
+
* This file contains text editing logic that should ideally live in TextFileHandler.editRange()
|
|
6
|
+
* to be consistent with how Excel editing works (ExcelFileHandler.editRange()).
|
|
7
|
+
*
|
|
8
|
+
* Current inconsistency:
|
|
9
|
+
* - Excel: edit_block → ExcelFileHandler.editRange() ✓ uses file handler
|
|
10
|
+
* - Text: edit_block → performSearchReplace() here → bypasses TextFileHandler
|
|
11
|
+
*
|
|
12
|
+
* Future refactor should:
|
|
13
|
+
* 1. Move performSearchReplace() + fuzzy logic into TextFileHandler.editRange()
|
|
14
|
+
* 2. Make this file a thin dispatch layer that routes to appropriate FileHandler
|
|
15
|
+
* 3. Unify the editRange() signature to handle both text search/replace and structured edits
|
|
16
|
+
*/
|
|
1
17
|
import { writeFile, readFileInternal, validatePath } from './filesystem.js';
|
|
2
18
|
import { recursiveFuzzyIndexOf, getSimilarityRatio } from './fuzzySearch.js';
|
|
3
19
|
import { capture } from '../utils/capture.js';
|
|
@@ -273,13 +289,80 @@ function highlightDifferences(expected, actual) {
|
|
|
273
289
|
return `${commonPrefix}{-${expectedDiff}-}{+${actualDiff}+}${commonSuffix}`;
|
|
274
290
|
}
|
|
275
291
|
/**
|
|
276
|
-
* Handle edit_block command
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
292
|
+
* Handle edit_block command
|
|
293
|
+
*
|
|
294
|
+
* 1. Text files: String replacement (old_string/new_string)
|
|
295
|
+
* - Uses fuzzy matching for resilience
|
|
296
|
+
* - Handles expected_replacements parameter
|
|
297
|
+
*
|
|
298
|
+
* 2. Structured files (Excel): Range rewrite (range + content)
|
|
299
|
+
* - Bulk updates to cell ranges (e.g., "Sheet1!A1:C10")
|
|
300
|
+
* - Whole sheet replacement (e.g., "Sheet1")
|
|
301
|
+
* - More powerful and simpler than surgical location-based edits
|
|
302
|
+
* - Supports chunking for large datasets (e.g., 1000 rows at a time)
|
|
303
|
+
|
|
280
304
|
*/
|
|
281
305
|
export async function handleEditBlock(args) {
|
|
282
306
|
const parsed = EditBlockArgsSchema.parse(args);
|
|
307
|
+
// Structured files: Range rewrite
|
|
308
|
+
if (parsed.range !== undefined && parsed.content !== undefined) {
|
|
309
|
+
try {
|
|
310
|
+
// Validate path before any filesystem operations
|
|
311
|
+
const validatedPath = await validatePath(parsed.file_path);
|
|
312
|
+
const { getFileHandler } = await import('../utils/files/factory.js');
|
|
313
|
+
const handler = await getFileHandler(validatedPath);
|
|
314
|
+
// Parse content if it's a JSON string (AI often sends arrays as JSON strings)
|
|
315
|
+
let content = parsed.content;
|
|
316
|
+
if (typeof content === 'string') {
|
|
317
|
+
try {
|
|
318
|
+
content = JSON.parse(content);
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// Leave as-is if not valid JSON - let handler decide
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// Check if handler supports range editing
|
|
325
|
+
if ('editRange' in handler && typeof handler.editRange === 'function') {
|
|
326
|
+
await handler.editRange(validatedPath, parsed.range, content, parsed.options);
|
|
327
|
+
return {
|
|
328
|
+
content: [{
|
|
329
|
+
type: "text",
|
|
330
|
+
text: `Successfully updated range ${parsed.range} in ${parsed.file_path}`
|
|
331
|
+
}],
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
return {
|
|
336
|
+
content: [{
|
|
337
|
+
type: "text",
|
|
338
|
+
text: `Error: Range-based editing not supported for ${parsed.file_path}`
|
|
339
|
+
}],
|
|
340
|
+
isError: true
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
346
|
+
return {
|
|
347
|
+
content: [{
|
|
348
|
+
type: "text",
|
|
349
|
+
text: `Error: ${errorMessage}`
|
|
350
|
+
}],
|
|
351
|
+
isError: true
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Text files: String replacement
|
|
356
|
+
// Validate required parameters for text replacement
|
|
357
|
+
if (parsed.old_string === undefined || parsed.new_string === undefined) {
|
|
358
|
+
return {
|
|
359
|
+
content: [{
|
|
360
|
+
type: "text",
|
|
361
|
+
text: `Error: Text replacement requires both old_string and new_string parameters`
|
|
362
|
+
}],
|
|
363
|
+
isError: true
|
|
364
|
+
};
|
|
365
|
+
}
|
|
283
366
|
const searchReplace = {
|
|
284
367
|
search: parsed.old_string,
|
|
285
368
|
replace: parsed.new_string
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ReadOptions, FileResult, PdfPageItem } from '../utils/files/base.js';
|
|
2
|
+
import { PdfOperations, PdfMetadata } from './pdf/index.js';
|
|
1
3
|
/**
|
|
2
4
|
* Validates a path to ensure it can be accessed or created.
|
|
3
5
|
* For existing paths, returns the real path (resolving symlinks).
|
|
@@ -8,11 +10,12 @@
|
|
|
8
10
|
* @throws Error if the path or its parent directories don't exist or if the path is not allowed
|
|
9
11
|
*/
|
|
10
12
|
export declare function validatePath(requestedPath: string): Promise<string>;
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
13
|
+
export type { FileResult } from '../utils/files/base.js';
|
|
14
|
+
type PdfPayload = {
|
|
15
|
+
metadata: PdfMetadata;
|
|
16
|
+
pages: PdfPageItem[];
|
|
17
|
+
};
|
|
18
|
+
type FileResultPayloads = PdfPayload;
|
|
16
19
|
/**
|
|
17
20
|
* Read file content from a URL
|
|
18
21
|
* @param url URL to fetch content from
|
|
@@ -22,20 +25,17 @@ export declare function readFileFromUrl(url: string): Promise<FileResult>;
|
|
|
22
25
|
/**
|
|
23
26
|
* Read file content from the local filesystem
|
|
24
27
|
* @param filePath Path to the file
|
|
25
|
-
* @param
|
|
26
|
-
* @param length Maximum number of lines to read (default: from config or 1000)
|
|
28
|
+
* @param options Read options (offset, length, sheet, range)
|
|
27
29
|
* @returns File content or file result with metadata
|
|
28
30
|
*/
|
|
29
|
-
export declare function readFileFromDisk(filePath: string,
|
|
31
|
+
export declare function readFileFromDisk(filePath: string, options?: ReadOptions): Promise<FileResult>;
|
|
30
32
|
/**
|
|
31
33
|
* Read a file from either the local filesystem or a URL
|
|
32
34
|
* @param filePath Path to the file or URL
|
|
33
|
-
* @param
|
|
34
|
-
* @param offset Starting line number to read from (default: 0)
|
|
35
|
-
* @param length Maximum number of lines to read (default: from config or 1000)
|
|
35
|
+
* @param options Read options (isUrl, offset, length, sheet, range)
|
|
36
36
|
* @returns File content or file result with metadata
|
|
37
37
|
*/
|
|
38
|
-
export declare function readFile(filePath: string,
|
|
38
|
+
export declare function readFile(filePath: string, options?: ReadOptions): Promise<FileResult>;
|
|
39
39
|
/**
|
|
40
40
|
* Read file content without status messages for internal operations
|
|
41
41
|
* This function preserves exact file content including original line endings,
|
|
@@ -53,6 +53,8 @@ export interface MultiFileResult {
|
|
|
53
53
|
mimeType?: string;
|
|
54
54
|
isImage?: boolean;
|
|
55
55
|
error?: string;
|
|
56
|
+
isPdf?: boolean;
|
|
57
|
+
payload?: FileResultPayloads;
|
|
56
58
|
}
|
|
57
59
|
export declare function readMultipleFiles(paths: string[]): Promise<MultiFileResult[]>;
|
|
58
60
|
export declare function createDirectory(dirPath: string): Promise<void>;
|
|
@@ -60,3 +62,12 @@ export declare function listDirectory(dirPath: string, depth?: number): Promise<
|
|
|
60
62
|
export declare function moveFile(sourcePath: string, destinationPath: string): Promise<void>;
|
|
61
63
|
export declare function searchFiles(rootPath: string, pattern: string): Promise<string[]>;
|
|
62
64
|
export declare function getFileInfo(filePath: string): Promise<Record<string, any>>;
|
|
65
|
+
/**
|
|
66
|
+
* Write content to a PDF file.
|
|
67
|
+
* Can create a new PDF from Markdown string, or modify an existing PDF using operations.
|
|
68
|
+
*
|
|
69
|
+
* @param filePath Path to the output PDF file
|
|
70
|
+
* @param content Markdown string (for creation) or array of operations (for modification)
|
|
71
|
+
* @param options Options for PDF generation or modification. For modification, can include `sourcePdf`.
|
|
72
|
+
*/
|
|
73
|
+
export declare function writePdf(filePath: string, content: string | PdfOperations[], outputPath?: string, options?: any): Promise<void>;
|