@everworker/oneringai 0.2.0 → 0.2.2

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/dist/index.js CHANGED
@@ -5,7 +5,9 @@ import * as fs16 from 'fs';
5
5
  import { promises, existsSync } from 'fs';
6
6
  import { EventEmitter } from 'eventemitter3';
7
7
  import * as path2 from 'path';
8
- import { join, resolve, dirname, relative, isAbsolute, normalize, extname } from 'path';
8
+ import { join, resolve, extname, dirname, relative, isAbsolute, normalize, sep } from 'path';
9
+ import TurndownService from 'turndown';
10
+ import { Readability } from '@mozilla/readability';
9
11
  import * as os2 from 'os';
10
12
  import { homedir } from 'os';
11
13
  import OpenAI3 from 'openai';
@@ -14,6 +16,7 @@ import { GoogleGenAI } from '@google/genai';
14
16
  import 'zod/v3';
15
17
  import * as z4mini from 'zod/v4-mini';
16
18
  import * as z from 'zod/v4';
19
+ import spawn$1 from 'cross-spawn';
17
20
  import process2 from 'process';
18
21
  import { PassThrough } from 'stream';
19
22
  import * as fs15 from 'fs/promises';
@@ -22,8 +25,6 @@ import * as simpleIcons from 'simple-icons';
22
25
  import { exec, spawn } from 'child_process';
23
26
  import { promisify } from 'util';
24
27
  import { load } from 'cheerio';
25
- import TurndownService from 'turndown';
26
- import { Readability } from '@mozilla/readability';
27
28
  import * as vm from 'vm';
28
29
 
29
30
  var __create = Object.create;
@@ -307,6 +308,10 @@ var init_pkce = __esm({
307
308
  });
308
309
 
309
310
  // src/connectors/oauth/flows/AuthCodePKCE.ts
311
+ function isPublicClientError(responseBody) {
312
+ const lower = responseBody.toLowerCase();
313
+ return lower.includes("aadsts700025") || lower.includes("invalid_client") && lower.includes("public");
314
+ }
310
315
  var AuthCodePKCEFlow;
311
316
  var init_AuthCodePKCE = __esm({
312
317
  "src/connectors/oauth/flows/AuthCodePKCE.ts"() {
@@ -402,14 +407,32 @@ var init_AuthCodePKCE = __esm({
402
407
  if (this.config.usePKCE !== false && verifierData) {
403
408
  params.append("code_verifier", verifierData.verifier);
404
409
  }
405
- const response = await fetch(this.config.tokenUrl, {
410
+ let response = await fetch(this.config.tokenUrl, {
406
411
  method: "POST",
407
412
  headers: {
408
413
  "Content-Type": "application/x-www-form-urlencoded"
409
414
  },
410
415
  body: params
411
416
  });
412
- if (!response.ok) {
417
+ if (!response.ok && this.config.clientSecret) {
418
+ const errorText = await response.text();
419
+ if (isPublicClientError(errorText)) {
420
+ params.delete("client_secret");
421
+ response = await fetch(this.config.tokenUrl, {
422
+ method: "POST",
423
+ headers: {
424
+ "Content-Type": "application/x-www-form-urlencoded"
425
+ },
426
+ body: params
427
+ });
428
+ if (!response.ok) {
429
+ const retryError = await response.text();
430
+ throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${retryError}`);
431
+ }
432
+ } else {
433
+ throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${errorText}`);
434
+ }
435
+ } else if (!response.ok) {
413
436
  const error = await response.text();
414
437
  throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${error}`);
415
438
  }
@@ -455,14 +478,32 @@ var init_AuthCodePKCE = __esm({
455
478
  if (this.config.clientSecret) {
456
479
  params.append("client_secret", this.config.clientSecret);
457
480
  }
458
- const response = await fetch(this.config.tokenUrl, {
481
+ let response = await fetch(this.config.tokenUrl, {
459
482
  method: "POST",
460
483
  headers: {
461
484
  "Content-Type": "application/x-www-form-urlencoded"
462
485
  },
463
486
  body: params
464
487
  });
465
- if (!response.ok) {
488
+ if (!response.ok && this.config.clientSecret) {
489
+ const errorText = await response.text();
490
+ if (isPublicClientError(errorText)) {
491
+ params.delete("client_secret");
492
+ response = await fetch(this.config.tokenUrl, {
493
+ method: "POST",
494
+ headers: {
495
+ "Content-Type": "application/x-www-form-urlencoded"
496
+ },
497
+ body: params
498
+ });
499
+ if (!response.ok) {
500
+ const retryError = await response.text();
501
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${retryError}`);
502
+ }
503
+ } else {
504
+ throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${errorText}`);
505
+ }
506
+ } else if (!response.ok) {
466
507
  const error = await response.text();
467
508
  throw new Error(`Token refresh failed: ${response.status} ${response.statusText} - ${error}`);
468
509
  }
@@ -2231,6 +2272,66 @@ var init_Connector = __esm({
2231
2272
  }
2232
2273
  });
2233
2274
 
2275
+ // src/core/constants.ts
2276
+ var AGENT_DEFAULTS, TOKEN_ESTIMATION, DOCUMENT_DEFAULTS;
2277
+ var init_constants = __esm({
2278
+ "src/core/constants.ts"() {
2279
+ AGENT_DEFAULTS = {
2280
+ /** Default maximum iterations for agentic loop */
2281
+ MAX_ITERATIONS: 50,
2282
+ /** Default temperature for LLM calls */
2283
+ DEFAULT_TEMPERATURE: 0.7,
2284
+ /** Message injected when max iterations is reached */
2285
+ MAX_ITERATIONS_MESSAGE: `You have reached the maximum iteration limit for this execution. Please:
2286
+ 1. Summarize what you have accomplished so far
2287
+ 2. Explain what remains to be done (if anything)
2288
+ 3. Ask the user if they would like you to continue
2289
+
2290
+ Do NOT use any tools in this response - just provide a clear summary and ask for confirmation to proceed.`
2291
+ };
2292
+ TOKEN_ESTIMATION = {
2293
+ /** Characters per token for code */
2294
+ CODE_CHARS_PER_TOKEN: 3,
2295
+ /** Characters per token for prose */
2296
+ PROSE_CHARS_PER_TOKEN: 4,
2297
+ /** Characters per token for mixed content */
2298
+ MIXED_CHARS_PER_TOKEN: 3.5,
2299
+ /** Default characters per token */
2300
+ DEFAULT_CHARS_PER_TOKEN: 4
2301
+ };
2302
+ DOCUMENT_DEFAULTS = {
2303
+ /** Maximum estimated tokens in output */
2304
+ MAX_OUTPUT_TOKENS: 1e5,
2305
+ /** Maximum output size in bytes (5MB) */
2306
+ MAX_OUTPUT_BYTES: 5 * 1024 * 1024,
2307
+ /** Maximum download size for URL sources (50MB) */
2308
+ MAX_DOWNLOAD_SIZE_BYTES: 50 * 1024 * 1024,
2309
+ /** Download timeout for URL sources */
2310
+ DOWNLOAD_TIMEOUT_MS: 6e4,
2311
+ /** Maximum extracted images from a single document */
2312
+ MAX_EXTRACTED_IMAGES: 50,
2313
+ /** Maximum Excel rows per sheet */
2314
+ MAX_EXCEL_ROWS: 1e3,
2315
+ /** Maximum Excel columns per sheet */
2316
+ MAX_EXCEL_COLUMNS: 50,
2317
+ /** Maximum HTML content length */
2318
+ MAX_HTML_LENGTH: 5e4,
2319
+ /** Characters per token estimate */
2320
+ CHARS_PER_TOKEN: 4,
2321
+ /** Estimated tokens for an image with auto detail */
2322
+ IMAGE_TOKENS_AUTO: 765,
2323
+ /** Estimated tokens for an image with low detail */
2324
+ IMAGE_TOKENS_LOW: 85,
2325
+ /** Image filter defaults */
2326
+ IMAGE_FILTER: {
2327
+ MIN_WIDTH: 50,
2328
+ MIN_HEIGHT: 50,
2329
+ MIN_SIZE_BYTES: 1024
2330
+ }
2331
+ };
2332
+ }
2333
+ });
2334
+
2234
2335
  // node_modules/@modelcontextprotocol/sdk/node_modules/ajv/dist/compile/codegen/code.js
2235
2336
  var require_code = __commonJS({
2236
2337
  "node_modules/@modelcontextprotocol/sdk/node_modules/ajv/dist/compile/codegen/code.js"(exports$1) {
@@ -14544,491 +14645,961 @@ var require_dist = __commonJS({
14544
14645
  }
14545
14646
  });
14546
14647
 
14547
- // node_modules/isexe/windows.js
14548
- var require_windows = __commonJS({
14549
- "node_modules/isexe/windows.js"(exports$1, module) {
14550
- module.exports = isexe;
14551
- isexe.sync = sync;
14552
- var fs17 = __require("fs");
14553
- function checkPathExt(path6, options) {
14554
- var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
14555
- if (!pathext) {
14556
- return true;
14557
- }
14558
- pathext = pathext.split(";");
14559
- if (pathext.indexOf("") !== -1) {
14560
- return true;
14648
+ // src/capabilities/documents/handlers/TextHandler.ts
14649
+ var CODE_FENCE_FORMATS, TextHandler;
14650
+ var init_TextHandler = __esm({
14651
+ "src/capabilities/documents/handlers/TextHandler.ts"() {
14652
+ init_constants();
14653
+ CODE_FENCE_FORMATS = {
14654
+ json: "json",
14655
+ xml: "xml",
14656
+ yaml: "yaml",
14657
+ yml: "yaml"
14658
+ };
14659
+ TextHandler = class {
14660
+ name = "TextHandler";
14661
+ supportedFormats = ["txt", "md", "json", "xml", "yaml", "yml"];
14662
+ async handle(buffer, filename, format, _options) {
14663
+ const text = buffer.toString("utf-8");
14664
+ const fenceLanguage = CODE_FENCE_FORMATS[format];
14665
+ const content = fenceLanguage ? `\`\`\`${fenceLanguage}
14666
+ ${text}
14667
+ \`\`\`` : text;
14668
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
14669
+ return [
14670
+ {
14671
+ type: "text",
14672
+ content,
14673
+ metadata: {
14674
+ sourceFilename: filename,
14675
+ format,
14676
+ index: 0,
14677
+ sizeBytes,
14678
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14679
+ }
14680
+ }
14681
+ ];
14561
14682
  }
14562
- for (var i = 0; i < pathext.length; i++) {
14563
- var p = pathext[i].toLowerCase();
14564
- if (p && path6.substr(-p.length).toLowerCase() === p) {
14565
- return true;
14683
+ };
14684
+ }
14685
+ });
14686
+
14687
+ // src/capabilities/documents/handlers/ImageHandler.ts
14688
+ var MIME_TYPES, ImageHandler;
14689
+ var init_ImageHandler = __esm({
14690
+ "src/capabilities/documents/handlers/ImageHandler.ts"() {
14691
+ init_constants();
14692
+ MIME_TYPES = {
14693
+ png: "image/png",
14694
+ jpg: "image/jpeg",
14695
+ jpeg: "image/jpeg",
14696
+ gif: "image/gif",
14697
+ webp: "image/webp",
14698
+ svg: "image/svg+xml"
14699
+ };
14700
+ ImageHandler = class {
14701
+ name = "ImageHandler";
14702
+ supportedFormats = ["png", "jpg", "jpeg", "gif", "webp", "svg"];
14703
+ async handle(buffer, filename, format, _options) {
14704
+ const pieces = [];
14705
+ const mimeType = MIME_TYPES[format] || "application/octet-stream";
14706
+ pieces.push({
14707
+ type: "image",
14708
+ base64: buffer.toString("base64"),
14709
+ mimeType,
14710
+ metadata: {
14711
+ sourceFilename: filename,
14712
+ format,
14713
+ index: 0,
14714
+ sizeBytes: buffer.length,
14715
+ estimatedTokens: DOCUMENT_DEFAULTS.IMAGE_TOKENS_AUTO,
14716
+ label: filename
14717
+ }
14718
+ });
14719
+ if (format === "svg") {
14720
+ const svgText = buffer.toString("utf-8");
14721
+ const sizeBytes = Buffer.byteLength(svgText, "utf-8");
14722
+ pieces.push({
14723
+ type: "text",
14724
+ content: `\`\`\`svg
14725
+ ${svgText}
14726
+ \`\`\``,
14727
+ metadata: {
14728
+ sourceFilename: filename,
14729
+ format,
14730
+ index: 1,
14731
+ section: "SVG source",
14732
+ sizeBytes,
14733
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14734
+ }
14735
+ });
14566
14736
  }
14737
+ return pieces;
14567
14738
  }
14568
- return false;
14569
- }
14570
- function checkStat(stat6, path6, options) {
14571
- if (!stat6.isSymbolicLink() && !stat6.isFile()) {
14572
- return false;
14573
- }
14574
- return checkPathExt(path6, options);
14575
- }
14576
- function isexe(path6, options, cb) {
14577
- fs17.stat(path6, function(er, stat6) {
14578
- cb(er, er ? false : checkStat(stat6, path6, options));
14579
- });
14580
- }
14581
- function sync(path6, options) {
14582
- return checkStat(fs17.statSync(path6), path6, options);
14583
- }
14739
+ };
14584
14740
  }
14585
14741
  });
14586
-
14587
- // node_modules/isexe/mode.js
14588
- var require_mode = __commonJS({
14589
- "node_modules/isexe/mode.js"(exports$1, module) {
14590
- module.exports = isexe;
14591
- isexe.sync = sync;
14592
- var fs17 = __require("fs");
14593
- function isexe(path6, options, cb) {
14594
- fs17.stat(path6, function(er, stat6) {
14595
- cb(er, er ? false : checkStat(stat6, options));
14596
- });
14597
- }
14598
- function sync(path6, options) {
14599
- return checkStat(fs17.statSync(path6), options);
14742
+ async function getJSDOM() {
14743
+ if (!JSDOM) {
14744
+ const jsdom = await import('jsdom');
14745
+ JSDOM = jsdom.JSDOM;
14746
+ }
14747
+ return JSDOM;
14748
+ }
14749
+ async function htmlToMarkdown(html, url2, maxLength = 5e4) {
14750
+ const JSDOMClass = await getJSDOM();
14751
+ const dom = new JSDOMClass(html, { url: url2 });
14752
+ const document = dom.window.document;
14753
+ let title = document.title || "";
14754
+ let byline;
14755
+ let excerpt;
14756
+ let contentHtml = html;
14757
+ let wasReadabilityUsed = false;
14758
+ try {
14759
+ const clonedDoc = document.cloneNode(true);
14760
+ const reader = new Readability(clonedDoc);
14761
+ const article = reader.parse();
14762
+ if (article && article.content && article.content.length > 100) {
14763
+ contentHtml = article.content;
14764
+ title = article.title || title;
14765
+ byline = article.byline || void 0;
14766
+ excerpt = article.excerpt || void 0;
14767
+ wasReadabilityUsed = true;
14600
14768
  }
14601
- function checkStat(stat6, options) {
14602
- return stat6.isFile() && checkMode(stat6, options);
14769
+ } catch {
14770
+ }
14771
+ const turndown = new TurndownService({
14772
+ headingStyle: "atx",
14773
+ codeBlockStyle: "fenced",
14774
+ bulletListMarker: "-",
14775
+ emDelimiter: "_"
14776
+ });
14777
+ turndown.remove(["script", "style", "nav", "footer", "aside", "iframe", "noscript"]);
14778
+ turndown.addRule("pre", {
14779
+ filter: ["pre"],
14780
+ replacement: (content, node) => {
14781
+ const element = node;
14782
+ const code = element.querySelector?.("code");
14783
+ const lang = code?.className?.match(/language-(\w+)/)?.[1] || "";
14784
+ const text = code?.textContent || content;
14785
+ return `
14786
+ \`\`\`${lang}
14787
+ ${text}
14788
+ \`\`\`
14789
+ `;
14603
14790
  }
14604
- function checkMode(stat6, options) {
14605
- var mod = stat6.mode;
14606
- var uid = stat6.uid;
14607
- var gid = stat6.gid;
14608
- var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
14609
- var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
14610
- var u = parseInt("100", 8);
14611
- var g = parseInt("010", 8);
14612
- var o = parseInt("001", 8);
14613
- var ug = u | g;
14614
- var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0;
14615
- return ret;
14791
+ });
14792
+ let markdown = turndown.turndown(contentHtml);
14793
+ markdown = markdown.replace(/\n{3,}/g, "\n\n").replace(/^\s+|\s+$/g, "").replace(/[ \t]+$/gm, "");
14794
+ let wasTruncated = false;
14795
+ if (markdown.length > maxLength) {
14796
+ const truncateAt = markdown.lastIndexOf("\n\n", maxLength);
14797
+ if (truncateAt > maxLength * 0.5) {
14798
+ markdown = markdown.slice(0, truncateAt) + "\n\n...[content truncated]";
14799
+ } else {
14800
+ markdown = markdown.slice(0, maxLength) + "...[truncated]";
14616
14801
  }
14802
+ wasTruncated = true;
14803
+ }
14804
+ return {
14805
+ markdown,
14806
+ title,
14807
+ byline,
14808
+ excerpt,
14809
+ wasReadabilityUsed,
14810
+ wasTruncated
14811
+ };
14812
+ }
14813
+ var JSDOM;
14814
+ var init_htmlToMarkdown = __esm({
14815
+ "src/tools/web/htmlToMarkdown.ts"() {
14816
+ JSDOM = null;
14817
+ }
14818
+ });
14819
+
14820
+ // src/capabilities/documents/handlers/HTMLHandler.ts
14821
+ var HTMLHandler;
14822
+ var init_HTMLHandler = __esm({
14823
+ "src/capabilities/documents/handlers/HTMLHandler.ts"() {
14824
+ init_constants();
14825
+ init_htmlToMarkdown();
14826
+ HTMLHandler = class {
14827
+ name = "HTMLHandler";
14828
+ supportedFormats = ["html"];
14829
+ async handle(buffer, filename, format, options) {
14830
+ const html = buffer.toString("utf-8");
14831
+ const maxLength = options.formatOptions?.html?.maxLength ?? DOCUMENT_DEFAULTS.MAX_HTML_LENGTH;
14832
+ const result = await htmlToMarkdown(html, `file://${filename}`, maxLength);
14833
+ const content = result.markdown;
14834
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
14835
+ return [
14836
+ {
14837
+ type: "text",
14838
+ content,
14839
+ metadata: {
14840
+ sourceFilename: filename,
14841
+ format,
14842
+ index: 0,
14843
+ sizeBytes,
14844
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN),
14845
+ label: result.title || void 0
14846
+ }
14847
+ }
14848
+ ];
14849
+ }
14850
+ };
14617
14851
  }
14618
14852
  });
14619
14853
 
14620
- // node_modules/isexe/index.js
14621
- var require_isexe = __commonJS({
14622
- "node_modules/isexe/index.js"(exports$1, module) {
14623
- __require("fs");
14624
- var core;
14625
- if (process.platform === "win32" || global.TESTING_WINDOWS) {
14626
- core = require_windows();
14627
- } else {
14628
- core = require_mode();
14629
- }
14630
- module.exports = isexe;
14631
- isexe.sync = sync;
14632
- function isexe(path6, options, cb) {
14633
- if (typeof options === "function") {
14634
- cb = options;
14635
- options = {};
14636
- }
14637
- if (!cb) {
14638
- if (typeof Promise !== "function") {
14639
- throw new TypeError("callback not provided");
14640
- }
14641
- return new Promise(function(resolve4, reject) {
14642
- isexe(path6, options || {}, function(er, is) {
14643
- if (er) {
14644
- reject(er);
14645
- } else {
14646
- resolve4(is);
14647
- }
14648
- });
14854
+ // src/capabilities/documents/handlers/OfficeHandler.ts
14855
+ async function getParseOffice() {
14856
+ if (!parseOffice) {
14857
+ const mod = await import('officeparser');
14858
+ parseOffice = mod.parseOffice;
14859
+ }
14860
+ return parseOffice;
14861
+ }
14862
+ var parseOffice, OfficeHandler;
14863
+ var init_OfficeHandler = __esm({
14864
+ "src/capabilities/documents/handlers/OfficeHandler.ts"() {
14865
+ init_constants();
14866
+ parseOffice = null;
14867
+ OfficeHandler = class {
14868
+ name = "OfficeHandler";
14869
+ supportedFormats = ["docx", "pptx", "odt", "odp", "ods", "rtf"];
14870
+ async handle(buffer, filename, format, options) {
14871
+ const parse = await getParseOffice();
14872
+ const extractImages = options.extractImages !== false;
14873
+ const includeSpeakerNotes = options.formatOptions?.office?.includeSpeakerNotes !== false;
14874
+ const ast = await parse(buffer, {
14875
+ extractAttachments: extractImages,
14876
+ ignoreNotes: !includeSpeakerNotes
14649
14877
  });
14878
+ const pieces = [];
14879
+ let pieceIndex = 0;
14880
+ const content = ast.content || [];
14881
+ const markdown = this.astToMarkdown(content, format);
14882
+ if (format === "pptx" || format === "odp") {
14883
+ const slides = this.splitBySlides(content);
14884
+ for (let i = 0; i < slides.length; i++) {
14885
+ const slideContent = this.astToMarkdown(slides[i] ?? [], format);
14886
+ if (slideContent.trim()) {
14887
+ const sizeBytes = Buffer.byteLength(slideContent, "utf-8");
14888
+ pieces.push({
14889
+ type: "text",
14890
+ content: slideContent,
14891
+ metadata: {
14892
+ sourceFilename: filename,
14893
+ format,
14894
+ index: pieceIndex++,
14895
+ section: `Slide ${i + 1}`,
14896
+ sizeBytes,
14897
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14898
+ }
14899
+ });
14900
+ }
14901
+ }
14902
+ } else {
14903
+ if (markdown.trim()) {
14904
+ const sizeBytes = Buffer.byteLength(markdown, "utf-8");
14905
+ pieces.push({
14906
+ type: "text",
14907
+ content: markdown,
14908
+ metadata: {
14909
+ sourceFilename: filename,
14910
+ format,
14911
+ index: pieceIndex++,
14912
+ sizeBytes,
14913
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
14914
+ }
14915
+ });
14916
+ }
14917
+ }
14918
+ if (extractImages && ast.attachments?.length > 0) {
14919
+ for (const attachment of ast.attachments) {
14920
+ if (attachment.type === "image" && attachment.data) {
14921
+ const imageData = attachment.data;
14922
+ const sizeBytes = Math.ceil(imageData.length * 0.75);
14923
+ pieces.push({
14924
+ type: "image",
14925
+ base64: imageData,
14926
+ mimeType: attachment.mimeType || "image/png",
14927
+ metadata: {
14928
+ sourceFilename: filename,
14929
+ format,
14930
+ index: pieceIndex++,
14931
+ sizeBytes,
14932
+ estimatedTokens: DOCUMENT_DEFAULTS.IMAGE_TOKENS_AUTO,
14933
+ label: attachment.altText || attachment.name || void 0
14934
+ }
14935
+ });
14936
+ }
14937
+ }
14938
+ }
14939
+ return pieces;
14650
14940
  }
14651
- core(path6, options || {}, function(er, is) {
14652
- if (er) {
14653
- if (er.code === "EACCES" || options && options.ignoreErrors) {
14654
- er = null;
14655
- is = false;
14941
+ /**
14942
+ * Split AST content into slide groups
14943
+ */
14944
+ splitBySlides(content) {
14945
+ const slides = [];
14946
+ let currentSlide = [];
14947
+ for (const node of content) {
14948
+ if (node.type === "slide") {
14949
+ if (currentSlide.length > 0) {
14950
+ slides.push(currentSlide);
14951
+ }
14952
+ currentSlide = [node];
14953
+ } else {
14954
+ currentSlide.push(node);
14656
14955
  }
14657
14956
  }
14658
- cb(er, is);
14659
- });
14660
- }
14661
- function sync(path6, options) {
14662
- try {
14663
- return core.sync(path6, options || {});
14664
- } catch (er) {
14665
- if (options && options.ignoreErrors || er.code === "EACCES") {
14666
- return false;
14667
- } else {
14668
- throw er;
14957
+ if (currentSlide.length > 0) {
14958
+ slides.push(currentSlide);
14959
+ }
14960
+ if (slides.length === 0 && content.length > 0) {
14961
+ slides.push(content);
14669
14962
  }
14963
+ return slides;
14670
14964
  }
14671
- }
14672
- }
14673
- });
14674
-
14675
- // node_modules/which/which.js
14676
- var require_which = __commonJS({
14677
- "node_modules/which/which.js"(exports$1, module) {
14678
- var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
14679
- var path6 = __require("path");
14680
- var COLON = isWindows ? ";" : ":";
14681
- var isexe = require_isexe();
14682
- var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
14683
- var getPathInfo = (cmd, opt) => {
14684
- const colon = opt.colon || COLON;
14685
- const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [
14686
- // windows always checks the cwd first
14687
- ...isWindows ? [process.cwd()] : [],
14688
- ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */
14689
- "").split(colon)
14690
- ];
14691
- const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
14692
- const pathExt = isWindows ? pathExtExe.split(colon) : [""];
14693
- if (isWindows) {
14694
- if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
14695
- pathExt.unshift("");
14965
+ /**
14966
+ * Convert AST nodes to markdown
14967
+ */
14968
+ astToMarkdown(nodes, format) {
14969
+ const parts = [];
14970
+ for (const node of nodes) {
14971
+ const md = this.nodeToMarkdown(node, format);
14972
+ if (md) parts.push(md);
14973
+ }
14974
+ return parts.join("\n\n");
14696
14975
  }
14697
- return {
14698
- pathEnv,
14699
- pathExt,
14700
- pathExtExe
14701
- };
14702
- };
14703
- var which = (cmd, opt, cb) => {
14704
- if (typeof opt === "function") {
14705
- cb = opt;
14706
- opt = {};
14707
- }
14708
- if (!opt)
14709
- opt = {};
14710
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14711
- const found = [];
14712
- const step = (i) => new Promise((resolve4, reject) => {
14713
- if (i === pathEnv.length)
14714
- return opt.all && found.length ? resolve4(found) : reject(getNotFoundError(cmd));
14715
- const ppRaw = pathEnv[i];
14716
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14717
- const pCmd = path6.join(pathPart, cmd);
14718
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14719
- resolve4(subStep(p, i, 0));
14720
- });
14721
- const subStep = (p, i, ii) => new Promise((resolve4, reject) => {
14722
- if (ii === pathExt.length)
14723
- return resolve4(step(i + 1));
14724
- const ext = pathExt[ii];
14725
- isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
14726
- if (!er && is) {
14727
- if (opt.all)
14728
- found.push(p + ext);
14729
- else
14730
- return resolve4(p + ext);
14976
+ /**
14977
+ * Convert a single AST node to markdown
14978
+ */
14979
+ nodeToMarkdown(node, format) {
14980
+ if (!node) return "";
14981
+ switch (node.type) {
14982
+ case "heading": {
14983
+ const level = node.metadata?.level || 1;
14984
+ const prefix = "#".repeat(Math.min(level, 6));
14985
+ return `${prefix} ${node.text || ""}`;
14986
+ }
14987
+ case "paragraph":
14988
+ return this.formatText(node);
14989
+ case "text":
14990
+ return this.formatText(node);
14991
+ case "list": {
14992
+ const items = node.children || [];
14993
+ return items.map((item, i) => {
14994
+ const indent = " ".repeat(node.metadata?.indentation || 0);
14995
+ const prefix = node.metadata?.listType === "ordered" ? `${i + 1}.` : "-";
14996
+ return `${indent}${prefix} ${item.text || this.getNodeText(item)}`;
14997
+ }).join("\n");
14998
+ }
14999
+ case "table": {
15000
+ return this.tableToMarkdown(node);
15001
+ }
15002
+ case "slide": {
15003
+ const slideNum = node.metadata?.slideNumber || "";
15004
+ const childContent = node.children ? node.children.map((c) => this.nodeToMarkdown(c, format)).filter(Boolean).join("\n\n") : node.text || "";
15005
+ return slideNum ? `### Slide ${slideNum}
15006
+
15007
+ ${childContent}` : childContent;
15008
+ }
15009
+ case "note":
15010
+ return `> **Note:** ${node.text || this.getNodeText(node)}`;
15011
+ case "sheet": {
15012
+ const sheetName = node.metadata?.sheetName || "Sheet";
15013
+ const childContent = node.children ? node.children.map((c) => this.nodeToMarkdown(c, format)).filter(Boolean).join("\n") : "";
15014
+ return `## Sheet: ${sheetName}
15015
+
15016
+ ${childContent}`;
15017
+ }
15018
+ case "page": {
15019
+ const pageNum = node.metadata?.pageNumber || "";
15020
+ const childContent = node.children ? node.children.map((c) => this.nodeToMarkdown(c, format)).filter(Boolean).join("\n\n") : node.text || "";
15021
+ return pageNum ? `--- Page ${pageNum} ---
15022
+
15023
+ ${childContent}` : childContent;
15024
+ }
15025
+ case "image":
15026
+ return `[Image: ${node.metadata?.altText || node.metadata?.attachmentName || "embedded image"}]`;
15027
+ case "chart":
15028
+ return `[Chart: ${node.metadata?.attachmentName || "embedded chart"}]`;
15029
+ default:
15030
+ return node.text || this.getNodeText(node);
15031
+ }
15032
+ }
15033
+ /**
15034
+ * Get text from a node recursively
15035
+ */
15036
+ getNodeText(node) {
15037
+ if (node.text) return node.text;
15038
+ if (node.children) {
15039
+ return node.children.map((c) => this.getNodeText(c)).join("");
15040
+ }
15041
+ return "";
15042
+ }
15043
+ /**
15044
+ * Format text with markdown formatting
15045
+ */
15046
+ formatText(node) {
15047
+ if (!node.children || node.children.length === 0) {
15048
+ return node.text || "";
15049
+ }
15050
+ return node.children.map((child) => {
15051
+ let text = child.text || this.getNodeText(child);
15052
+ if (!text) return "";
15053
+ const fmt = child.formatting;
15054
+ if (fmt) {
15055
+ if (fmt.bold) text = `**${text}**`;
15056
+ if (fmt.italic) text = `_${text}_`;
15057
+ if (fmt.strikethrough) text = `~~${text}~~`;
14731
15058
  }
14732
- return resolve4(subStep(p, i, ii + 1));
14733
- });
14734
- });
14735
- return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
14736
- };
14737
- var whichSync = (cmd, opt) => {
14738
- opt = opt || {};
14739
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14740
- const found = [];
14741
- for (let i = 0; i < pathEnv.length; i++) {
14742
- const ppRaw = pathEnv[i];
14743
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14744
- const pCmd = path6.join(pathPart, cmd);
14745
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14746
- for (let j = 0; j < pathExt.length; j++) {
14747
- const cur = p + pathExt[j];
14748
- try {
14749
- const is = isexe.sync(cur, { pathExt: pathExtExe });
14750
- if (is) {
14751
- if (opt.all)
14752
- found.push(cur);
14753
- else
14754
- return cur;
14755
- }
14756
- } catch (ex) {
15059
+ if (child.metadata?.link && child.metadata?.linkType === "external") {
15060
+ text = `[${text}](${child.metadata.link})`;
14757
15061
  }
14758
- }
15062
+ return text;
15063
+ }).join("");
14759
15064
  }
14760
- if (opt.all && found.length)
14761
- return found;
14762
- if (opt.nothrow)
14763
- return null;
14764
- throw getNotFoundError(cmd);
14765
- };
14766
- module.exports = which;
14767
- which.sync = whichSync;
14768
- }
14769
- });
15065
+ /**
15066
+ * Convert table node to markdown table
15067
+ */
15068
+ tableToMarkdown(node) {
15069
+ if (!node.children || node.children.length === 0) return "";
15070
+ const rows = [];
15071
+ for (const row of node.children) {
15072
+ if (row.type === "row" && row.children) {
15073
+ rows.push(row.children.map((cell) => {
15074
+ const text = cell.text || this.getNodeText(cell);
15075
+ return text.replace(/\|/g, "\\|").trim();
15076
+ }));
15077
+ }
15078
+ }
15079
+ if (rows.length === 0) return "";
15080
+ const maxCols = Math.max(...rows.map((r) => r.length));
15081
+ const normalizedRows = rows.map((r) => {
15082
+ while (r.length < maxCols) r.push("");
15083
+ return r;
15084
+ });
15085
+ const firstRow = normalizedRows[0] ?? [];
15086
+ const header = `| ${firstRow.join(" | ")} |`;
15087
+ const separator = `| ${firstRow.map(() => "---").join(" | ")} |`;
15088
+ const body = normalizedRows.slice(1).map((r) => `| ${r.join(" | ")} |`).join("\n");
15089
+ return body ? `${header}
15090
+ ${separator}
15091
+ ${body}` : `${header}
15092
+ ${separator}`;
15093
+ }
15094
+ };
15095
+ }
15096
+ });
15097
+
15098
+ // src/capabilities/documents/handlers/ExcelHandler.ts
15099
+ async function getExcelJS() {
15100
+ if (!ExcelJS) {
15101
+ ExcelJS = await import('exceljs');
15102
+ }
15103
+ return ExcelJS;
15104
+ }
15105
+ var ExcelJS, ExcelHandler;
15106
+ var init_ExcelHandler = __esm({
15107
+ "src/capabilities/documents/handlers/ExcelHandler.ts"() {
15108
+ init_constants();
15109
+ ExcelJS = null;
15110
+ ExcelHandler = class {
15111
+ name = "ExcelHandler";
15112
+ supportedFormats = ["xlsx", "csv"];
15113
+ async handle(buffer, filename, format, options) {
15114
+ const exceljs = await getExcelJS();
15115
+ const Workbook = exceljs.Workbook || exceljs.default?.Workbook;
15116
+ const excelOpts = {
15117
+ maxRows: options.formatOptions?.excel?.maxRows ?? DOCUMENT_DEFAULTS.MAX_EXCEL_ROWS,
15118
+ maxColumns: options.formatOptions?.excel?.maxColumns ?? DOCUMENT_DEFAULTS.MAX_EXCEL_COLUMNS,
15119
+ tableFormat: options.formatOptions?.excel?.tableFormat ?? "markdown",
15120
+ includeFormulas: options.formatOptions?.excel?.includeFormulas ?? false
15121
+ };
15122
+ const workbook = new Workbook();
15123
+ if (format === "csv") {
15124
+ await workbook.csv.read(
15125
+ new (await import('stream')).Readable({
15126
+ read() {
15127
+ this.push(buffer);
15128
+ this.push(null);
15129
+ }
15130
+ })
15131
+ );
15132
+ } else {
15133
+ await workbook.xlsx.load(buffer);
15134
+ }
15135
+ const pieces = [];
15136
+ let pieceIndex = 0;
15137
+ const requestedSheets = options.pages;
15138
+ workbook.eachSheet((worksheet, sheetId) => {
15139
+ if (requestedSheets && requestedSheets.length > 0) {
15140
+ const isRequested = requestedSheets.some((p) => {
15141
+ if (typeof p === "number") return sheetId === p;
15142
+ return worksheet.name === p || String(sheetId) === p;
15143
+ });
15144
+ if (!isRequested) return;
15145
+ }
15146
+ const content = this.sheetToContent(worksheet, excelOpts);
15147
+ if (!content.trim()) return;
15148
+ const sheetContent = format === "csv" ? content : `## Sheet: ${worksheet.name}
14770
15149
 
14771
- // node_modules/path-key/index.js
14772
- var require_path_key = __commonJS({
14773
- "node_modules/path-key/index.js"(exports$1, module) {
14774
- var pathKey = (options = {}) => {
14775
- const environment = options.env || process.env;
14776
- const platform2 = options.platform || process.platform;
14777
- if (platform2 !== "win32") {
14778
- return "PATH";
15150
+ ${content}`;
15151
+ const sizeBytes = Buffer.byteLength(sheetContent, "utf-8");
15152
+ pieces.push({
15153
+ type: "text",
15154
+ content: sheetContent,
15155
+ metadata: {
15156
+ sourceFilename: filename,
15157
+ format,
15158
+ index: pieceIndex++,
15159
+ section: format === "csv" ? void 0 : worksheet.name,
15160
+ sizeBytes,
15161
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15162
+ }
15163
+ });
15164
+ });
15165
+ return pieces;
14779
15166
  }
14780
- return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
14781
- };
14782
- module.exports = pathKey;
14783
- module.exports.default = pathKey;
14784
- }
14785
- });
14786
-
14787
- // node_modules/cross-spawn/lib/util/resolveCommand.js
14788
- var require_resolveCommand = __commonJS({
14789
- "node_modules/cross-spawn/lib/util/resolveCommand.js"(exports$1, module) {
14790
- var path6 = __require("path");
14791
- var which = require_which();
14792
- var getPathKey = require_path_key();
14793
- function resolveCommandAttempt(parsed, withoutPathExt) {
14794
- const env = parsed.options.env || process.env;
14795
- const cwd = process.cwd();
14796
- const hasCustomCwd = parsed.options.cwd != null;
14797
- const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled;
14798
- if (shouldSwitchCwd) {
14799
- try {
14800
- process.chdir(parsed.options.cwd);
14801
- } catch (err) {
15167
+ /**
15168
+ * Convert a worksheet to the configured format
15169
+ */
15170
+ sheetToContent(worksheet, opts) {
15171
+ switch (opts.tableFormat) {
15172
+ case "csv":
15173
+ return this.sheetToCSV(worksheet, opts);
15174
+ case "json":
15175
+ return this.sheetToJSON(worksheet, opts);
15176
+ default:
15177
+ return this.sheetToMarkdownTable(worksheet, opts);
14802
15178
  }
14803
15179
  }
14804
- let resolved;
14805
- try {
14806
- resolved = which.sync(parsed.command, {
14807
- path: env[getPathKey({ env })],
14808
- pathExt: withoutPathExt ? path6.delimiter : void 0
15180
+ /**
15181
+ * Convert worksheet to markdown table
15182
+ */
15183
+ sheetToMarkdownTable(worksheet, opts) {
15184
+ const rows = this.extractRows(worksheet, opts);
15185
+ if (rows.length === 0) return "";
15186
+ const maxCols = Math.min(
15187
+ Math.max(...rows.map((r) => r.length)),
15188
+ opts.maxColumns
15189
+ );
15190
+ const normalizedRows = rows.map((r) => {
15191
+ const truncated = r.slice(0, maxCols);
15192
+ while (truncated.length < maxCols) truncated.push("");
15193
+ return truncated;
14809
15194
  });
14810
- } catch (e) {
14811
- } finally {
14812
- if (shouldSwitchCwd) {
14813
- process.chdir(cwd);
15195
+ const firstRow = normalizedRows[0] ?? [];
15196
+ const header = `| ${firstRow.join(" | ")} |`;
15197
+ const separator = `| ${firstRow.map(() => "---").join(" | ")} |`;
15198
+ const body = normalizedRows.slice(1).map((r) => `| ${r.join(" | ")} |`).join("\n");
15199
+ let result = `${header}
15200
+ ${separator}`;
15201
+ if (body) result += `
15202
+ ${body}`;
15203
+ if (worksheet.rowCount > opts.maxRows) {
15204
+ result += `
15205
+
15206
+ _...truncated (${worksheet.rowCount - opts.maxRows} more rows)_`;
14814
15207
  }
15208
+ return result;
14815
15209
  }
14816
- if (resolved) {
14817
- resolved = path6.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
15210
+ /**
15211
+ * Convert worksheet to CSV
15212
+ */
15213
+ sheetToCSV(worksheet, opts) {
15214
+ const rows = this.extractRows(worksheet, opts);
15215
+ return rows.map(
15216
+ (row) => row.slice(0, opts.maxColumns).map((cell) => {
15217
+ if (cell.includes(",") || cell.includes('"') || cell.includes("\n")) {
15218
+ return `"${cell.replace(/"/g, '""')}"`;
15219
+ }
15220
+ return cell;
15221
+ }).join(",")
15222
+ ).join("\n");
14818
15223
  }
14819
- return resolved;
14820
- }
14821
- function resolveCommand(parsed) {
14822
- return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
14823
- }
14824
- module.exports = resolveCommand;
14825
- }
14826
- });
14827
-
14828
- // node_modules/cross-spawn/lib/util/escape.js
14829
- var require_escape = __commonJS({
14830
- "node_modules/cross-spawn/lib/util/escape.js"(exports$1, module) {
14831
- var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
14832
- function escapeCommand(arg) {
14833
- arg = arg.replace(metaCharsRegExp, "^$1");
14834
- return arg;
14835
- }
14836
- function escapeArgument(arg, doubleEscapeMetaChars) {
14837
- arg = `${arg}`;
14838
- arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
14839
- arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
14840
- arg = `"${arg}"`;
14841
- arg = arg.replace(metaCharsRegExp, "^$1");
14842
- if (doubleEscapeMetaChars) {
14843
- arg = arg.replace(metaCharsRegExp, "^$1");
15224
+ /**
15225
+ * Convert worksheet to JSON
15226
+ */
15227
+ sheetToJSON(worksheet, opts) {
15228
+ const rows = this.extractRows(worksheet, opts);
15229
+ if (rows.length < 2) return "[]";
15230
+ const headers = (rows[0] ?? []).slice(0, opts.maxColumns);
15231
+ const data = rows.slice(1).map((row) => {
15232
+ const obj = {};
15233
+ headers.forEach((header, i) => {
15234
+ if (header && i < row.length) {
15235
+ obj[header] = row[i] ?? "";
15236
+ }
15237
+ });
15238
+ return obj;
15239
+ });
15240
+ return "```json\n" + JSON.stringify(data, null, 2) + "\n```";
14844
15241
  }
14845
- return arg;
14846
- }
14847
- module.exports.command = escapeCommand;
14848
- module.exports.argument = escapeArgument;
14849
- }
14850
- });
14851
-
14852
- // node_modules/shebang-regex/index.js
14853
- var require_shebang_regex = __commonJS({
14854
- "node_modules/shebang-regex/index.js"(exports$1, module) {
14855
- module.exports = /^#!(.*)/;
14856
- }
14857
- });
14858
-
14859
- // node_modules/shebang-command/index.js
14860
- var require_shebang_command = __commonJS({
14861
- "node_modules/shebang-command/index.js"(exports$1, module) {
14862
- var shebangRegex = require_shebang_regex();
14863
- module.exports = (string3 = "") => {
14864
- const match = string3.match(shebangRegex);
14865
- if (!match) {
14866
- return null;
15242
+ /**
15243
+ * Extract rows from worksheet as string arrays
15244
+ */
15245
+ extractRows(worksheet, opts) {
15246
+ const rows = [];
15247
+ let rowCount = 0;
15248
+ worksheet.eachRow({ includeEmpty: false }, (row) => {
15249
+ if (rowCount >= opts.maxRows) return;
15250
+ rowCount++;
15251
+ const cells = [];
15252
+ row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
15253
+ if (colNumber > opts.maxColumns) return;
15254
+ let value = "";
15255
+ if (opts.includeFormulas && cell.formula) {
15256
+ value = `${this.getCellValue(cell)} (=${cell.formula})`;
15257
+ } else {
15258
+ value = this.getCellValue(cell);
15259
+ }
15260
+ while (cells.length < colNumber - 1) cells.push("");
15261
+ cells.push(value);
15262
+ });
15263
+ rows.push(cells);
15264
+ });
15265
+ return rows;
14867
15266
  }
14868
- const [path6, argument] = match[0].replace(/#! ?/, "").split(" ");
14869
- const binary = path6.split("/").pop();
14870
- if (binary === "env") {
14871
- return argument;
15267
+ /**
15268
+ * Get cell value as string
15269
+ */
15270
+ getCellValue(cell) {
15271
+ if (cell.value === null || cell.value === void 0) return "";
15272
+ if (typeof cell.value === "object") {
15273
+ if (cell.value.richText) {
15274
+ return cell.value.richText.map((rt) => rt.text || "").join("");
15275
+ }
15276
+ if (cell.value.hyperlink) {
15277
+ return cell.value.text || cell.value.hyperlink;
15278
+ }
15279
+ if ("result" in cell.value) {
15280
+ return String(cell.value.result ?? "");
15281
+ }
15282
+ if (cell.value instanceof Date) {
15283
+ return cell.value.toISOString().split("T")[0];
15284
+ }
15285
+ return String(cell.value);
15286
+ }
15287
+ return String(cell.value).replace(/\|/g, "\\|");
14872
15288
  }
14873
- return argument ? `${binary} ${argument}` : binary;
14874
15289
  };
14875
15290
  }
14876
15291
  });
14877
15292
 
14878
- // node_modules/cross-spawn/lib/util/readShebang.js
14879
- var require_readShebang = __commonJS({
14880
- "node_modules/cross-spawn/lib/util/readShebang.js"(exports$1, module) {
14881
- var fs17 = __require("fs");
14882
- var shebangCommand = require_shebang_command();
14883
- function readShebang(command) {
14884
- const size = 150;
14885
- const buffer = Buffer.alloc(size);
14886
- let fd;
14887
- try {
14888
- fd = fs17.openSync(command, "r");
14889
- fs17.readSync(fd, buffer, 0, size, 0);
14890
- fs17.closeSync(fd);
14891
- } catch (e) {
14892
- }
14893
- return shebangCommand(buffer.toString());
14894
- }
14895
- module.exports = readShebang;
14896
- }
14897
- });
14898
-
14899
- // node_modules/cross-spawn/lib/parse.js
14900
- var require_parse = __commonJS({
14901
- "node_modules/cross-spawn/lib/parse.js"(exports$1, module) {
14902
- var path6 = __require("path");
14903
- var resolveCommand = require_resolveCommand();
14904
- var escape2 = require_escape();
14905
- var readShebang = require_readShebang();
14906
- var isWin = process.platform === "win32";
14907
- var isExecutableRegExp = /\.(?:com|exe)$/i;
14908
- var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
14909
- function detectShebang(parsed) {
14910
- parsed.file = resolveCommand(parsed);
14911
- const shebang = parsed.file && readShebang(parsed.file);
14912
- if (shebang) {
14913
- parsed.args.unshift(parsed.file);
14914
- parsed.command = shebang;
14915
- return resolveCommand(parsed);
14916
- }
14917
- return parsed.file;
14918
- }
14919
- function parseNonShell(parsed) {
14920
- if (!isWin) {
14921
- return parsed;
14922
- }
14923
- const commandFile = detectShebang(parsed);
14924
- const needsShell = !isExecutableRegExp.test(commandFile);
14925
- if (parsed.options.forceShell || needsShell) {
14926
- const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
14927
- parsed.command = path6.normalize(parsed.command);
14928
- parsed.command = escape2.command(parsed.command);
14929
- parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
14930
- const shellCommand = [parsed.command].concat(parsed.args).join(" ");
14931
- parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
14932
- parsed.command = process.env.comspec || "cmd.exe";
14933
- parsed.options.windowsVerbatimArguments = true;
15293
+ // src/capabilities/documents/handlers/PDFHandler.ts
15294
+ async function getUnpdf() {
15295
+ if (!unpdfModule) {
15296
+ const mod = await import('unpdf');
15297
+ unpdfModule = {
15298
+ extractText: mod.extractText,
15299
+ extractImages: mod.extractImages,
15300
+ getMeta: mod.getMeta
15301
+ };
15302
+ }
15303
+ return unpdfModule;
15304
+ }
15305
+ var unpdfModule, PDFHandler;
15306
+ var init_PDFHandler = __esm({
15307
+ "src/capabilities/documents/handlers/PDFHandler.ts"() {
15308
+ init_constants();
15309
+ unpdfModule = null;
15310
+ PDFHandler = class {
15311
+ name = "PDFHandler";
15312
+ supportedFormats = ["pdf"];
15313
+ async handle(buffer, filename, format, options) {
15314
+ const unpdf = await getUnpdf();
15315
+ const pieces = [];
15316
+ let pieceIndex = 0;
15317
+ let metadata = {};
15318
+ const includeMetadata = options.formatOptions?.pdf?.includeMetadata !== false;
15319
+ if (includeMetadata) {
15320
+ try {
15321
+ metadata = await unpdf.getMeta(buffer);
15322
+ } catch {
15323
+ }
15324
+ }
15325
+ const textResult = await unpdf.extractText(buffer, { mergePages: false });
15326
+ const pages = textResult?.pages || textResult?.text ? Array.isArray(textResult.text) ? textResult.text : [textResult.text] : [];
15327
+ const requestedPages = options.pages;
15328
+ const pageEntries = pages.map((text, i) => ({ text, pageNum: i + 1 }));
15329
+ const filteredPages = requestedPages && requestedPages.length > 0 ? pageEntries.filter(
15330
+ (p) => requestedPages.some((rp) => {
15331
+ const num = typeof rp === "string" ? parseInt(rp, 10) : rp;
15332
+ return num === p.pageNum;
15333
+ })
15334
+ ) : pageEntries;
15335
+ if (includeMetadata && metadata?.info) {
15336
+ const metaParts = [];
15337
+ if (metadata.info.Title) metaParts.push(`**Title:** ${metadata.info.Title}`);
15338
+ if (metadata.info.Author) metaParts.push(`**Author:** ${metadata.info.Author}`);
15339
+ if (metadata.info.Subject) metaParts.push(`**Subject:** ${metadata.info.Subject}`);
15340
+ if (metadata.info.Creator) metaParts.push(`**Creator:** ${metadata.info.Creator}`);
15341
+ if (pages.length) metaParts.push(`**Pages:** ${pages.length}`);
15342
+ if (metaParts.length > 0) {
15343
+ const metaContent = metaParts.join("\n");
15344
+ const sizeBytes = Buffer.byteLength(metaContent, "utf-8");
15345
+ pieces.push({
15346
+ type: "text",
15347
+ content: metaContent,
15348
+ metadata: {
15349
+ sourceFilename: filename,
15350
+ format,
15351
+ index: pieceIndex++,
15352
+ section: "Metadata",
15353
+ sizeBytes,
15354
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15355
+ }
15356
+ });
15357
+ }
15358
+ }
15359
+ for (const page of filteredPages) {
15360
+ const text = page.text.trim();
15361
+ if (!text) continue;
15362
+ const sizeBytes = Buffer.byteLength(text, "utf-8");
15363
+ pieces.push({
15364
+ type: "text",
15365
+ content: text,
15366
+ metadata: {
15367
+ sourceFilename: filename,
15368
+ format,
15369
+ index: pieceIndex++,
15370
+ section: `Page ${page.pageNum}`,
15371
+ sizeBytes,
15372
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15373
+ }
15374
+ });
15375
+ }
15376
+ if (options.extractImages !== false) {
15377
+ try {
15378
+ const imagesResult = await unpdf.extractImages(buffer, {});
15379
+ const images = imagesResult?.images || [];
15380
+ for (const img of images) {
15381
+ if (!img.data) continue;
15382
+ const base64 = typeof img.data === "string" ? img.data : Buffer.from(img.data).toString("base64");
15383
+ const sizeBytes = Math.ceil(base64.length * 0.75);
15384
+ pieces.push({
15385
+ type: "image",
15386
+ base64,
15387
+ mimeType: img.mimeType || "image/png",
15388
+ width: img.width,
15389
+ height: img.height,
15390
+ metadata: {
15391
+ sourceFilename: filename,
15392
+ format,
15393
+ index: pieceIndex++,
15394
+ sizeBytes,
15395
+ estimatedTokens: DOCUMENT_DEFAULTS.IMAGE_TOKENS_AUTO,
15396
+ label: img.name || void 0
15397
+ }
15398
+ });
15399
+ }
15400
+ } catch {
15401
+ }
15402
+ }
15403
+ return pieces;
15404
+ }
15405
+ };
15406
+ }
15407
+ });
15408
+
15409
+ // src/capabilities/documents/handlers/index.ts
15410
+ var handlers_exports = {};
15411
+ __export(handlers_exports, {
15412
+ ExcelHandler: () => ExcelHandler,
15413
+ HTMLHandler: () => HTMLHandler,
15414
+ ImageHandler: () => ImageHandler,
15415
+ OfficeHandler: () => OfficeHandler,
15416
+ PDFHandler: () => PDFHandler,
15417
+ TextHandler: () => TextHandler,
15418
+ getDefaultHandlers: () => getDefaultHandlers
15419
+ });
15420
+ function getDefaultHandlers() {
15421
+ return /* @__PURE__ */ new Map([
15422
+ ["text", new TextHandler()],
15423
+ ["image", new ImageHandler()],
15424
+ ["html", new HTMLHandler()],
15425
+ ["office", new OfficeHandler()],
15426
+ ["spreadsheet", new ExcelHandler()],
15427
+ ["pdf", new PDFHandler()]
15428
+ ]);
15429
+ }
15430
+ var init_handlers = __esm({
15431
+ "src/capabilities/documents/handlers/index.ts"() {
15432
+ init_TextHandler();
15433
+ init_ImageHandler();
15434
+ init_HTMLHandler();
15435
+ init_OfficeHandler();
15436
+ init_ExcelHandler();
15437
+ init_PDFHandler();
15438
+ init_TextHandler();
15439
+ init_ImageHandler();
15440
+ init_HTMLHandler();
15441
+ init_OfficeHandler();
15442
+ init_ExcelHandler();
15443
+ init_PDFHandler();
15444
+ }
15445
+ });
15446
+
15447
+ // src/capabilities/documents/transformers/DefaultTransformers.ts
15448
+ function normalizeTable(table) {
15449
+ const lines = table.trim().split("\n");
15450
+ if (lines.length < 2) return table;
15451
+ const rows = lines.map(
15452
+ (line) => line.split("|").slice(1, -1).map((cell) => cell.trim())
15453
+ );
15454
+ const colCount = Math.max(...rows.map((r) => r.length));
15455
+ const colWidths = new Array(colCount).fill(3);
15456
+ for (const row of rows) {
15457
+ for (let i = 0; i < row.length; i++) {
15458
+ const cell = row[i] ?? "";
15459
+ if (cell.match(/^[-:]+$/)) continue;
15460
+ colWidths[i] = Math.max(colWidths[i] ?? 3, cell.length);
15461
+ }
15462
+ }
15463
+ const result = rows.map((row, rowIndex) => {
15464
+ const cells = [];
15465
+ for (let i = 0; i < colCount; i++) {
15466
+ const cell = row[i] || "";
15467
+ if (rowIndex === 1) {
15468
+ cells.push("-".repeat(colWidths[i]));
15469
+ } else {
15470
+ cells.push(cell.padEnd(colWidths[i]));
14934
15471
  }
14935
- return parsed;
14936
15472
  }
14937
- function parse(command, args, options) {
14938
- if (args && !Array.isArray(args)) {
14939
- options = args;
14940
- args = null;
15473
+ return `| ${cells.join(" | ")} |`;
15474
+ });
15475
+ return result.join("\n");
15476
+ }
15477
+ function getDefaultTransformers() {
15478
+ return [
15479
+ documentHeaderTransformer,
15480
+ tableFormattingTransformer,
15481
+ truncationTransformer
15482
+ ];
15483
+ }
15484
+ var documentHeaderTransformer, tableFormattingTransformer, truncationTransformer;
15485
+ var init_DefaultTransformers = __esm({
15486
+ "src/capabilities/documents/transformers/DefaultTransformers.ts"() {
15487
+ init_constants();
15488
+ documentHeaderTransformer = {
15489
+ name: "documentHeaderTransformer",
15490
+ appliesTo: [],
15491
+ // applies to all formats
15492
+ priority: 10,
15493
+ async transform(pieces, context) {
15494
+ if (pieces.length === 0) return pieces;
15495
+ const totalSize = pieces.reduce((sum, p) => sum + p.metadata.sizeBytes, 0);
15496
+ const sizeStr = totalSize > 1024 * 1024 ? `${(totalSize / 1024 / 1024).toFixed(1)}MB` : `${(totalSize / 1024).toFixed(1)}KB`;
15497
+ const header = `# Document: ${context.filename}
15498
+ _Format: ${context.format.toUpperCase()} | Size: ${sizeStr}_`;
15499
+ const headerBytes = Buffer.byteLength(header, "utf-8");
15500
+ const headerPiece = {
15501
+ type: "text",
15502
+ content: header,
15503
+ metadata: {
15504
+ sourceFilename: context.filename,
15505
+ format: context.format,
15506
+ index: -1,
15507
+ // will be re-indexed
15508
+ section: "Header",
15509
+ sizeBytes: headerBytes,
15510
+ estimatedTokens: Math.ceil(headerBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15511
+ }
15512
+ };
15513
+ const result = [headerPiece, ...pieces];
15514
+ result.forEach((p, i) => {
15515
+ p.metadata.index = i;
15516
+ });
15517
+ return result;
14941
15518
  }
14942
- args = args ? args.slice(0) : [];
14943
- options = Object.assign({}, options);
14944
- const parsed = {
14945
- command,
14946
- args,
14947
- options,
14948
- file: void 0,
14949
- original: {
14950
- command,
14951
- args
14952
- }
14953
- };
14954
- return options.shell ? parsed : parseNonShell(parsed);
14955
- }
14956
- module.exports = parse;
14957
- }
14958
- });
14959
-
14960
- // node_modules/cross-spawn/lib/enoent.js
14961
- var require_enoent = __commonJS({
14962
- "node_modules/cross-spawn/lib/enoent.js"(exports$1, module) {
14963
- var isWin = process.platform === "win32";
14964
- function notFoundError(original, syscall) {
14965
- return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
14966
- code: "ENOENT",
14967
- errno: "ENOENT",
14968
- syscall: `${syscall} ${original.command}`,
14969
- path: original.command,
14970
- spawnargs: original.args
14971
- });
14972
- }
14973
- function hookChildProcess(cp, parsed) {
14974
- if (!isWin) {
14975
- return;
15519
+ };
15520
+ tableFormattingTransformer = {
15521
+ name: "tableFormattingTransformer",
15522
+ appliesTo: ["xlsx", "csv"],
15523
+ priority: 50,
15524
+ async transform(pieces, _context) {
15525
+ return pieces.map((piece) => {
15526
+ if (piece.type !== "text") return piece;
15527
+ let content = piece.content;
15528
+ content = content.replace(
15529
+ /(\|[^\n]+\|\n\|[\s\-:|]+\|\n(?:\|[^\n]+\|\n?)*)/g,
15530
+ (table) => normalizeTable(table)
15531
+ );
15532
+ if (content === piece.content) return piece;
15533
+ const sizeBytes = Buffer.byteLength(content, "utf-8");
15534
+ return {
15535
+ ...piece,
15536
+ content,
15537
+ metadata: {
15538
+ ...piece.metadata,
15539
+ sizeBytes,
15540
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15541
+ }
15542
+ };
15543
+ });
14976
15544
  }
14977
- const originalEmit = cp.emit;
14978
- cp.emit = function(name, arg1) {
14979
- if (name === "exit") {
14980
- const err = verifyENOENT(arg1, parsed);
14981
- if (err) {
14982
- return originalEmit.call(cp, "error", err);
15545
+ };
15546
+ truncationTransformer = {
15547
+ name: "truncationTransformer",
15548
+ appliesTo: [],
15549
+ // applies to all formats
15550
+ priority: 1e3,
15551
+ // runs last
15552
+ async transform(pieces, context) {
15553
+ const maxTokens = context.options.maxTokens ?? DOCUMENT_DEFAULTS.MAX_OUTPUT_TOKENS;
15554
+ const maxBytes = context.options.maxOutputBytes ?? DOCUMENT_DEFAULTS.MAX_OUTPUT_BYTES;
15555
+ let totalTokens = 0;
15556
+ let totalBytes = 0;
15557
+ const result = [];
15558
+ for (const piece of pieces) {
15559
+ totalTokens += piece.metadata.estimatedTokens;
15560
+ totalBytes += piece.metadata.sizeBytes;
15561
+ if (totalTokens > maxTokens || totalBytes > maxBytes) {
15562
+ if (piece.type === "text") {
15563
+ const remainingTokens = maxTokens - (totalTokens - piece.metadata.estimatedTokens);
15564
+ const remainingChars = remainingTokens * DOCUMENT_DEFAULTS.CHARS_PER_TOKEN;
15565
+ if (remainingChars > 100) {
15566
+ const content = piece.content;
15567
+ const truncateAt = content.lastIndexOf("\n\n", remainingChars);
15568
+ const cutPoint = truncateAt > remainingChars * 0.3 ? truncateAt : remainingChars;
15569
+ const truncated = content.slice(0, cutPoint) + "\n\n..._[content truncated]_";
15570
+ const sizeBytes = Buffer.byteLength(truncated, "utf-8");
15571
+ result.push({
15572
+ ...piece,
15573
+ content: truncated,
15574
+ metadata: {
15575
+ ...piece.metadata,
15576
+ sizeBytes,
15577
+ estimatedTokens: Math.ceil(sizeBytes / DOCUMENT_DEFAULTS.CHARS_PER_TOKEN)
15578
+ }
15579
+ });
15580
+ }
15581
+ }
15582
+ break;
14983
15583
  }
15584
+ result.push(piece);
14984
15585
  }
14985
- return originalEmit.apply(cp, arguments);
14986
- };
14987
- }
14988
- function verifyENOENT(status, parsed) {
14989
- if (isWin && status === 1 && !parsed.file) {
14990
- return notFoundError(parsed.original, "spawn");
14991
- }
14992
- return null;
14993
- }
14994
- function verifyENOENTSync(status, parsed) {
14995
- if (isWin && status === 1 && !parsed.file) {
14996
- return notFoundError(parsed.original, "spawnSync");
15586
+ return result;
14997
15587
  }
14998
- return null;
14999
- }
15000
- module.exports = {
15001
- hookChildProcess,
15002
- verifyENOENT,
15003
- verifyENOENTSync,
15004
- notFoundError
15005
- };
15006
- }
15007
- });
15008
-
15009
- // node_modules/cross-spawn/index.js
15010
- var require_cross_spawn = __commonJS({
15011
- "node_modules/cross-spawn/index.js"(exports$1, module) {
15012
- var cp = __require("child_process");
15013
- var parse = require_parse();
15014
- var enoent = require_enoent();
15015
- function spawn3(command, args, options) {
15016
- const parsed = parse(command, args, options);
15017
- const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
15018
- enoent.hookChildProcess(spawned, parsed);
15019
- return spawned;
15020
- }
15021
- function spawnSync(command, args, options) {
15022
- const parsed = parse(command, args, options);
15023
- const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
15024
- result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
15025
- return result;
15026
- }
15027
- module.exports = spawn3;
15028
- module.exports.spawn = spawn3;
15029
- module.exports.sync = spawnSync;
15030
- module.exports._parse = parse;
15031
- module.exports._enoent = enoent;
15588
+ };
15589
+ }
15590
+ });
15591
+
15592
+ // src/capabilities/documents/transformers/index.ts
15593
+ var transformers_exports = {};
15594
+ __export(transformers_exports, {
15595
+ documentHeaderTransformer: () => documentHeaderTransformer,
15596
+ getDefaultTransformers: () => getDefaultTransformers,
15597
+ tableFormattingTransformer: () => tableFormattingTransformer,
15598
+ truncationTransformer: () => truncationTransformer
15599
+ });
15600
+ var init_transformers = __esm({
15601
+ "src/capabilities/documents/transformers/index.ts"() {
15602
+ init_DefaultTransformers();
15032
15603
  }
15033
15604
  });
15034
15605
 
@@ -15743,6 +16314,32 @@ var ParallelTasksError = class _ParallelTasksError extends AIError {
15743
16314
  return this.failures.map((f) => f.taskId);
15744
16315
  }
15745
16316
  };
16317
+ var DocumentReadError = class _DocumentReadError extends AIError {
16318
+ constructor(source, message, originalError) {
16319
+ super(
16320
+ `Failed to read document '${source}': ${message}`,
16321
+ "DOCUMENT_READ_ERROR",
16322
+ 500,
16323
+ originalError
16324
+ );
16325
+ this.source = source;
16326
+ this.name = "DocumentReadError";
16327
+ Object.setPrototypeOf(this, _DocumentReadError.prototype);
16328
+ }
16329
+ };
16330
+ var UnsupportedFormatError = class _UnsupportedFormatError extends AIError {
16331
+ constructor(format, family) {
16332
+ super(
16333
+ `Unsupported document format: '${format}'${family ? ` (family: ${family})` : ""}`,
16334
+ "UNSUPPORTED_FORMAT",
16335
+ 400
16336
+ );
16337
+ this.format = format;
16338
+ this.family = family;
16339
+ this.name = "UnsupportedFormatError";
16340
+ Object.setPrototypeOf(this, _UnsupportedFormatError.prototype);
16341
+ }
16342
+ };
15746
16343
  var ContextOverflowError = class _ContextOverflowError extends AIError {
15747
16344
  constructor(message, budget) {
15748
16345
  super(
@@ -18146,24 +18743,9 @@ var ContentType = /* @__PURE__ */ ((ContentType2) => {
18146
18743
  ContentType2["TOOL_RESULT"] = "tool_result";
18147
18744
  return ContentType2;
18148
18745
  })(ContentType || {});
18149
- var AGENT_DEFAULTS = {
18150
- /** Default maximum iterations for agentic loop */
18151
- MAX_ITERATIONS: 50,
18152
- /** Default temperature for LLM calls */
18153
- DEFAULT_TEMPERATURE: 0.7,
18154
- /** Message injected when max iterations is reached */
18155
- MAX_ITERATIONS_MESSAGE: `You have reached the maximum iteration limit for this execution. Please:
18156
- 1. Summarize what you have accomplished so far
18157
- 2. Explain what remains to be done (if anything)
18158
- 3. Ask the user if they would like you to continue
18159
-
18160
- Do NOT use any tools in this response - just provide a clear summary and ask for confirmation to proceed.`
18161
- };
18162
- var TOKEN_ESTIMATION = {
18163
- /** Characters per token for mixed content */
18164
- MIXED_CHARS_PER_TOKEN: 3.5};
18165
18746
 
18166
18747
  // src/core/context-nextgen/BasePluginNextGen.ts
18748
+ init_constants();
18167
18749
  var simpleTokenEstimator = {
18168
18750
  estimateTokens(text) {
18169
18751
  if (!text || text.length === 0) return 0;
@@ -18172,6 +18754,14 @@ var simpleTokenEstimator = {
18172
18754
  estimateDataTokens(data) {
18173
18755
  const text = typeof data === "string" ? data : JSON.stringify(data);
18174
18756
  return this.estimateTokens(text);
18757
+ },
18758
+ estimateImageTokens(width, height, detail) {
18759
+ if (detail === "low") return 85;
18760
+ if (width && height) {
18761
+ const tiles = Math.ceil(width / 512) * Math.ceil(height / 512);
18762
+ return 85 + 170 * tiles;
18763
+ }
18764
+ return 1e3;
18175
18765
  }
18176
18766
  };
18177
18767
  var BasePluginNextGen = class {
@@ -21419,12 +22009,26 @@ var AgentContextNextGen = class _AgentContextNextGen extends EventEmitter {
21419
22009
  return "";
21420
22010
  }
21421
22011
  const id = this.generateId();
21422
- const contentArray = results.map((r) => ({
21423
- type: "tool_result" /* TOOL_RESULT */,
21424
- tool_use_id: r.tool_use_id,
21425
- content: typeof r.content === "string" ? r.content : JSON.stringify(r.content),
21426
- error: r.error
21427
- }));
22012
+ const contentArray = results.map((r) => {
22013
+ let contentStr;
22014
+ let images;
22015
+ if (typeof r.content === "string") {
22016
+ contentStr = r.content;
22017
+ } else if (r.content && Array.isArray(r.content.__images) && r.content.__images.length > 0) {
22018
+ images = r.content.__images;
22019
+ const { __images: _, base64: __, ...rest } = r.content;
22020
+ contentStr = JSON.stringify(rest);
22021
+ } else {
22022
+ contentStr = JSON.stringify(r.content);
22023
+ }
22024
+ return {
22025
+ type: "tool_result" /* TOOL_RESULT */,
22026
+ tool_use_id: r.tool_use_id,
22027
+ content: contentStr,
22028
+ error: r.error,
22029
+ ...images ? { __images: images } : {}
22030
+ };
22031
+ });
21428
22032
  const message = {
21429
22033
  type: "message",
21430
22034
  id,
@@ -21685,12 +22289,29 @@ ${content}`);
21685
22289
  total += this._estimator.estimateDataTokens(c.input || {});
21686
22290
  } else if (c.type === "tool_result" /* TOOL_RESULT */) {
21687
22291
  total += this._estimator.estimateTokens(c.content || "");
22292
+ const images = c.__images;
22293
+ if (images?.length) {
22294
+ for (const _img of images) {
22295
+ total += this._estimateImageTokens();
22296
+ }
22297
+ }
21688
22298
  } else if (c.type === "input_image_url" /* INPUT_IMAGE_URL */) {
21689
- total += 200;
22299
+ const imgContent = c;
22300
+ const detail = imgContent.image_url?.detail;
22301
+ total += this._estimateImageTokens(void 0, void 0, detail);
21690
22302
  }
21691
22303
  }
21692
22304
  return total;
21693
22305
  }
22306
+ /**
22307
+ * Estimate tokens for a single image, using the estimator's image method if available.
22308
+ */
22309
+ _estimateImageTokens(width, height, detail) {
22310
+ if (this._estimator.estimateImageTokens) {
22311
+ return this._estimator.estimateImageTokens(width, height, detail);
22312
+ }
22313
+ return 1e3;
22314
+ }
21694
22315
  // ============================================================================
21695
22316
  // Compaction
21696
22317
  // ============================================================================
@@ -21923,7 +22544,8 @@ ${content}`);
21923
22544
  if (c.type === "tool_result" /* TOOL_RESULT */) {
21924
22545
  const toolResult = c;
21925
22546
  const content = toolResult.content || "";
21926
- if (this.isBinaryContent(content)) {
22547
+ const images = toolResult.__images;
22548
+ if (!images?.length && this.isBinaryContent(content)) {
21927
22549
  truncatedContent.push({
21928
22550
  type: "tool_result" /* TOOL_RESULT */,
21929
22551
  tool_use_id: toolResult.tool_use_id,
@@ -21940,7 +22562,9 @@ ${content}`);
21940
22562
  tool_use_id: toolResult.tool_use_id,
21941
22563
  content: `${truncated}
21942
22564
 
21943
- [TRUNCATED: Original output was ${Math.round(content.length / 1024)}KB. Only first ${Math.round(availableChars / 1024)}KB shown. Consider using more targeted queries.]`
22565
+ [TRUNCATED: Original output was ${Math.round(content.length / 1024)}KB. Only first ${Math.round(availableChars / 1024)}KB shown. Consider using more targeted queries.]`,
22566
+ // Preserve images even when text is truncated — they're handled natively by providers
22567
+ ...images ? { __images: images } : {}
21944
22568
  });
21945
22569
  totalCharsUsed += truncated.length + 150;
21946
22570
  } else if (availableChars > 0) {
@@ -21951,7 +22575,9 @@ ${content}`);
21951
22575
  type: "tool_result" /* TOOL_RESULT */,
21952
22576
  tool_use_id: toolResult.tool_use_id,
21953
22577
  content: "[Output too large - skipped due to context limits. Try a more targeted query.]",
21954
- error: "Output too large"
22578
+ error: "Output too large",
22579
+ // Preserve images even when text is dropped
22580
+ ...images ? { __images: images } : {}
21955
22581
  });
21956
22582
  totalCharsUsed += 100;
21957
22583
  }
@@ -22480,14 +23106,41 @@ var OpenAIResponsesConverter = class {
22480
23106
  arguments: content.arguments
22481
23107
  });
22482
23108
  break;
22483
- case "tool_result":
22484
- const output = typeof content.content === "string" ? content.content : JSON.stringify(content.content);
23109
+ case "tool_result": {
23110
+ const contentImages = content.__images;
23111
+ let outputText;
23112
+ let images;
23113
+ if (contentImages?.length) {
23114
+ outputText = typeof content.content === "string" ? content.content : JSON.stringify(content.content);
23115
+ images = contentImages;
23116
+ } else {
23117
+ const rawOutput = typeof content.content === "string" ? content.content : JSON.stringify(content.content);
23118
+ const extracted = this.extractImagesFromOutput(rawOutput);
23119
+ outputText = extracted.text;
23120
+ images = extracted.images;
23121
+ }
22485
23122
  items.push({
22486
23123
  type: "function_call_output",
22487
23124
  call_id: content.tool_use_id,
22488
- output
23125
+ output: outputText
22489
23126
  });
23127
+ if (images.length > 0) {
23128
+ const imageContent = images.map((img) => ({
23129
+ type: "input_image",
23130
+ image_url: `data:${img.mediaType};base64,${img.base64}`
23131
+ }));
23132
+ items.push({
23133
+ type: "message",
23134
+ role: "user",
23135
+ content: [
23136
+ { type: "input_text", text: "[Screenshot from tool result]" },
23137
+ ...imageContent
23138
+ ],
23139
+ status: "completed"
23140
+ });
23141
+ }
22490
23142
  break;
23143
+ }
22491
23144
  }
22492
23145
  }
22493
23146
  if (messageContent.length > 0) {
@@ -22655,6 +23308,22 @@ var OpenAIResponsesConverter = class {
22655
23308
  }
22656
23309
  };
22657
23310
  }
23311
+ /**
23312
+ * Extract __images from a JSON tool result and return cleaned text + images.
23313
+ * Used by the __images convention for multimodal tool results.
23314
+ */
23315
+ extractImagesFromOutput(output) {
23316
+ try {
23317
+ const parsed = JSON.parse(output);
23318
+ if (parsed && Array.isArray(parsed.__images) && parsed.__images.length > 0) {
23319
+ const images = parsed.__images;
23320
+ const { __images: _, base64: __, ...rest } = parsed;
23321
+ return { text: JSON.stringify(rest), images };
23322
+ }
23323
+ } catch {
23324
+ }
23325
+ return { text: output, images: [] };
23326
+ }
22658
23327
  };
22659
23328
 
22660
23329
  // src/domain/entities/StreamEvent.ts
@@ -23460,6 +24129,7 @@ var AnthropicConverter = class extends BaseConverter {
23460
24129
  /**
23461
24130
  * Convert tool result to Anthropic block
23462
24131
  * Anthropic requires non-empty content when is_error is true
24132
+ * Supports __images convention: tool results with __images get multimodal content
23463
24133
  */
23464
24134
  convertToolResultToAnthropicBlock(resultContent) {
23465
24135
  const isError = !!resultContent.error;
@@ -23472,6 +24142,30 @@ var AnthropicConverter = class extends BaseConverter {
23472
24142
  if (isError && !toolResultContent) {
23473
24143
  toolResultContent = resultContent.error || "Tool execution failed";
23474
24144
  }
24145
+ const images = resultContent.__images?.length ? resultContent.__images : this.extractImages(toolResultContent);
24146
+ if (images) {
24147
+ const textContent = resultContent.__images?.length ? toolResultContent : this.stripImagesFromContent(toolResultContent);
24148
+ const contentBlocks = [];
24149
+ if (textContent.trim()) {
24150
+ contentBlocks.push({ type: "text", text: textContent });
24151
+ }
24152
+ for (const img of images) {
24153
+ contentBlocks.push({
24154
+ type: "image",
24155
+ source: {
24156
+ type: "base64",
24157
+ media_type: img.mediaType || "image/png",
24158
+ data: img.base64
24159
+ }
24160
+ });
24161
+ }
24162
+ return {
24163
+ type: "tool_result",
24164
+ tool_use_id: resultContent.tool_use_id,
24165
+ content: contentBlocks.length > 0 ? contentBlocks : textContent,
24166
+ is_error: isError
24167
+ };
24168
+ }
23475
24169
  return {
23476
24170
  type: "tool_result",
23477
24171
  tool_use_id: resultContent.tool_use_id,
@@ -23479,6 +24173,32 @@ var AnthropicConverter = class extends BaseConverter {
23479
24173
  is_error: isError
23480
24174
  };
23481
24175
  }
24176
+ /**
24177
+ * Extract __images from a JSON-stringified tool result content.
24178
+ * Returns null if no images found.
24179
+ */
24180
+ extractImages(content) {
24181
+ try {
24182
+ const parsed = JSON.parse(content);
24183
+ if (parsed && Array.isArray(parsed.__images) && parsed.__images.length > 0) {
24184
+ return parsed.__images;
24185
+ }
24186
+ } catch {
24187
+ }
24188
+ return null;
24189
+ }
24190
+ /**
24191
+ * Strip __images and base64 fields from JSON content to reduce token usage in text.
24192
+ */
24193
+ stripImagesFromContent(content) {
24194
+ try {
24195
+ const parsed = JSON.parse(content);
24196
+ const { __images: _, base64: __, ...rest } = parsed;
24197
+ return JSON.stringify(rest);
24198
+ } catch {
24199
+ return content;
24200
+ }
24201
+ }
23482
24202
  /**
23483
24203
  * Convert our Tool[] -> Anthropic tools
23484
24204
  * Uses shared conversion utilities (DRY)
@@ -24206,18 +24926,38 @@ var GoogleConverter = class {
24206
24926
  }
24207
24927
  parts.push(functionCallPart);
24208
24928
  break;
24209
- case "tool_result" /* TOOL_RESULT */:
24929
+ case "tool_result" /* TOOL_RESULT */: {
24210
24930
  const functionName = this.toolCallMapping.get(c.tool_use_id) || this.extractToolName(c.tool_use_id);
24931
+ const contentImages = c.__images;
24932
+ let resultText;
24933
+ let resultImages;
24934
+ if (contentImages?.length) {
24935
+ resultText = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
24936
+ resultImages = contentImages;
24937
+ } else {
24938
+ const resultStr = typeof c.content === "string" ? c.content : JSON.stringify(c.content);
24939
+ const extracted = this.extractImagesFromResult(resultStr);
24940
+ resultText = extracted.text;
24941
+ resultImages = extracted.images;
24942
+ }
24211
24943
  parts.push({
24212
24944
  functionResponse: {
24213
24945
  name: functionName,
24214
- // Use actual function name from mapping
24215
24946
  response: {
24216
- result: typeof c.content === "string" ? c.content : c.content
24947
+ result: resultText
24217
24948
  }
24218
24949
  }
24219
24950
  });
24951
+ for (const img of resultImages) {
24952
+ parts.push({
24953
+ inlineData: {
24954
+ mimeType: img.mediaType || "image/png",
24955
+ data: img.base64
24956
+ }
24957
+ });
24958
+ }
24220
24959
  break;
24960
+ }
24221
24961
  }
24222
24962
  }
24223
24963
  return parts;
@@ -24353,6 +25093,22 @@ var GoogleConverter = class {
24353
25093
  reset() {
24354
25094
  this.clearMappings();
24355
25095
  }
25096
+ /**
25097
+ * Extract __images from a JSON tool result and return cleaned text + images.
25098
+ * Used by the __images convention for multimodal tool results.
25099
+ */
25100
+ extractImagesFromResult(content) {
25101
+ try {
25102
+ const parsed = JSON.parse(content);
25103
+ if (parsed && Array.isArray(parsed.__images) && parsed.__images.length > 0) {
25104
+ const images = parsed.__images;
25105
+ const { __images: _, base64: __, ...rest } = parsed;
25106
+ return { text: JSON.stringify(rest), images };
25107
+ }
25108
+ } catch {
25109
+ }
25110
+ return { text: content, images: [] };
25111
+ }
24356
25112
  };
24357
25113
  var GoogleStreamConverter = class {
24358
25114
  responseId = "";
@@ -26315,6 +27071,7 @@ function assertNotDestroyed(obj, operation) {
26315
27071
 
26316
27072
  // src/core/Agent.ts
26317
27073
  init_Metrics();
27074
+ init_constants();
26318
27075
  var Agent = class _Agent extends BaseAgent {
26319
27076
  // ===== Agent-specific State =====
26320
27077
  hookManager;
@@ -27522,6 +28279,9 @@ var Agent = class _Agent extends BaseAgent {
27522
28279
  this._logger.debug("Agent destroyed");
27523
28280
  }
27524
28281
  };
28282
+
28283
+ // src/core/index.ts
28284
+ init_constants();
27525
28285
  (class {
27526
28286
  static DEFAULT_PATHS = [
27527
28287
  "./oneringai.config.json",
@@ -30931,9 +31691,6 @@ var Client = class extends Protocol {
30931
31691
  }
30932
31692
  };
30933
31693
 
30934
- // node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
30935
- var import_cross_spawn = __toESM(require_cross_spawn());
30936
-
30937
31694
  // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
30938
31695
  var ReadBuffer = class {
30939
31696
  append(chunk) {
@@ -31011,7 +31768,7 @@ var StdioClientTransport = class {
31011
31768
  throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
31012
31769
  }
31013
31770
  return new Promise((resolve4, reject) => {
31014
- this._process = (0, import_cross_spawn.default)(this._serverParams.command, this._serverParams.args ?? [], {
31771
+ this._process = spawn$1(this._serverParams.command, this._serverParams.args ?? [], {
31015
31772
  // merge default env with server env because mcp server needs some env vars
31016
31773
  env: {
31017
31774
  ...getDefaultEnvironment(),
@@ -38560,6 +39317,494 @@ var ZenRowsProvider = class {
38560
39317
  };
38561
39318
  registerScrapeProvider("zenrows", ZenRowsProvider);
38562
39319
 
39320
+ // src/capabilities/documents/DocumentReader.ts
39321
+ init_constants();
39322
+
39323
+ // src/capabilities/documents/FormatDetector.ts
39324
+ var EXTENSION_MAP = {
39325
+ // Office
39326
+ ".docx": { format: "docx", family: "office", mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
39327
+ ".pptx": { format: "pptx", family: "office", mimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation" },
39328
+ ".odt": { format: "odt", family: "office", mimeType: "application/vnd.oasis.opendocument.text" },
39329
+ ".odp": { format: "odp", family: "office", mimeType: "application/vnd.oasis.opendocument.presentation" },
39330
+ ".ods": { format: "ods", family: "office", mimeType: "application/vnd.oasis.opendocument.spreadsheet" },
39331
+ ".rtf": { format: "rtf", family: "office", mimeType: "application/rtf" },
39332
+ // Spreadsheet
39333
+ ".xlsx": { format: "xlsx", family: "spreadsheet", mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
39334
+ ".csv": { format: "csv", family: "spreadsheet", mimeType: "text/csv" },
39335
+ // PDF
39336
+ ".pdf": { format: "pdf", family: "pdf", mimeType: "application/pdf" },
39337
+ // HTML
39338
+ ".html": { format: "html", family: "html", mimeType: "text/html" },
39339
+ ".htm": { format: "html", family: "html", mimeType: "text/html" },
39340
+ // Text
39341
+ ".txt": { format: "txt", family: "text", mimeType: "text/plain" },
39342
+ ".md": { format: "md", family: "text", mimeType: "text/markdown" },
39343
+ ".json": { format: "json", family: "text", mimeType: "application/json" },
39344
+ ".xml": { format: "xml", family: "text", mimeType: "application/xml" },
39345
+ ".yaml": { format: "yaml", family: "text", mimeType: "application/yaml" },
39346
+ ".yml": { format: "yml", family: "text", mimeType: "application/yaml" },
39347
+ // Image
39348
+ ".png": { format: "png", family: "image", mimeType: "image/png" },
39349
+ ".jpg": { format: "jpg", family: "image", mimeType: "image/jpeg" },
39350
+ ".jpeg": { format: "jpeg", family: "image", mimeType: "image/jpeg" },
39351
+ ".gif": { format: "gif", family: "image", mimeType: "image/gif" },
39352
+ ".webp": { format: "webp", family: "image", mimeType: "image/webp" },
39353
+ ".svg": { format: "svg", family: "image", mimeType: "image/svg+xml" }
39354
+ };
39355
+ var MIME_MAP = {
39356
+ "application/pdf": { format: "pdf", family: "pdf" },
39357
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document": { format: "docx", family: "office" },
39358
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation": { format: "pptx", family: "office" },
39359
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { format: "xlsx", family: "spreadsheet" },
39360
+ "application/vnd.oasis.opendocument.text": { format: "odt", family: "office" },
39361
+ "application/vnd.oasis.opendocument.presentation": { format: "odp", family: "office" },
39362
+ "application/vnd.oasis.opendocument.spreadsheet": { format: "ods", family: "office" },
39363
+ "application/rtf": { format: "rtf", family: "office" },
39364
+ "text/rtf": { format: "rtf", family: "office" },
39365
+ "text/csv": { format: "csv", family: "spreadsheet" },
39366
+ "application/csv": { format: "csv", family: "spreadsheet" }
39367
+ };
39368
+ var BINARY_DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set([
39369
+ ".docx",
39370
+ ".pptx",
39371
+ ".xlsx",
39372
+ ".odt",
39373
+ ".odp",
39374
+ ".ods",
39375
+ ".pdf",
39376
+ ".png",
39377
+ ".jpg",
39378
+ ".jpeg",
39379
+ ".gif",
39380
+ ".webp"
39381
+ ]);
39382
+ var FormatDetector = class _FormatDetector {
39383
+ /**
39384
+ * Detect format from filename and optional buffer
39385
+ */
39386
+ static detect(filename, _buffer) {
39387
+ const ext = _FormatDetector.getExtension(filename);
39388
+ const entry = EXTENSION_MAP[ext];
39389
+ if (!entry) {
39390
+ return {
39391
+ format: "txt",
39392
+ family: "text",
39393
+ mimeType: "text/plain",
39394
+ confidence: "low"
39395
+ };
39396
+ }
39397
+ return {
39398
+ format: entry.format,
39399
+ family: entry.family,
39400
+ mimeType: entry.mimeType,
39401
+ confidence: "high"
39402
+ };
39403
+ }
39404
+ /**
39405
+ * Check if an extension is a supported document format
39406
+ * Used by readFile to detect when to use DocumentReader
39407
+ */
39408
+ static isDocumentFormat(ext) {
39409
+ const normalizedExt = ext.startsWith(".") ? ext.toLowerCase() : `.${ext.toLowerCase()}`;
39410
+ return normalizedExt in EXTENSION_MAP;
39411
+ }
39412
+ /**
39413
+ * Check if an extension is a binary document format
39414
+ * (i.e., cannot be read as UTF-8)
39415
+ */
39416
+ static isBinaryDocumentFormat(ext) {
39417
+ const normalizedExt = ext.startsWith(".") ? ext.toLowerCase() : `.${ext.toLowerCase()}`;
39418
+ return BINARY_DOCUMENT_EXTENSIONS.has(normalizedExt);
39419
+ }
39420
+ /**
39421
+ * Check if a Content-Type header indicates a document format
39422
+ * Used by webFetch to detect downloadable documents
39423
+ */
39424
+ static isDocumentMimeType(contentType) {
39425
+ const mime = (contentType.split(";")[0] ?? "").trim().toLowerCase();
39426
+ return mime in MIME_MAP;
39427
+ }
39428
+ /**
39429
+ * Detect format from Content-Type header
39430
+ */
39431
+ static detectFromMimeType(contentType) {
39432
+ const mime = (contentType.split(";")[0] ?? "").trim().toLowerCase();
39433
+ const entry = MIME_MAP[mime];
39434
+ if (!entry) return null;
39435
+ const extEntry = Object.values(EXTENSION_MAP).find(
39436
+ (e) => e.format === entry.format
39437
+ );
39438
+ return {
39439
+ format: entry.format,
39440
+ family: entry.family,
39441
+ mimeType: extEntry?.mimeType || mime,
39442
+ confidence: "high"
39443
+ };
39444
+ }
39445
+ /**
39446
+ * Get all supported document extensions
39447
+ */
39448
+ static getSupportedExtensions() {
39449
+ return Object.keys(EXTENSION_MAP);
39450
+ }
39451
+ /**
39452
+ * Get the normalized extension from a filename
39453
+ */
39454
+ static getExtension(filename) {
39455
+ const lastDot = filename.lastIndexOf(".");
39456
+ if (lastDot === -1 || lastDot === filename.length - 1) return "";
39457
+ return filename.slice(lastDot).toLowerCase();
39458
+ }
39459
+ };
39460
+
39461
+ // src/capabilities/documents/DocumentReader.ts
39462
+ var DocumentReader = class _DocumentReader {
39463
+ handlers;
39464
+ config;
39465
+ constructor(config = {}) {
39466
+ this.config = config;
39467
+ this.handlers = config.handlers ? new Map(config.handlers) : /* @__PURE__ */ new Map();
39468
+ }
39469
+ /**
39470
+ * Create a new DocumentReader instance
39471
+ */
39472
+ static create(config = {}) {
39473
+ const reader = new _DocumentReader(config);
39474
+ reader.registerDefaultHandlers();
39475
+ return reader;
39476
+ }
39477
+ /**
39478
+ * Register all default format handlers (lazy-loaded)
39479
+ */
39480
+ registerDefaultHandlers() {
39481
+ }
39482
+ /**
39483
+ * Register a custom format handler
39484
+ */
39485
+ registerHandler(family, handler) {
39486
+ this.handlers.set(family, handler);
39487
+ }
39488
+ /**
39489
+ * Read a document from any source
39490
+ */
39491
+ async read(source, options = {}) {
39492
+ const startTime = Date.now();
39493
+ const warnings = [];
39494
+ const mergedOptions = {
39495
+ ...this.config.defaults,
39496
+ ...options,
39497
+ formatOptions: {
39498
+ ...this.config.defaults?.formatOptions,
39499
+ ...options.formatOptions
39500
+ },
39501
+ imageFilter: {
39502
+ ...this.config.defaults?.imageFilter,
39503
+ ...options.imageFilter
39504
+ }
39505
+ };
39506
+ try {
39507
+ const { buffer, filename } = await this.resolveSource(
39508
+ typeof source === "string" ? this.parseStringSource(source) : source
39509
+ );
39510
+ const detection = FormatDetector.detect(filename, buffer);
39511
+ const handler = await this.getHandler(detection.family);
39512
+ if (!handler) {
39513
+ throw new UnsupportedFormatError(detection.format, detection.family);
39514
+ }
39515
+ let pieces = await handler.handle(buffer, filename, detection.format, mergedOptions);
39516
+ if (mergedOptions.extractImages !== false) {
39517
+ pieces = this.filterImages(pieces, mergedOptions.imageFilter);
39518
+ } else {
39519
+ pieces = pieces.filter((p) => p.type !== "image");
39520
+ }
39521
+ const transformerContext = {
39522
+ filename,
39523
+ format: detection.format,
39524
+ family: detection.family,
39525
+ options: mergedOptions
39526
+ };
39527
+ pieces = await this.runTransformers(pieces, transformerContext, mergedOptions);
39528
+ const metadata = this.assembleMetadata(pieces, filename, detection, startTime);
39529
+ return {
39530
+ success: true,
39531
+ pieces,
39532
+ metadata,
39533
+ warnings
39534
+ };
39535
+ } catch (error) {
39536
+ if (error instanceof DocumentReadError || error instanceof UnsupportedFormatError) {
39537
+ throw error;
39538
+ }
39539
+ throw new DocumentReadError(
39540
+ typeof source === "string" ? source : "path" in source ? source.path : "filename" in source ? source.filename : "unknown",
39541
+ error instanceof Error ? error.message : String(error),
39542
+ error instanceof Error ? error : void 0
39543
+ );
39544
+ }
39545
+ }
39546
+ /**
39547
+ * Parse a string source (auto-detect path vs URL)
39548
+ */
39549
+ parseStringSource(source) {
39550
+ if (source.startsWith("http://") || source.startsWith("https://")) {
39551
+ return { type: "url", url: source };
39552
+ }
39553
+ return { type: "file", path: source };
39554
+ }
39555
+ /**
39556
+ * Resolve any source to a buffer and filename
39557
+ */
39558
+ async resolveSource(source) {
39559
+ switch (source.type) {
39560
+ case "file": {
39561
+ const buffer = await readFile(source.path);
39562
+ const filename = source.path.split("/").pop() || source.path;
39563
+ return { buffer, filename };
39564
+ }
39565
+ case "url": {
39566
+ const maxSize = this.config.maxDownloadSizeBytes ?? DOCUMENT_DEFAULTS.MAX_DOWNLOAD_SIZE_BYTES;
39567
+ const timeout = this.config.downloadTimeoutMs ?? DOCUMENT_DEFAULTS.DOWNLOAD_TIMEOUT_MS;
39568
+ const controller = new AbortController();
39569
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
39570
+ try {
39571
+ const response = await fetch(source.url, {
39572
+ headers: {
39573
+ ...source.headers,
39574
+ "User-Agent": "OneRingAI-DocumentReader/1.0"
39575
+ },
39576
+ signal: controller.signal
39577
+ });
39578
+ clearTimeout(timeoutId);
39579
+ if (!response.ok) {
39580
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
39581
+ }
39582
+ const contentLength = response.headers.get("content-length");
39583
+ if (contentLength && parseInt(contentLength, 10) > maxSize) {
39584
+ throw new Error(`File too large: ${contentLength} bytes (max: ${maxSize})`);
39585
+ }
39586
+ const arrayBuffer = await response.arrayBuffer();
39587
+ if (arrayBuffer.byteLength > maxSize) {
39588
+ throw new Error(`Downloaded file too large: ${arrayBuffer.byteLength} bytes (max: ${maxSize})`);
39589
+ }
39590
+ const filename = this.extractFilenameFromURL(source.url, response);
39591
+ return { buffer: Buffer.from(arrayBuffer), filename };
39592
+ } catch (error) {
39593
+ clearTimeout(timeoutId);
39594
+ if (error.name === "AbortError") {
39595
+ throw new Error(`Download timed out after ${timeout}ms`);
39596
+ }
39597
+ throw error;
39598
+ }
39599
+ }
39600
+ case "buffer": {
39601
+ const buffer = Buffer.isBuffer(source.buffer) ? source.buffer : Buffer.from(source.buffer);
39602
+ return { buffer, filename: source.filename };
39603
+ }
39604
+ case "blob": {
39605
+ const arrayBuffer = await source.blob.arrayBuffer();
39606
+ return { buffer: Buffer.from(arrayBuffer), filename: source.filename };
39607
+ }
39608
+ }
39609
+ }
39610
+ /**
39611
+ * Extract filename from URL and response headers
39612
+ */
39613
+ extractFilenameFromURL(url2, response) {
39614
+ const disposition = response.headers.get("content-disposition");
39615
+ if (disposition) {
39616
+ const match = disposition.match(/filename[^;=\n]*=(['"]?)([^'"\n;]*)\1/);
39617
+ if (match?.[2]) return match[2];
39618
+ }
39619
+ try {
39620
+ const pathname = new URL(url2).pathname;
39621
+ const basename = pathname.split("/").pop();
39622
+ if (basename && basename.includes(".")) return basename;
39623
+ } catch {
39624
+ }
39625
+ return "document";
39626
+ }
39627
+ /**
39628
+ * Get the handler for a format family, loading defaults lazily
39629
+ */
39630
+ async getHandler(family) {
39631
+ if (this.handlers.has(family)) {
39632
+ return this.handlers.get(family);
39633
+ }
39634
+ try {
39635
+ const { getDefaultHandlers: getDefaultHandlers2 } = await Promise.resolve().then(() => (init_handlers(), handlers_exports));
39636
+ const defaults = getDefaultHandlers2();
39637
+ const handler = defaults.get(family);
39638
+ if (handler) {
39639
+ this.handlers.set(family, handler);
39640
+ return handler;
39641
+ }
39642
+ } catch {
39643
+ }
39644
+ return null;
39645
+ }
39646
+ /**
39647
+ * Filter images based on options
39648
+ */
39649
+ filterImages(pieces, filterOptions) {
39650
+ const minWidth = filterOptions?.minWidth ?? DOCUMENT_DEFAULTS.IMAGE_FILTER.MIN_WIDTH;
39651
+ const minHeight = filterOptions?.minHeight ?? DOCUMENT_DEFAULTS.IMAGE_FILTER.MIN_HEIGHT;
39652
+ const minSizeBytes = filterOptions?.minSizeBytes ?? DOCUMENT_DEFAULTS.IMAGE_FILTER.MIN_SIZE_BYTES;
39653
+ const maxImages = filterOptions?.maxImages ?? DOCUMENT_DEFAULTS.MAX_EXTRACTED_IMAGES;
39654
+ const excludePatterns = filterOptions?.excludePatterns ?? [];
39655
+ let imageCount = 0;
39656
+ return pieces.filter((piece) => {
39657
+ if (piece.type !== "image") return true;
39658
+ const img = piece;
39659
+ if (img.width !== void 0 && img.width < minWidth) return false;
39660
+ if (img.height !== void 0 && img.height < minHeight) return false;
39661
+ if (img.metadata.sizeBytes < minSizeBytes) return false;
39662
+ const label = img.metadata.label || "";
39663
+ if (excludePatterns.some((p) => p.test(label))) return false;
39664
+ imageCount++;
39665
+ if (imageCount > maxImages) return false;
39666
+ return true;
39667
+ });
39668
+ }
39669
+ /**
39670
+ * Run the transformer pipeline
39671
+ */
39672
+ async runTransformers(pieces, context, options) {
39673
+ const transformers = [];
39674
+ if (!options.skipDefaultTransformers) {
39675
+ try {
39676
+ const { getDefaultTransformers: getDefaultTransformers2 } = await Promise.resolve().then(() => (init_transformers(), transformers_exports));
39677
+ transformers.push(...getDefaultTransformers2());
39678
+ } catch {
39679
+ }
39680
+ }
39681
+ if (options.transformers) {
39682
+ transformers.push(...options.transformers);
39683
+ }
39684
+ transformers.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
39685
+ let result = pieces;
39686
+ for (const transformer of transformers) {
39687
+ if (transformer.appliesTo.length === 0 || transformer.appliesTo.includes(context.format)) {
39688
+ result = await transformer.transform(result, context);
39689
+ }
39690
+ }
39691
+ return result;
39692
+ }
39693
+ /**
39694
+ * Assemble metadata from pieces
39695
+ */
39696
+ assembleMetadata(pieces, filename, detection, startTime) {
39697
+ const textPieces = pieces.filter((p) => p.type === "text");
39698
+ const imagePieces = pieces.filter((p) => p.type === "image");
39699
+ const totalSizeBytes = pieces.reduce((sum, p) => sum + p.metadata.sizeBytes, 0);
39700
+ const estimatedTokens = pieces.reduce((sum, p) => sum + p.metadata.estimatedTokens, 0);
39701
+ return {
39702
+ filename,
39703
+ format: detection.format,
39704
+ family: detection.family,
39705
+ mimeType: detection.mimeType,
39706
+ totalPieces: pieces.length,
39707
+ totalTextPieces: textPieces.length,
39708
+ totalImagePieces: imagePieces.length,
39709
+ totalSizeBytes,
39710
+ estimatedTokens,
39711
+ processingTimeMs: Date.now() - startTime
39712
+ };
39713
+ }
39714
+ };
39715
+ function mergeTextPieces(pieces) {
39716
+ return pieces.filter((p) => p.type === "text").map((p) => p.content).join("\n\n");
39717
+ }
39718
+
39719
+ // src/capabilities/documents/index.ts
39720
+ init_handlers();
39721
+ init_transformers();
39722
+
39723
+ // src/utils/documentContentBridge.ts
39724
+ function documentToContent(result, options = {}) {
39725
+ const {
39726
+ imageDetail = "auto",
39727
+ imageFilter,
39728
+ maxImages = 20,
39729
+ mergeAdjacentText = true
39730
+ } = options;
39731
+ const minWidth = imageFilter?.minWidth ?? 0;
39732
+ const minHeight = imageFilter?.minHeight ?? 0;
39733
+ const minSizeBytes = imageFilter?.minSizeBytes ?? 0;
39734
+ const excludePatterns = imageFilter?.excludePatterns ?? [];
39735
+ const contents = [];
39736
+ let imageCount = 0;
39737
+ let pendingText = [];
39738
+ const flushText = () => {
39739
+ if (pendingText.length > 0) {
39740
+ const text = {
39741
+ type: "input_text" /* INPUT_TEXT */,
39742
+ text: pendingText.join("\n\n")
39743
+ };
39744
+ contents.push(text);
39745
+ pendingText = [];
39746
+ }
39747
+ };
39748
+ for (const piece of result.pieces) {
39749
+ if (piece.type === "text") {
39750
+ if (mergeAdjacentText) {
39751
+ pendingText.push(piece.content);
39752
+ } else {
39753
+ const text = {
39754
+ type: "input_text" /* INPUT_TEXT */,
39755
+ text: piece.content
39756
+ };
39757
+ contents.push(text);
39758
+ }
39759
+ } else if (piece.type === "image") {
39760
+ if (piece.width !== void 0 && piece.width < minWidth) continue;
39761
+ if (piece.height !== void 0 && piece.height < minHeight) continue;
39762
+ if (piece.metadata.sizeBytes < minSizeBytes) continue;
39763
+ const label = piece.metadata.label || "";
39764
+ if (excludePatterns.some((p) => p.test(label))) continue;
39765
+ imageCount++;
39766
+ if (imageCount > maxImages) continue;
39767
+ flushText();
39768
+ const imageContent = {
39769
+ type: "input_image_url" /* INPUT_IMAGE_URL */,
39770
+ image_url: {
39771
+ url: `data:${piece.mimeType};base64,${piece.base64}`,
39772
+ detail: imageDetail
39773
+ }
39774
+ };
39775
+ contents.push(imageContent);
39776
+ }
39777
+ }
39778
+ flushText();
39779
+ return contents;
39780
+ }
39781
+ async function readDocumentAsContent(source, options = {}) {
39782
+ const {
39783
+ imageDetail,
39784
+ maxImages,
39785
+ mergeAdjacentText,
39786
+ // imageFilter is shared between both
39787
+ ...readOptions
39788
+ } = options;
39789
+ const contentOptions = {
39790
+ imageDetail,
39791
+ imageFilter: options.imageFilter,
39792
+ maxImages,
39793
+ mergeAdjacentText
39794
+ };
39795
+ const reader = DocumentReader.create();
39796
+ const result = await reader.read(source, readOptions);
39797
+ if (!result.success) {
39798
+ return [
39799
+ {
39800
+ type: "input_text" /* INPUT_TEXT */,
39801
+ text: `[Document read error: ${result.error || "Unknown error"}]`
39802
+ }
39803
+ ];
39804
+ }
39805
+ return documentToContent(result, contentOptions);
39806
+ }
39807
+
38563
39808
  // src/domain/interfaces/IContextStorage.ts
38564
39809
  var CONTEXT_SESSION_FORMAT_VERSION = 1;
38565
39810
 
@@ -40500,6 +41745,21 @@ var ApproximateTokenEstimator = class {
40500
41745
  return 100;
40501
41746
  }
40502
41747
  }
41748
+ /**
41749
+ * Estimate tokens for an image using tile-based model (matches OpenAI pricing).
41750
+ *
41751
+ * - detail='low': 85 tokens
41752
+ * - detail='high' with known dimensions: 85 + 170 per 512×512 tile
41753
+ * - Unknown dimensions: 1000 tokens (conservative default)
41754
+ */
41755
+ estimateImageTokens(width, height, detail) {
41756
+ if (detail === "low") return 85;
41757
+ if (width && height) {
41758
+ const tiles = Math.ceil(width / 512) * Math.ceil(height / 512);
41759
+ return 85 + 170 * tiles;
41760
+ }
41761
+ return 1e3;
41762
+ }
40503
41763
  };
40504
41764
 
40505
41765
  // src/infrastructure/context/estimators/index.ts
@@ -40727,10 +41987,17 @@ var FileContextStorage = class {
40727
41987
  }
40728
41988
  /**
40729
41989
  * Get the storage path (for display/debugging)
41990
+ * @deprecated Use getLocation() instead
40730
41991
  */
40731
41992
  getPath() {
40732
41993
  return this.sessionsDirectory;
40733
41994
  }
41995
+ /**
41996
+ * Get a human-readable storage location string (for display/debugging)
41997
+ */
41998
+ getLocation() {
41999
+ return this.sessionsDirectory;
42000
+ }
40734
42001
  /**
40735
42002
  * Get the agent ID
40736
42003
  */
@@ -41102,7 +42369,7 @@ var FileAgentDefinitionStorage = class {
41102
42369
  function createFileAgentDefinitionStorage(config) {
41103
42370
  return new FileAgentDefinitionStorage(config);
41104
42371
  }
41105
- var MIME_TYPES = {
42372
+ var MIME_TYPES2 = {
41106
42373
  png: "image/png",
41107
42374
  jpeg: "image/jpeg",
41108
42375
  jpg: "image/jpeg",
@@ -41132,7 +42399,7 @@ var FileMediaStorage = class {
41132
42399
  const filePath = path2.join(dir, filename);
41133
42400
  await fs15.writeFile(filePath, data);
41134
42401
  const format = metadata.format.toLowerCase();
41135
- const mimeType = MIME_TYPES[format] ?? "application/octet-stream";
42402
+ const mimeType = MIME_TYPES2[format] ?? "application/octet-stream";
41136
42403
  return {
41137
42404
  location: filePath,
41138
42405
  mimeType,
@@ -41177,7 +42444,7 @@ var FileMediaStorage = class {
41177
42444
  const stat6 = await fs15.stat(filePath);
41178
42445
  if (!stat6.isFile()) continue;
41179
42446
  const ext = path2.extname(file).slice(1).toLowerCase();
41180
- const mimeType = MIME_TYPES[ext] ?? "application/octet-stream";
42447
+ const mimeType = MIME_TYPES2[ext] ?? "application/octet-stream";
41181
42448
  let type;
41182
42449
  for (const prefix of MEDIA_TYPE_PREFIXES) {
41183
42450
  if (file.startsWith(`${prefix}_`)) {
@@ -41669,6 +42936,23 @@ var SERVICE_DEFINITIONS = [
41669
42936
  baseURL: "https://api-m.paypal.com/v2",
41670
42937
  docsURL: "https://developer.paypal.com/docs/api/"
41671
42938
  },
42939
+ {
42940
+ id: "quickbooks",
42941
+ name: "QuickBooks",
42942
+ category: "payments",
42943
+ urlPattern: /quickbooks\.api\.intuit\.com|intuit\.com.*quickbooks/i,
42944
+ baseURL: "https://quickbooks.api.intuit.com/v3",
42945
+ docsURL: "https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/account",
42946
+ commonScopes: ["com.intuit.quickbooks.accounting"]
42947
+ },
42948
+ {
42949
+ id: "ramp",
42950
+ name: "Ramp",
42951
+ category: "payments",
42952
+ urlPattern: /api\.ramp\.com/i,
42953
+ baseURL: "https://api.ramp.com/developer/v1",
42954
+ docsURL: "https://docs.ramp.com/reference"
42955
+ },
41672
42956
  // ============ Cloud Providers ============
41673
42957
  {
41674
42958
  id: "aws",
@@ -43094,7 +44378,9 @@ function getVendorInfo(vendorId) {
43094
44378
  name: a.name,
43095
44379
  type: a.type,
43096
44380
  description: a.description,
43097
- requiredFields: a.requiredFields
44381
+ requiredFields: a.requiredFields,
44382
+ scopes: a.scopes,
44383
+ scopeDescriptions: a.scopeDescriptions
43098
44384
  }))
43099
44385
  };
43100
44386
  }
@@ -43110,7 +44396,9 @@ function listVendors() {
43110
44396
  name: a.name,
43111
44397
  type: a.type,
43112
44398
  description: a.description,
43113
- requiredFields: a.requiredFields
44399
+ requiredFields: a.requiredFields,
44400
+ scopes: a.scopes,
44401
+ scopeDescriptions: a.scopeDescriptions
43114
44402
  }))
43115
44403
  }));
43116
44404
  }
@@ -43159,14 +44447,49 @@ var microsoftTemplate = {
43159
44447
  scopes: [
43160
44448
  "User.Read",
43161
44449
  "Mail.Read",
44450
+ "Mail.ReadWrite",
43162
44451
  "Mail.Send",
43163
- "Files.ReadWrite",
43164
44452
  "Calendars.ReadWrite",
44453
+ "Contacts.Read",
44454
+ "Contacts.ReadWrite",
44455
+ "Files.ReadWrite",
44456
+ "Sites.Read.All",
44457
+ "Sites.ReadWrite.All",
44458
+ "Notes.Read",
44459
+ "Notes.ReadWrite",
44460
+ "Tasks.ReadWrite",
43165
44461
  "ChannelMessage.Send",
43166
44462
  "Team.ReadBasic.All",
43167
44463
  "Chat.ReadWrite",
44464
+ "People.Read",
44465
+ "Presence.Read",
44466
+ "Directory.Read.All",
44467
+ "BookingsAppointment.ReadWrite.All",
43168
44468
  "offline_access"
43169
- ]
44469
+ ],
44470
+ scopeDescriptions: {
44471
+ "User.Read": "Read your profile",
44472
+ "Mail.Read": "Read your email",
44473
+ "Mail.ReadWrite": "Read and write your email",
44474
+ "Mail.Send": "Send email on your behalf",
44475
+ "Calendars.ReadWrite": "Read and write your calendar",
44476
+ "Contacts.Read": "Read your contacts",
44477
+ "Contacts.ReadWrite": "Read and write your contacts",
44478
+ "Files.ReadWrite": "Read and write your files (OneDrive)",
44479
+ "Sites.Read.All": "Read SharePoint sites",
44480
+ "Sites.ReadWrite.All": "Read and write SharePoint sites",
44481
+ "Notes.Read": "Read your OneNote notebooks",
44482
+ "Notes.ReadWrite": "Read and write your OneNote notebooks",
44483
+ "Tasks.ReadWrite": "Read and write your tasks (To Do / Planner)",
44484
+ "ChannelMessage.Send": "Send messages in Teams channels",
44485
+ "Team.ReadBasic.All": "Read Teams basic info",
44486
+ "Chat.ReadWrite": "Read and write Teams chats",
44487
+ "People.Read": "Read your relevant people list",
44488
+ "Presence.Read": "Read user presence information",
44489
+ "Directory.Read.All": "Read directory data (Azure AD)",
44490
+ "BookingsAppointment.ReadWrite.All": "Manage Bookings appointments",
44491
+ "offline_access": "Maintain access (refresh token)"
44492
+ }
43170
44493
  },
43171
44494
  {
43172
44495
  id: "client-credentials",
@@ -43181,7 +44504,10 @@ var microsoftTemplate = {
43181
44504
  flow: "client_credentials",
43182
44505
  tokenUrl: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token"
43183
44506
  },
43184
- scopes: ["https://graph.microsoft.com/.default"]
44507
+ scopes: ["https://graph.microsoft.com/.default"],
44508
+ scopeDescriptions: {
44509
+ "https://graph.microsoft.com/.default": "All permissions granted to the app registration"
44510
+ }
43185
44511
  }
43186
44512
  ]
43187
44513
  };
@@ -43215,9 +44541,24 @@ var googleTemplate = {
43215
44541
  "https://www.googleapis.com/auth/drive",
43216
44542
  "https://www.googleapis.com/auth/calendar",
43217
44543
  "https://www.googleapis.com/auth/gmail.readonly",
44544
+ "https://www.googleapis.com/auth/gmail.send",
43218
44545
  "https://www.googleapis.com/auth/spreadsheets",
43219
- "https://www.googleapis.com/auth/documents"
43220
- ]
44546
+ "https://www.googleapis.com/auth/documents",
44547
+ "https://www.googleapis.com/auth/contacts.readonly",
44548
+ "https://www.googleapis.com/auth/tasks",
44549
+ "https://www.googleapis.com/auth/admin.directory.user.readonly"
44550
+ ],
44551
+ scopeDescriptions: {
44552
+ "https://www.googleapis.com/auth/drive": "Read and write Google Drive files",
44553
+ "https://www.googleapis.com/auth/calendar": "Read and write Google Calendar",
44554
+ "https://www.googleapis.com/auth/gmail.readonly": "Read Gmail messages",
44555
+ "https://www.googleapis.com/auth/gmail.send": "Send Gmail messages",
44556
+ "https://www.googleapis.com/auth/spreadsheets": "Read and write Google Sheets",
44557
+ "https://www.googleapis.com/auth/documents": "Read and write Google Docs",
44558
+ "https://www.googleapis.com/auth/contacts.readonly": "Read Google Contacts",
44559
+ "https://www.googleapis.com/auth/tasks": "Read and write Google Tasks",
44560
+ "https://www.googleapis.com/auth/admin.directory.user.readonly": "Read user directory (Admin)"
44561
+ }
43221
44562
  },
43222
44563
  {
43223
44564
  id: "service-account",
@@ -43236,7 +44577,11 @@ var googleTemplate = {
43236
44577
  scopes: [
43237
44578
  "https://www.googleapis.com/auth/cloud-platform",
43238
44579
  "https://www.googleapis.com/auth/drive"
43239
- ]
44580
+ ],
44581
+ scopeDescriptions: {
44582
+ "https://www.googleapis.com/auth/cloud-platform": "Full access to Google Cloud Platform",
44583
+ "https://www.googleapis.com/auth/drive": "Read and write Google Drive files"
44584
+ }
43240
44585
  }
43241
44586
  ]
43242
44587
  };
@@ -43278,7 +44623,19 @@ var slackTemplate = {
43278
44623
  authorizationUrl: "https://slack.com/oauth/v2/authorize",
43279
44624
  tokenUrl: "https://slack.com/api/oauth.v2.access"
43280
44625
  },
43281
- scopes: ["chat:write", "channels:read", "users:read", "im:write", "groups:read"]
44626
+ scopes: ["chat:write", "channels:read", "users:read", "im:write", "groups:read", "files:read", "files:write", "reactions:read", "reactions:write", "team:read"],
44627
+ scopeDescriptions: {
44628
+ "chat:write": "Send messages as the app",
44629
+ "channels:read": "View basic channel info",
44630
+ "users:read": "View people in the workspace",
44631
+ "im:write": "Send direct messages",
44632
+ "groups:read": "View basic private channel info",
44633
+ "files:read": "View files shared in channels",
44634
+ "files:write": "Upload and manage files",
44635
+ "reactions:read": "View emoji reactions",
44636
+ "reactions:write": "Add and remove emoji reactions",
44637
+ "team:read": "View workspace info"
44638
+ }
43282
44639
  }
43283
44640
  ]
43284
44641
  };
@@ -43319,7 +44676,16 @@ var discordTemplate = {
43319
44676
  authorizationUrl: "https://discord.com/api/oauth2/authorize",
43320
44677
  tokenUrl: "https://discord.com/api/oauth2/token"
43321
44678
  },
43322
- scopes: ["identify", "guilds", "guilds.members.read", "messages.read"]
44679
+ scopes: ["identify", "email", "guilds", "guilds.members.read", "messages.read", "bot", "connections"],
44680
+ scopeDescriptions: {
44681
+ "identify": "Access your username and avatar",
44682
+ "email": "Access your email address",
44683
+ "guilds": "View your server list",
44684
+ "guilds.members.read": "Read server member info",
44685
+ "messages.read": "Read messages in accessible channels",
44686
+ "bot": "Add a bot to your servers",
44687
+ "connections": "View your connected accounts"
44688
+ }
43323
44689
  }
43324
44690
  ]
43325
44691
  };
@@ -43386,7 +44752,18 @@ var githubTemplate = {
43386
44752
  authorizationUrl: "https://github.com/login/oauth/authorize",
43387
44753
  tokenUrl: "https://github.com/login/oauth/access_token"
43388
44754
  },
43389
- scopes: ["repo", "read:user", "read:org", "workflow", "gist"]
44755
+ scopes: ["repo", "read:user", "user:email", "read:org", "workflow", "gist", "notifications", "delete_repo", "admin:org"],
44756
+ scopeDescriptions: {
44757
+ "repo": "Full control of private repositories",
44758
+ "read:user": "Read user profile data",
44759
+ "user:email": "Access user email addresses",
44760
+ "read:org": "Read org and team membership",
44761
+ "workflow": "Update GitHub Actions workflows",
44762
+ "gist": "Create and manage gists",
44763
+ "notifications": "Access notifications",
44764
+ "delete_repo": "Delete repositories",
44765
+ "admin:org": "Full control of orgs and teams"
44766
+ }
43390
44767
  },
43391
44768
  {
43392
44769
  id: "github-app",
@@ -43441,7 +44818,13 @@ var gitlabTemplate = {
43441
44818
  authorizationUrl: "https://gitlab.com/oauth/authorize",
43442
44819
  tokenUrl: "https://gitlab.com/oauth/token"
43443
44820
  },
43444
- scopes: ["api", "read_user", "read_repository", "write_repository"]
44821
+ scopes: ["api", "read_user", "read_repository", "write_repository"],
44822
+ scopeDescriptions: {
44823
+ "api": "Full API access",
44824
+ "read_user": "Read user profile",
44825
+ "read_repository": "Read repository contents",
44826
+ "write_repository": "Write to repositories"
44827
+ }
43445
44828
  }
43446
44829
  ]
43447
44830
  };
@@ -43483,7 +44866,14 @@ var jiraTemplate = {
43483
44866
  authorizationUrl: "https://auth.atlassian.com/authorize",
43484
44867
  tokenUrl: "https://auth.atlassian.com/oauth/token"
43485
44868
  },
43486
- scopes: ["read:jira-work", "write:jira-work", "read:jira-user"]
44869
+ scopes: ["read:jira-work", "write:jira-work", "read:jira-user", "manage:jira-project", "manage:jira-configuration"],
44870
+ scopeDescriptions: {
44871
+ "read:jira-work": "Read issues, projects, boards",
44872
+ "write:jira-work": "Create and update issues",
44873
+ "read:jira-user": "Read user information",
44874
+ "manage:jira-project": "Manage projects and components",
44875
+ "manage:jira-configuration": "Manage Jira settings"
44876
+ }
43487
44877
  }
43488
44878
  ]
43489
44879
  };
@@ -43523,7 +44913,14 @@ var confluenceTemplate = {
43523
44913
  authorizationUrl: "https://auth.atlassian.com/authorize",
43524
44914
  tokenUrl: "https://auth.atlassian.com/oauth/token"
43525
44915
  },
43526
- scopes: ["read:confluence-content.all", "write:confluence-content", "read:confluence-space.summary"]
44916
+ scopes: ["read:confluence-content.all", "write:confluence-content", "read:confluence-space.summary", "write:confluence-space", "read:confluence-user"],
44917
+ scopeDescriptions: {
44918
+ "read:confluence-content.all": "Read all pages and blog posts",
44919
+ "write:confluence-content": "Create and update pages",
44920
+ "read:confluence-space.summary": "Read space summaries",
44921
+ "write:confluence-space": "Create and manage spaces",
44922
+ "read:confluence-user": "Read user information"
44923
+ }
43527
44924
  }
43528
44925
  ]
43529
44926
  };
@@ -43562,7 +44959,16 @@ var bitbucketTemplate = {
43562
44959
  authorizationUrl: "https://bitbucket.org/site/oauth2/authorize",
43563
44960
  tokenUrl: "https://bitbucket.org/site/oauth2/access_token"
43564
44961
  },
43565
- scopes: ["repository", "pullrequest", "account"]
44962
+ scopes: ["repository", "repository:write", "pullrequest", "pullrequest:write", "account", "pipeline", "wiki"],
44963
+ scopeDescriptions: {
44964
+ "repository": "Read repositories",
44965
+ "repository:write": "Write to repositories",
44966
+ "pullrequest": "Read pull requests",
44967
+ "pullrequest:write": "Create and update pull requests",
44968
+ "account": "Read account information",
44969
+ "pipeline": "Access Pipelines (CI/CD)",
44970
+ "wiki": "Access repository wiki"
44971
+ }
43566
44972
  }
43567
44973
  ]
43568
44974
  };
@@ -43602,7 +45008,12 @@ var trelloTemplate = {
43602
45008
  authorizationUrl: "https://trello.com/1/authorize",
43603
45009
  tokenUrl: "https://trello.com/1/OAuthGetAccessToken"
43604
45010
  },
43605
- scopes: ["read", "write", "account"]
45011
+ scopes: ["read", "write", "account"],
45012
+ scopeDescriptions: {
45013
+ "read": "Read boards, lists, and cards",
45014
+ "write": "Create and update boards, lists, and cards",
45015
+ "account": "Read member information"
45016
+ }
43606
45017
  }
43607
45018
  ]
43608
45019
  };
@@ -43797,7 +45208,15 @@ var salesforceTemplate = {
43797
45208
  authorizationUrl: "https://login.salesforce.com/services/oauth2/authorize",
43798
45209
  tokenUrl: "https://login.salesforce.com/services/oauth2/token"
43799
45210
  },
43800
- scopes: ["api", "refresh_token", "offline_access"]
45211
+ scopes: ["api", "refresh_token", "offline_access", "chatter_api", "wave_api", "full"],
45212
+ scopeDescriptions: {
45213
+ "api": "Access and manage your data",
45214
+ "refresh_token": "Maintain access with refresh tokens",
45215
+ "offline_access": "Access data while you are offline",
45216
+ "chatter_api": "Access Chatter feeds and posts",
45217
+ "wave_api": "Access Analytics (Wave) API",
45218
+ "full": "Full access to all data"
45219
+ }
43801
45220
  },
43802
45221
  {
43803
45222
  id: "jwt-bearer",
@@ -43852,7 +45271,26 @@ var hubspotTemplate = {
43852
45271
  authorizationUrl: "https://app.hubspot.com/oauth/authorize",
43853
45272
  tokenUrl: "https://api.hubapi.com/oauth/v1/token"
43854
45273
  },
43855
- scopes: ["crm.objects.contacts.read", "crm.objects.contacts.write", "crm.objects.companies.read"]
45274
+ scopes: [
45275
+ "crm.objects.contacts.read",
45276
+ "crm.objects.contacts.write",
45277
+ "crm.objects.companies.read",
45278
+ "crm.objects.companies.write",
45279
+ "crm.objects.deals.read",
45280
+ "crm.objects.deals.write",
45281
+ "tickets",
45282
+ "e-commerce"
45283
+ ],
45284
+ scopeDescriptions: {
45285
+ "crm.objects.contacts.read": "Read contacts",
45286
+ "crm.objects.contacts.write": "Create and update contacts",
45287
+ "crm.objects.companies.read": "Read companies",
45288
+ "crm.objects.companies.write": "Create and update companies",
45289
+ "crm.objects.deals.read": "Read deals",
45290
+ "crm.objects.deals.write": "Create and update deals",
45291
+ "tickets": "Read and write support tickets",
45292
+ "e-commerce": "Access e-commerce data (products, line items)"
45293
+ }
43856
45294
  }
43857
45295
  ]
43858
45296
  };
@@ -43965,6 +45403,86 @@ var paypalTemplate = {
43965
45403
  ]
43966
45404
  };
43967
45405
 
45406
+ // src/connectors/vendors/templates/quickbooks.ts
45407
+ var quickbooksTemplate = {
45408
+ id: "quickbooks",
45409
+ name: "QuickBooks",
45410
+ serviceType: "quickbooks",
45411
+ baseURL: "https://quickbooks.api.intuit.com/v3",
45412
+ docsURL: "https://developer.intuit.com/app/developer/qbo/docs/api/accounting/all-entities/account",
45413
+ credentialsSetupURL: "https://developer.intuit.com/app/developer/dashboard",
45414
+ category: "payments",
45415
+ notes: "Use sandbox URL (sandbox-quickbooks.api.intuit.com) for testing. Requires company/realm ID in API paths.",
45416
+ authTemplates: [
45417
+ {
45418
+ id: "oauth-user",
45419
+ name: "OAuth (User Authorization)",
45420
+ type: "oauth",
45421
+ flow: "authorization_code",
45422
+ description: "Standard OAuth 2.0 flow for accessing QuickBooks on behalf of a user. Create an app at developer.intuit.com",
45423
+ requiredFields: ["clientId", "clientSecret", "redirectUri"],
45424
+ optionalFields: ["scope"],
45425
+ defaults: {
45426
+ type: "oauth",
45427
+ flow: "authorization_code",
45428
+ authorizationUrl: "https://appcenter.intuit.com/connect/oauth2",
45429
+ tokenUrl: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
45430
+ },
45431
+ scopes: ["com.intuit.quickbooks.accounting", "com.intuit.quickbooks.payment"]
45432
+ }
45433
+ ]
45434
+ };
45435
+
45436
+ // src/connectors/vendors/templates/ramp.ts
45437
+ var rampTemplate = {
45438
+ id: "ramp",
45439
+ name: "Ramp",
45440
+ serviceType: "ramp",
45441
+ baseURL: "https://api.ramp.com/developer/v1",
45442
+ docsURL: "https://docs.ramp.com",
45443
+ credentialsSetupURL: "https://app.ramp.com/settings/developer",
45444
+ category: "payments",
45445
+ authTemplates: [
45446
+ {
45447
+ id: "oauth-client-credentials",
45448
+ name: "OAuth (Client Credentials)",
45449
+ type: "oauth",
45450
+ flow: "client_credentials",
45451
+ description: "App-level authentication using client credentials. Create an API application in Ramp developer settings",
45452
+ requiredFields: ["clientId", "clientSecret"],
45453
+ defaults: {
45454
+ type: "oauth",
45455
+ flow: "client_credentials",
45456
+ tokenUrl: "https://api.ramp.com/developer/v1/token"
45457
+ }
45458
+ },
45459
+ {
45460
+ id: "oauth-user",
45461
+ name: "OAuth (User Authorization)",
45462
+ type: "oauth",
45463
+ flow: "authorization_code",
45464
+ description: "OAuth 2.0 authorization code flow for accessing Ramp on behalf of a user",
45465
+ requiredFields: ["clientId", "clientSecret", "redirectUri"],
45466
+ optionalFields: ["scope"],
45467
+ defaults: {
45468
+ type: "oauth",
45469
+ flow: "authorization_code",
45470
+ authorizationUrl: "https://app.ramp.com/v1/authorize",
45471
+ tokenUrl: "https://api.ramp.com/developer/v1/token"
45472
+ },
45473
+ scopes: [
45474
+ "transactions:read",
45475
+ "users:read",
45476
+ "users:write",
45477
+ "cards:read",
45478
+ "cards:write",
45479
+ "departments:read",
45480
+ "reimbursements:read"
45481
+ ]
45482
+ }
45483
+ ]
45484
+ };
45485
+
43968
45486
  // src/connectors/vendors/templates/aws.ts
43969
45487
  var awsTemplate = {
43970
45488
  id: "aws",
@@ -44017,7 +45535,16 @@ var dropboxTemplate = {
44017
45535
  tokenUrl: "https://api.dropboxapi.com/oauth2/token",
44018
45536
  usePKCE: true
44019
45537
  },
44020
- scopes: ["files.content.read", "files.content.write", "files.metadata.read"]
45538
+ scopes: ["files.content.read", "files.content.write", "files.metadata.read", "files.metadata.write", "sharing.read", "sharing.write", "account_info.read"],
45539
+ scopeDescriptions: {
45540
+ "files.content.read": "Read file contents",
45541
+ "files.content.write": "Upload and modify files",
45542
+ "files.metadata.read": "Read file and folder metadata",
45543
+ "files.metadata.write": "Modify file and folder metadata",
45544
+ "sharing.read": "View sharing settings",
45545
+ "sharing.write": "Manage sharing settings",
45546
+ "account_info.read": "Read account information"
45547
+ }
44021
45548
  }
44022
45549
  ]
44023
45550
  };
@@ -44045,6 +45572,13 @@ var boxTemplate = {
44045
45572
  flow: "authorization_code",
44046
45573
  authorizationUrl: "https://account.box.com/api/oauth2/authorize",
44047
45574
  tokenUrl: "https://api.box.com/oauth2/token"
45575
+ },
45576
+ scopes: ["root_readwrite", "manage_users", "manage_groups", "manage_enterprise"],
45577
+ scopeDescriptions: {
45578
+ "root_readwrite": "Read and write all files and folders",
45579
+ "manage_users": "Manage enterprise users",
45580
+ "manage_groups": "Manage enterprise groups",
45581
+ "manage_enterprise": "Manage enterprise settings"
44048
45582
  }
44049
45583
  },
44050
45584
  {
@@ -44221,6 +45755,11 @@ var pagerdutyTemplate = {
44221
45755
  flow: "authorization_code",
44222
45756
  authorizationUrl: "https://app.pagerduty.com/oauth/authorize",
44223
45757
  tokenUrl: "https://app.pagerduty.com/oauth/token"
45758
+ },
45759
+ scopes: ["read", "write"],
45760
+ scopeDescriptions: {
45761
+ "read": "Read incidents, services, and schedules",
45762
+ "write": "Create and update incidents and services"
44224
45763
  }
44225
45764
  }
44226
45765
  ]
@@ -44259,6 +45798,14 @@ var sentryTemplate = {
44259
45798
  flow: "authorization_code",
44260
45799
  authorizationUrl: "https://sentry.io/oauth/authorize/",
44261
45800
  tokenUrl: "https://sentry.io/oauth/token/"
45801
+ },
45802
+ scopes: ["project:read", "project:write", "event:read", "org:read", "member:read"],
45803
+ scopeDescriptions: {
45804
+ "project:read": "Read project settings",
45805
+ "project:write": "Manage project settings",
45806
+ "event:read": "Read error events and issues",
45807
+ "org:read": "Read organization info",
45808
+ "member:read": "Read org member info"
44262
45809
  }
44263
45810
  }
44264
45811
  ]
@@ -44456,7 +46003,13 @@ var zendeskTemplate = {
44456
46003
  authorizationUrl: "https://{subdomain}.zendesk.com/oauth/authorizations/new",
44457
46004
  tokenUrl: "https://{subdomain}.zendesk.com/oauth/tokens"
44458
46005
  },
44459
- scopes: ["read", "write", "tickets:read", "tickets:write"]
46006
+ scopes: ["read", "write", "tickets:read", "tickets:write"],
46007
+ scopeDescriptions: {
46008
+ "read": "Read all resources",
46009
+ "write": "Create and update resources",
46010
+ "tickets:read": "Read support tickets",
46011
+ "tickets:write": "Create and update tickets"
46012
+ }
44460
46013
  }
44461
46014
  ]
44462
46015
  };
@@ -44534,7 +46087,19 @@ var shopifyTemplate = {
44534
46087
  authorizationUrl: "https://{subdomain}.myshopify.com/admin/oauth/authorize",
44535
46088
  tokenUrl: "https://{subdomain}.myshopify.com/admin/oauth/access_token"
44536
46089
  },
44537
- scopes: ["read_products", "write_products", "read_orders", "write_orders"]
46090
+ scopes: ["read_products", "write_products", "read_orders", "write_orders", "read_customers", "write_customers", "read_inventory", "write_inventory", "read_fulfillments", "write_fulfillments"],
46091
+ scopeDescriptions: {
46092
+ "read_products": "Read products and collections",
46093
+ "write_products": "Create and update products",
46094
+ "read_orders": "Read orders and transactions",
46095
+ "write_orders": "Create and update orders",
46096
+ "read_customers": "Read customer information",
46097
+ "write_customers": "Create and update customers",
46098
+ "read_inventory": "Read inventory levels",
46099
+ "write_inventory": "Update inventory levels",
46100
+ "read_fulfillments": "Read fulfillment data",
46101
+ "write_fulfillments": "Create and update fulfillments"
46102
+ }
44538
46103
  }
44539
46104
  ]
44540
46105
  };
@@ -44567,6 +46132,8 @@ var allVendorTemplates = [
44567
46132
  // Payments
44568
46133
  stripeTemplate,
44569
46134
  paypalTemplate,
46135
+ quickbooksTemplate,
46136
+ rampTemplate,
44570
46137
  // Cloud
44571
46138
  awsTemplate,
44572
46139
  // Storage
@@ -44629,6 +46196,9 @@ var VENDOR_ICON_MAP = {
44629
46196
  // Payments
44630
46197
  stripe: "stripe",
44631
46198
  paypal: "paypal",
46199
+ quickbooks: "quickbooks",
46200
+ ramp: null,
46201
+ // No Simple Icon available
44632
46202
  // Email
44633
46203
  sendgrid: "sendgrid",
44634
46204
  mailchimp: "mailchimp",
@@ -44675,6 +46245,8 @@ var FALLBACK_PLACEHOLDERS = {
44675
46245
  // Email (trademark removed)
44676
46246
  sendgrid: { color: "#1A82E2", letter: "S" },
44677
46247
  postmark: { color: "#FFDE00", letter: "P" },
46248
+ // Payments (no Simple Icon available)
46249
+ ramp: { color: "#F2C94C", letter: "R" },
44678
46250
  // Search (no Simple Icon available)
44679
46251
  serper: { color: "#4A90A4", letter: "S" },
44680
46252
  tavily: { color: "#7C3AED", letter: "T" },
@@ -45454,13 +47026,30 @@ function extractNumber(text, patterns = [
45454
47026
  var tools_exports = {};
45455
47027
  __export(tools_exports, {
45456
47028
  ConnectorTools: () => ConnectorTools,
47029
+ DEFAULT_DESKTOP_CONFIG: () => DEFAULT_DESKTOP_CONFIG,
45457
47030
  DEFAULT_FILESYSTEM_CONFIG: () => DEFAULT_FILESYSTEM_CONFIG,
45458
47031
  DEFAULT_SHELL_CONFIG: () => DEFAULT_SHELL_CONFIG,
47032
+ DESKTOP_TOOL_NAMES: () => DESKTOP_TOOL_NAMES,
47033
+ DocumentReader: () => DocumentReader,
45459
47034
  FileMediaOutputHandler: () => FileMediaStorage,
47035
+ FormatDetector: () => FormatDetector,
47036
+ NutTreeDriver: () => NutTreeDriver,
45460
47037
  ToolRegistry: () => ToolRegistry,
47038
+ applyHumanDelay: () => applyHumanDelay,
45461
47039
  bash: () => bash,
45462
47040
  createBashTool: () => createBashTool,
45463
47041
  createCreatePRTool: () => createCreatePRTool,
47042
+ createDesktopGetCursorTool: () => createDesktopGetCursorTool,
47043
+ createDesktopGetScreenSizeTool: () => createDesktopGetScreenSizeTool,
47044
+ createDesktopKeyboardKeyTool: () => createDesktopKeyboardKeyTool,
47045
+ createDesktopKeyboardTypeTool: () => createDesktopKeyboardTypeTool,
47046
+ createDesktopMouseClickTool: () => createDesktopMouseClickTool,
47047
+ createDesktopMouseDragTool: () => createDesktopMouseDragTool,
47048
+ createDesktopMouseMoveTool: () => createDesktopMouseMoveTool,
47049
+ createDesktopMouseScrollTool: () => createDesktopMouseScrollTool,
47050
+ createDesktopScreenshotTool: () => createDesktopScreenshotTool,
47051
+ createDesktopWindowFocusTool: () => createDesktopWindowFocusTool,
47052
+ createDesktopWindowListTool: () => createDesktopWindowListTool,
45464
47053
  createEditFileTool: () => createEditFileTool,
45465
47054
  createExecuteJavaScriptTool: () => createExecuteJavaScriptTool,
45466
47055
  createGetPRTool: () => createGetPRTool,
@@ -45480,12 +47069,25 @@ __export(tools_exports, {
45480
47069
  createWebScrapeTool: () => createWebScrapeTool,
45481
47070
  createWebSearchTool: () => createWebSearchTool,
45482
47071
  createWriteFileTool: () => createWriteFileTool,
47072
+ desktopGetCursor: () => desktopGetCursor,
47073
+ desktopGetScreenSize: () => desktopGetScreenSize,
47074
+ desktopKeyboardKey: () => desktopKeyboardKey,
47075
+ desktopKeyboardType: () => desktopKeyboardType,
47076
+ desktopMouseClick: () => desktopMouseClick,
47077
+ desktopMouseDrag: () => desktopMouseDrag,
47078
+ desktopMouseMove: () => desktopMouseMove,
47079
+ desktopMouseScroll: () => desktopMouseScroll,
47080
+ desktopScreenshot: () => desktopScreenshot,
47081
+ desktopTools: () => desktopTools,
47082
+ desktopWindowFocus: () => desktopWindowFocus,
47083
+ desktopWindowList: () => desktopWindowList,
45483
47084
  developerTools: () => developerTools,
45484
47085
  editFile: () => editFile,
45485
47086
  executeJavaScript: () => executeJavaScript,
45486
47087
  expandTilde: () => expandTilde,
45487
47088
  getAllBuiltInTools: () => getAllBuiltInTools,
45488
47089
  getBackgroundOutput: () => getBackgroundOutput,
47090
+ getDesktopDriver: () => getDesktopDriver,
45489
47091
  getMediaOutputHandler: () => getMediaOutputHandler,
45490
47092
  getMediaStorage: () => getMediaStorage,
45491
47093
  getToolByName: () => getToolByName,
@@ -45500,8 +47102,11 @@ __export(tools_exports, {
45500
47102
  jsonManipulator: () => jsonManipulator,
45501
47103
  killBackgroundProcess: () => killBackgroundProcess,
45502
47104
  listDirectory: () => listDirectory,
47105
+ mergeTextPieces: () => mergeTextPieces,
47106
+ parseKeyCombo: () => parseKeyCombo,
45503
47107
  parseRepository: () => parseRepository,
45504
47108
  readFile: () => readFile5,
47109
+ resetDefaultDriver: () => resetDefaultDriver,
45505
47110
  resolveRepository: () => resolveRepository,
45506
47111
  setMediaOutputHandler: () => setMediaOutputHandler,
45507
47112
  setMediaStorage: () => setMediaStorage,
@@ -45547,13 +47152,11 @@ var DEFAULT_FILESYSTEM_CONFIG = {
45547
47152
  ".avi",
45548
47153
  ".mov",
45549
47154
  ".mkv",
45550
- ".pdf",
47155
+ // Note: .pdf, .docx, .xlsx, .pptx are NOT excluded — DocumentReader handles them
45551
47156
  ".doc",
45552
- ".docx",
45553
47157
  ".xls",
45554
- ".xlsx",
45555
47158
  ".ppt",
45556
- ".pptx",
47159
+ // Legacy Office formats not yet supported
45557
47160
  ".woff",
45558
47161
  ".woff2",
45559
47162
  ".ttf",
@@ -45561,6 +47164,9 @@ var DEFAULT_FILESYSTEM_CONFIG = {
45561
47164
  ".otf"
45562
47165
  ]
45563
47166
  };
47167
+ function toForwardSlash(p) {
47168
+ return sep === "\\" ? p.replace(/\\/g, "/") : p;
47169
+ }
45564
47170
  function validatePath(inputPath, config = {}) {
45565
47171
  const workingDir = config.workingDirectory || process.cwd();
45566
47172
  const allowedDirs = config.allowedDirectories || [];
@@ -45577,7 +47183,8 @@ function validatePath(inputPath, config = {}) {
45577
47183
  } else {
45578
47184
  resolvedPath = resolve(workingDir, expandedPath);
45579
47185
  }
45580
- const pathSegments = resolvedPath.split("/").filter(Boolean);
47186
+ const normalizedResolved = toForwardSlash(resolvedPath);
47187
+ const pathSegments = normalizedResolved.split("/").filter(Boolean);
45581
47188
  for (const blocked of blockedDirs) {
45582
47189
  if (!blocked.includes("/")) {
45583
47190
  if (pathSegments.includes(blocked)) {
@@ -45588,8 +47195,8 @@ function validatePath(inputPath, config = {}) {
45588
47195
  };
45589
47196
  }
45590
47197
  } else {
45591
- const blockedPath = isAbsolute(blocked) ? blocked : resolve(workingDir, blocked);
45592
- if (resolvedPath.startsWith(blockedPath + "/") || resolvedPath === blockedPath) {
47198
+ const blockedPath = toForwardSlash(isAbsolute(blocked) ? blocked : resolve(workingDir, blocked));
47199
+ if (normalizedResolved.startsWith(blockedPath + "/") || normalizedResolved === blockedPath) {
45593
47200
  return {
45594
47201
  valid: false,
45595
47202
  resolvedPath,
@@ -45601,8 +47208,8 @@ function validatePath(inputPath, config = {}) {
45601
47208
  if (allowedDirs.length > 0) {
45602
47209
  let isAllowed = false;
45603
47210
  for (const allowed of allowedDirs) {
45604
- const allowedPath = isAbsolute(allowed) ? allowed : resolve(workingDir, allowed);
45605
- if (resolvedPath.startsWith(allowedPath + "/") || resolvedPath === allowedPath) {
47211
+ const allowedPath = toForwardSlash(isAbsolute(allowed) ? allowed : resolve(workingDir, allowed));
47212
+ if (normalizedResolved.startsWith(allowedPath + "/") || normalizedResolved === allowedPath) {
45606
47213
  isAllowed = true;
45607
47214
  break;
45608
47215
  }
@@ -45636,7 +47243,7 @@ function createReadFileTool(config = {}) {
45636
47243
  type: "function",
45637
47244
  function: {
45638
47245
  name: "read_file",
45639
- description: `Read content from a file on the local filesystem.
47246
+ description: `Read content from a file on the local filesystem. Supports text files AND binary document formats \u2014 PDF, DOCX, PPTX, XLSX, ODS, ODT, ODP, and images (PNG, JPG, GIF, WEBP) are automatically converted to markdown text.
45640
47247
 
45641
47248
  USAGE:
45642
47249
  - The file_path parameter must be an absolute path, not a relative path
@@ -45645,20 +47252,34 @@ USAGE:
45645
47252
  - Any lines longer than 2000 characters will be truncated
45646
47253
  - Results are returned with line numbers starting at 1
45647
47254
 
47255
+ DOCUMENT SUPPORT:
47256
+ - PDF files: extracted as markdown text with per-page sections
47257
+ - Word documents (.docx): converted to markdown preserving headings, lists, tables
47258
+ - PowerPoint (.pptx): extracted slide-by-slide as markdown
47259
+ - Excel (.xlsx) / CSV / ODS: tables converted to markdown tables
47260
+ - OpenDocument (.odt, .odp, .ods): converted like their MS Office equivalents
47261
+ - Images (.png, .jpg, .gif, .webp): described as image metadata
47262
+ - Binary documents are auto-detected by extension \u2014 just pass the file path
47263
+
45648
47264
  WHEN TO USE:
45649
47265
  - To read source code files before making edits
45650
47266
  - To understand file contents and structure
45651
47267
  - To read configuration files
45652
47268
  - To examine log files or data files
47269
+ - To read PDF, Word, Excel, PowerPoint, or other document files as text
45653
47270
 
45654
47271
  IMPORTANT:
45655
47272
  - Always read a file before attempting to edit it
45656
47273
  - Use offset/limit for very large files to read in chunks
45657
47274
  - The tool will return an error if the file doesn't exist
47275
+ - offset/limit are ignored for binary document formats (full document is always returned)
45658
47276
 
45659
47277
  EXAMPLES:
45660
47278
  - Read entire file: { "file_path": "/path/to/file.ts" }
45661
- - Read lines 100-200: { "file_path": "/path/to/file.ts", "offset": 100, "limit": 100 }`,
47279
+ - Read lines 100-200: { "file_path": "/path/to/file.ts", "offset": 100, "limit": 100 }
47280
+ - Read a PDF: { "file_path": "/path/to/report.pdf" }
47281
+ - Read an Excel file: { "file_path": "/path/to/data.xlsx" }
47282
+ - Read a Word doc: { "file_path": "/path/to/document.docx" }`,
45662
47283
  parameters: {
45663
47284
  type: "object",
45664
47285
  properties: {
@@ -45720,6 +47341,32 @@ EXAMPLES:
45720
47341
  size: stats.size
45721
47342
  };
45722
47343
  }
47344
+ const ext = extname(resolvedPath).toLowerCase();
47345
+ if (FormatDetector.isBinaryDocumentFormat(ext)) {
47346
+ try {
47347
+ const reader = DocumentReader.create(mergedConfig.documentReaderConfig);
47348
+ const result2 = await reader.read(
47349
+ { type: "file", path: resolvedPath },
47350
+ {
47351
+ extractImages: false,
47352
+ ...mergedConfig.documentReaderConfig?.defaults
47353
+ }
47354
+ );
47355
+ if (result2.success) {
47356
+ const content2 = mergeTextPieces(result2.pieces);
47357
+ return {
47358
+ success: true,
47359
+ content: content2,
47360
+ lines: content2.split("\n").length,
47361
+ truncated: false,
47362
+ encoding: "document",
47363
+ size: stats.size,
47364
+ path: file_path
47365
+ };
47366
+ }
47367
+ } catch {
47368
+ }
47369
+ }
45723
47370
  const content = await readFile(resolvedPath, "utf-8");
45724
47371
  const allLines = content.split("\n");
45725
47372
  const totalLines = allLines.length;
@@ -46041,7 +47688,7 @@ async function findFiles(dir, pattern, baseDir, config, results = [], depth = 0)
46041
47688
  for (const entry of entries) {
46042
47689
  if (results.length >= config.maxResults) break;
46043
47690
  const fullPath = join(dir, entry.name);
46044
- const relativePath = relative(baseDir, fullPath);
47691
+ const relativePath = toForwardSlash(relative(baseDir, fullPath));
46045
47692
  if (entry.isDirectory()) {
46046
47693
  const isBlocked = config.blockedDirectories.some(
46047
47694
  (blocked) => entry.name === blocked || relativePath.includes(`/${blocked}/`) || relativePath.startsWith(`${blocked}/`)
@@ -46404,7 +48051,7 @@ WHEN TO USE:
46404
48051
  );
46405
48052
  if (matches.length > 0) {
46406
48053
  filesMatched++;
46407
- const relativePath = relative(resolvedPath, file) || file;
48054
+ const relativePath = toForwardSlash(relative(resolvedPath, file)) || file;
46408
48055
  for (const match of matches) {
46409
48056
  match.file = relativePath;
46410
48057
  }
@@ -46470,7 +48117,7 @@ async function listDir(dir, baseDir, config, recursive, filter, maxDepth = 3, cu
46470
48117
  for (const entry of dirEntries) {
46471
48118
  if (entries.length >= config.maxResults) break;
46472
48119
  const fullPath = join(dir, entry.name);
46473
- const relativePath = relative(baseDir, fullPath);
48120
+ const relativePath = toForwardSlash(relative(baseDir, fullPath));
46474
48121
  if (entry.isDirectory() && config.blockedDirectories.includes(entry.name)) {
46475
48122
  continue;
46476
48123
  }
@@ -46685,6 +48332,8 @@ function createBashTool(config = {}) {
46685
48332
  name: "bash",
46686
48333
  description: `Execute shell commands with optional timeout.
46687
48334
 
48335
+ SHELL: This tool uses ${mergedConfig.shell}${process.platform === "win32" ? " (Windows). Use Windows command syntax (dir, type, del, etc.), NOT Unix commands (ls, cat, rm, etc.). Use \\ as path separator or quote paths with forward slashes." : " (Unix). Use standard Unix command syntax."}
48336
+
46688
48337
  USAGE:
46689
48338
  - Execute any shell command
46690
48339
  - Working directory persists between commands
@@ -46701,9 +48350,11 @@ For file operations, prefer dedicated tools:
46701
48350
 
46702
48351
  BEST PRACTICES:
46703
48352
  - Always quote file paths with spaces: cd "/path with spaces"
46704
- - Use absolute paths when possible
48353
+ - Use absolute paths when possible${process.platform === "win32" ? `
46705
48354
  - Chain dependent commands with &&: git add . && git commit -m "msg"
46706
- - Use ; only when you don't care if earlier commands fail
48355
+ - Use PowerShell syntax if cmd.exe is insufficient` : `
48356
+ - Chain dependent commands with &&: git add . && git commit -m "msg"
48357
+ - Use ; only when you don't care if earlier commands fail`}
46707
48358
  - Avoid interactive commands (no -i flags)
46708
48359
 
46709
48360
  GIT SAFETY:
@@ -47420,92 +49071,30 @@ function detectContentQuality(html, text, $) {
47420
49071
  issues
47421
49072
  };
47422
49073
  }
47423
- var JSDOM = null;
47424
- async function getJSDOM() {
47425
- if (!JSDOM) {
47426
- const jsdom = await import('jsdom');
47427
- JSDOM = jsdom.JSDOM;
47428
- }
47429
- return JSDOM;
47430
- }
47431
- async function htmlToMarkdown(html, url2, maxLength = 5e4) {
47432
- const JSDOMClass = await getJSDOM();
47433
- const dom = new JSDOMClass(html, { url: url2 });
47434
- const document = dom.window.document;
47435
- let title = document.title || "";
47436
- let byline;
47437
- let excerpt;
47438
- let contentHtml = html;
47439
- let wasReadabilityUsed = false;
47440
- try {
47441
- const clonedDoc = document.cloneNode(true);
47442
- const reader = new Readability(clonedDoc);
47443
- const article = reader.parse();
47444
- if (article && article.content && article.content.length > 100) {
47445
- contentHtml = article.content;
47446
- title = article.title || title;
47447
- byline = article.byline || void 0;
47448
- excerpt = article.excerpt || void 0;
47449
- wasReadabilityUsed = true;
47450
- }
47451
- } catch {
47452
- }
47453
- const turndown = new TurndownService({
47454
- headingStyle: "atx",
47455
- codeBlockStyle: "fenced",
47456
- bulletListMarker: "-",
47457
- emDelimiter: "_"
47458
- });
47459
- turndown.remove(["script", "style", "nav", "footer", "aside", "iframe", "noscript"]);
47460
- turndown.addRule("pre", {
47461
- filter: ["pre"],
47462
- replacement: (content, node) => {
47463
- const element = node;
47464
- const code = element.querySelector?.("code");
47465
- const lang = code?.className?.match(/language-(\w+)/)?.[1] || "";
47466
- const text = code?.textContent || content;
47467
- return `
47468
- \`\`\`${lang}
47469
- ${text}
47470
- \`\`\`
47471
- `;
47472
- }
47473
- });
47474
- let markdown = turndown.turndown(contentHtml);
47475
- markdown = markdown.replace(/\n{3,}/g, "\n\n").replace(/^\s+|\s+$/g, "").replace(/[ \t]+$/gm, "");
47476
- let wasTruncated = false;
47477
- if (markdown.length > maxLength) {
47478
- const truncateAt = markdown.lastIndexOf("\n\n", maxLength);
47479
- if (truncateAt > maxLength * 0.5) {
47480
- markdown = markdown.slice(0, truncateAt) + "\n\n...[content truncated]";
47481
- } else {
47482
- markdown = markdown.slice(0, maxLength) + "...[truncated]";
47483
- }
47484
- wasTruncated = true;
47485
- }
47486
- return {
47487
- markdown,
47488
- title,
47489
- byline,
47490
- excerpt,
47491
- wasReadabilityUsed,
47492
- wasTruncated
47493
- };
47494
- }
47495
49074
 
47496
49075
  // src/tools/web/webFetch.ts
49076
+ init_htmlToMarkdown();
47497
49077
  var webFetch = {
47498
49078
  definition: {
47499
49079
  type: "function",
47500
49080
  function: {
47501
49081
  name: "web_fetch",
47502
- description: `Fetch and extract text content from a web page URL.
49082
+ description: `Fetch and extract content from a URL \u2014 works with web pages AND document files (PDF, DOCX, XLSX, PPTX, etc.). Document URLs are automatically detected and converted to markdown text.
47503
49083
 
47504
- IMPORTANT: This tool performs a simple HTTP fetch and HTML parsing. It works well for:
49084
+ WEB PAGES:
49085
+ This tool performs HTTP fetch and HTML parsing. It works well for:
47505
49086
  - Static websites (blogs, documentation, articles)
47506
49087
  - Server-rendered HTML pages
47507
49088
  - Content that doesn't require JavaScript
47508
49089
 
49090
+ DOCUMENT URLs:
49091
+ When the URL points to a document file (detected via Content-Type header or URL extension), the document is automatically downloaded and converted to markdown:
49092
+ - PDF files: extracted as markdown with per-page sections
49093
+ - Word (.docx), PowerPoint (.pptx): converted to structured markdown
49094
+ - Excel (.xlsx), CSV, ODS: tables converted to markdown tables
49095
+ - OpenDocument formats (.odt, .odp, .ods): converted like MS Office equivalents
49096
+ - Returns contentType: "document" and includes documentMetadata in the result
49097
+
47509
49098
  LIMITATIONS:
47510
49099
  - Cannot execute JavaScript
47511
49100
  - May fail on React/Vue/Angular sites (will return low quality score)
@@ -47525,8 +49114,8 @@ RETURNS:
47525
49114
  success: boolean,
47526
49115
  url: string,
47527
49116
  title: string,
47528
- content: string, // Clean markdown (converted from HTML via Readability + Turndown)
47529
- contentType: string, // 'html' | 'json' | 'text' | 'error'
49117
+ content: string, // Clean markdown (converted from HTML or document)
49118
+ contentType: string, // 'html' | 'json' | 'text' | 'document' | 'error'
47530
49119
  qualityScore: number, // 0-100 (quality of extraction)
47531
49120
  requiresJS: boolean, // True if site likely needs JavaScript
47532
49121
  suggestedAction: string, // Suggestion if quality is low
@@ -47534,20 +49123,24 @@ RETURNS:
47534
49123
  excerpt: string, // Short summary excerpt (if extracted)
47535
49124
  byline: string, // Author info (if extracted)
47536
49125
  wasTruncated: boolean, // True if content was truncated
49126
+ documentMetadata: object, // Document metadata (format, pages, etc.) \u2014 only for document URLs
47537
49127
  error: string // Error message if failed
47538
49128
  }
47539
49129
 
47540
- EXAMPLE:
47541
- To fetch a blog post:
49130
+ EXAMPLES:
49131
+ Fetch a blog post:
47542
49132
  {
47543
49133
  url: "https://example.com/blog/article"
47544
49134
  }
47545
49135
 
47546
- With custom user agent:
49136
+ Fetch a PDF document:
49137
+ {
49138
+ url: "https://example.com/reports/q4-2025.pdf"
49139
+ }
49140
+
49141
+ Fetch an Excel spreadsheet:
47547
49142
  {
47548
- url: "https://example.com/page",
47549
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
47550
- timeout: 15000
49143
+ url: "https://example.com/data/metrics.xlsx"
47551
49144
  }`,
47552
49145
  parameters: {
47553
49146
  type: "object",
@@ -47611,6 +49204,51 @@ With custom user agent:
47611
49204
  };
47612
49205
  }
47613
49206
  const contentType = response.headers.get("content-type") || "";
49207
+ const urlExt = (() => {
49208
+ try {
49209
+ const pathname = new URL(args.url).pathname;
49210
+ const ext = pathname.split(".").pop()?.toLowerCase();
49211
+ return ext ? `.${ext}` : "";
49212
+ } catch {
49213
+ return "";
49214
+ }
49215
+ })();
49216
+ if (FormatDetector.isDocumentMimeType(contentType) || FormatDetector.isBinaryDocumentFormat(urlExt)) {
49217
+ try {
49218
+ const arrayBuffer = await response.arrayBuffer();
49219
+ const buffer = Buffer.from(arrayBuffer);
49220
+ const disposition = response.headers.get("content-disposition");
49221
+ let filename = "document";
49222
+ if (disposition) {
49223
+ const match = disposition.match(/filename[^;=\n]*=(['"]?)([^'"\n;]*)\1/);
49224
+ if (match?.[2]) filename = match[2];
49225
+ } else {
49226
+ try {
49227
+ const basename = new URL(args.url).pathname.split("/").pop();
49228
+ if (basename && basename.includes(".")) filename = basename;
49229
+ } catch {
49230
+ }
49231
+ }
49232
+ const reader = DocumentReader.create();
49233
+ const result = await reader.read(
49234
+ { type: "buffer", buffer, filename },
49235
+ { extractImages: false }
49236
+ );
49237
+ if (result.success) {
49238
+ return {
49239
+ success: true,
49240
+ url: args.url,
49241
+ title: `Document: ${filename}`,
49242
+ content: mergeTextPieces(result.pieces),
49243
+ contentType: "document",
49244
+ qualityScore: 100,
49245
+ requiresJS: false,
49246
+ documentMetadata: result.metadata
49247
+ };
49248
+ }
49249
+ } catch {
49250
+ }
49251
+ }
47614
49252
  if (contentType.includes("application/json")) {
47615
49253
  const json = await response.json();
47616
49254
  return {
@@ -47877,6 +49515,10 @@ For JS-heavy sites:
47877
49515
  const api = await tryAPI(args, startTime, attemptedMethods);
47878
49516
  if (api.success) return api;
47879
49517
  if (native.success) return native;
49518
+ const errors = [];
49519
+ if (native.error) errors.push(`native: ${native.error}`);
49520
+ if (api.error) errors.push(`api(${connector.name}): ${api.error}`);
49521
+ const detail = errors.length > 0 ? errors.join(" | ") : "Unknown failure";
47880
49522
  return {
47881
49523
  success: false,
47882
49524
  url: args.url,
@@ -47885,7 +49527,7 @@ For JS-heavy sites:
47885
49527
  content: "",
47886
49528
  durationMs: Date.now() - startTime,
47887
49529
  attemptedMethods,
47888
- error: "All scraping methods failed. Site may have bot protection."
49530
+ error: `All scraping methods failed. ${detail}`
47889
49531
  };
47890
49532
  },
47891
49533
  describeCall: (args) => args.url
@@ -49549,6 +51191,819 @@ function registerGitHubTools() {
49549
51191
  // src/tools/github/index.ts
49550
51192
  registerGitHubTools();
49551
51193
 
51194
+ // src/tools/desktop/types.ts
51195
+ var DEFAULT_DESKTOP_CONFIG = {
51196
+ driver: null,
51197
+ // Lazy-initialized
51198
+ humanDelay: [50, 150],
51199
+ humanizeMovement: false
51200
+ };
51201
+ async function applyHumanDelay(config) {
51202
+ const [min, max] = config.humanDelay ?? DEFAULT_DESKTOP_CONFIG.humanDelay;
51203
+ if (min === 0 && max === 0) return;
51204
+ const delay = min + Math.random() * (max - min);
51205
+ await new Promise((resolve4) => setTimeout(resolve4, delay));
51206
+ }
51207
+ var DESKTOP_TOOL_NAMES = [
51208
+ "desktop_screenshot",
51209
+ "desktop_mouse_move",
51210
+ "desktop_mouse_click",
51211
+ "desktop_mouse_drag",
51212
+ "desktop_mouse_scroll",
51213
+ "desktop_get_cursor",
51214
+ "desktop_keyboard_type",
51215
+ "desktop_keyboard_key",
51216
+ "desktop_get_screen_size",
51217
+ "desktop_window_list",
51218
+ "desktop_window_focus"
51219
+ ];
51220
+
51221
+ // src/tools/desktop/driver/NutTreeDriver.ts
51222
+ var KEY_MAP = {
51223
+ // Modifiers
51224
+ ctrl: "LeftControl",
51225
+ control: "LeftControl",
51226
+ cmd: "LeftCmd",
51227
+ command: "LeftCmd",
51228
+ meta: "LeftCmd",
51229
+ super: "LeftCmd",
51230
+ alt: "LeftAlt",
51231
+ option: "LeftAlt",
51232
+ shift: "LeftShift",
51233
+ // Navigation
51234
+ enter: "Return",
51235
+ return: "Return",
51236
+ tab: "Tab",
51237
+ escape: "Escape",
51238
+ esc: "Escape",
51239
+ backspace: "Backspace",
51240
+ delete: "Delete",
51241
+ space: "Space",
51242
+ // Arrow keys
51243
+ up: "Up",
51244
+ down: "Down",
51245
+ left: "Left",
51246
+ right: "Right",
51247
+ // Function keys
51248
+ f1: "F1",
51249
+ f2: "F2",
51250
+ f3: "F3",
51251
+ f4: "F4",
51252
+ f5: "F5",
51253
+ f6: "F6",
51254
+ f7: "F7",
51255
+ f8: "F8",
51256
+ f9: "F9",
51257
+ f10: "F10",
51258
+ f11: "F11",
51259
+ f12: "F12",
51260
+ // Other
51261
+ home: "Home",
51262
+ end: "End",
51263
+ pageup: "PageUp",
51264
+ pagedown: "PageDown",
51265
+ insert: "Insert",
51266
+ printscreen: "Print",
51267
+ capslock: "CapsLock",
51268
+ numlock: "NumLock",
51269
+ scrolllock: "ScrollLock"
51270
+ };
51271
+ function parseKeyCombo(keys, KeyEnum) {
51272
+ const parts = keys.toLowerCase().split("+").map((k) => k.trim());
51273
+ const result = [];
51274
+ for (const part of parts) {
51275
+ const mapped = KEY_MAP[part];
51276
+ if (mapped && KeyEnum[mapped] !== void 0) {
51277
+ result.push(KeyEnum[mapped]);
51278
+ continue;
51279
+ }
51280
+ if (part.length === 1) {
51281
+ const upper = part.toUpperCase();
51282
+ if (KeyEnum[upper] !== void 0) {
51283
+ result.push(KeyEnum[upper]);
51284
+ continue;
51285
+ }
51286
+ }
51287
+ const pascal = part.charAt(0).toUpperCase() + part.slice(1);
51288
+ if (KeyEnum[pascal] !== void 0) {
51289
+ result.push(KeyEnum[pascal]);
51290
+ continue;
51291
+ }
51292
+ if (KeyEnum[part] !== void 0) {
51293
+ result.push(KeyEnum[part]);
51294
+ continue;
51295
+ }
51296
+ throw new Error(`Unknown key: "${part}". Available modifiers: ctrl, cmd, alt, shift. Common keys: enter, tab, escape, space, up, down, left, right, f1-f12, a-z, 0-9`);
51297
+ }
51298
+ return result;
51299
+ }
51300
+ async function encodeRGBAToPNG(data, width, height) {
51301
+ const { PNG } = await import('pngjs');
51302
+ const png = new PNG({ width, height });
51303
+ const sourceBuffer = Buffer.isBuffer(data) ? data : Buffer.from(data);
51304
+ sourceBuffer.copy(png.data, 0, 0, width * height * 4);
51305
+ return PNG.sync.write(png);
51306
+ }
51307
+ var NutTreeDriver = class {
51308
+ _isInitialized = false;
51309
+ _scaleFactor = 1;
51310
+ // Lazy-loaded nut-tree modules
51311
+ _nut = null;
51312
+ // Cache of Window objects keyed by windowHandle, populated by getWindowList()
51313
+ _windowCache = /* @__PURE__ */ new Map();
51314
+ get isInitialized() {
51315
+ return this._isInitialized;
51316
+ }
51317
+ get scaleFactor() {
51318
+ return this._scaleFactor;
51319
+ }
51320
+ async initialize() {
51321
+ if (this._isInitialized) return;
51322
+ try {
51323
+ this._nut = await import('@nut-tree-fork/nut-js');
51324
+ } catch {
51325
+ throw new Error(
51326
+ "@nut-tree-fork/nut-js is not installed. Install it to use desktop automation tools:\n npm install @nut-tree-fork/nut-js"
51327
+ );
51328
+ }
51329
+ try {
51330
+ const { mouse, keyboard } = this._nut;
51331
+ if (mouse.config) {
51332
+ mouse.config.mouseSpeed = 1e4;
51333
+ mouse.config.autoDelayMs = 0;
51334
+ }
51335
+ if (keyboard.config) {
51336
+ keyboard.config.autoDelayMs = 0;
51337
+ }
51338
+ } catch {
51339
+ }
51340
+ try {
51341
+ const { screen } = this._nut;
51342
+ const logicalWidth = await screen.width();
51343
+ const screenshotImage = await screen.grab();
51344
+ const physicalWidth = screenshotImage.width;
51345
+ this._scaleFactor = physicalWidth / logicalWidth;
51346
+ } catch (err) {
51347
+ if (err.message?.includes("permission") || err.message?.includes("accessibility")) {
51348
+ throw new Error(
51349
+ "Desktop automation requires accessibility permissions.\nOn macOS: System Settings \u2192 Privacy & Security \u2192 Accessibility \u2192 Enable your terminal app."
51350
+ );
51351
+ }
51352
+ this._scaleFactor = 1;
51353
+ }
51354
+ this._isInitialized = true;
51355
+ }
51356
+ assertInitialized() {
51357
+ if (!this._isInitialized) {
51358
+ throw new Error("NutTreeDriver not initialized. Call initialize() first.");
51359
+ }
51360
+ }
51361
+ /** Convert physical (screenshot) coords to logical (OS) coords */
51362
+ toLogical(x, y) {
51363
+ return {
51364
+ x: Math.round(x / this._scaleFactor),
51365
+ y: Math.round(y / this._scaleFactor)
51366
+ };
51367
+ }
51368
+ /** Convert logical (OS) coords to physical (screenshot) coords */
51369
+ toPhysical(x, y) {
51370
+ return {
51371
+ x: Math.round(x * this._scaleFactor),
51372
+ y: Math.round(y * this._scaleFactor)
51373
+ };
51374
+ }
51375
+ // ===== Screen =====
51376
+ async screenshot(region) {
51377
+ this.assertInitialized();
51378
+ const { screen } = this._nut;
51379
+ let image;
51380
+ if (region) {
51381
+ const { Region } = this._nut;
51382
+ const logTopLeft = this.toLogical(region.x, region.y);
51383
+ const logicalWidth = Math.round(region.width / this._scaleFactor);
51384
+ const logicalHeight = Math.round(region.height / this._scaleFactor);
51385
+ const nutRegion = new Region(logTopLeft.x, logTopLeft.y, logicalWidth, logicalHeight);
51386
+ image = await screen.grabRegion(nutRegion);
51387
+ } else {
51388
+ image = await screen.grab();
51389
+ }
51390
+ const pngBuffer = await encodeRGBAToPNG(image.data, image.width, image.height);
51391
+ const base64 = pngBuffer.toString("base64");
51392
+ return {
51393
+ base64,
51394
+ width: image.width,
51395
+ height: image.height
51396
+ };
51397
+ }
51398
+ async getScreenSize() {
51399
+ this.assertInitialized();
51400
+ const { screen } = this._nut;
51401
+ const logicalWidth = await screen.width();
51402
+ const logicalHeight = await screen.height();
51403
+ return {
51404
+ physicalWidth: Math.round(logicalWidth * this._scaleFactor),
51405
+ physicalHeight: Math.round(logicalHeight * this._scaleFactor),
51406
+ logicalWidth,
51407
+ logicalHeight,
51408
+ scaleFactor: this._scaleFactor
51409
+ };
51410
+ }
51411
+ // ===== Mouse =====
51412
+ async mouseMove(x, y) {
51413
+ this.assertInitialized();
51414
+ const { mouse, straightTo, Point } = this._nut;
51415
+ const logical = this.toLogical(x, y);
51416
+ await mouse.move(straightTo(new Point(logical.x, logical.y)));
51417
+ }
51418
+ async mouseClick(x, y, button, clickCount) {
51419
+ this.assertInitialized();
51420
+ const { mouse, straightTo, Point, Button } = this._nut;
51421
+ const nutButton = button === "right" ? Button.RIGHT : button === "middle" ? Button.MIDDLE : Button.LEFT;
51422
+ const logical = this.toLogical(x, y);
51423
+ await mouse.move(straightTo(new Point(logical.x, logical.y)));
51424
+ for (let i = 0; i < clickCount; i++) {
51425
+ await mouse.click(nutButton);
51426
+ }
51427
+ }
51428
+ async mouseDrag(startX, startY, endX, endY, button) {
51429
+ this.assertInitialized();
51430
+ const { mouse, straightTo, Point, Button } = this._nut;
51431
+ const nutButton = button === "right" ? Button.RIGHT : button === "middle" ? Button.MIDDLE : Button.LEFT;
51432
+ const logicalStart = this.toLogical(startX, startY);
51433
+ const logicalEnd = this.toLogical(endX, endY);
51434
+ await mouse.move(straightTo(new Point(logicalStart.x, logicalStart.y)));
51435
+ await mouse.pressButton(nutButton);
51436
+ await mouse.move(straightTo(new Point(logicalEnd.x, logicalEnd.y)));
51437
+ await mouse.releaseButton(nutButton);
51438
+ }
51439
+ async mouseScroll(deltaX, deltaY, x, y) {
51440
+ this.assertInitialized();
51441
+ const { mouse, straightTo, Point } = this._nut;
51442
+ if (x !== void 0 && y !== void 0) {
51443
+ const logical = this.toLogical(x, y);
51444
+ await mouse.move(straightTo(new Point(logical.x, logical.y)));
51445
+ }
51446
+ if (deltaY !== 0) {
51447
+ if (deltaY > 0) {
51448
+ await mouse.scrollDown(Math.abs(deltaY));
51449
+ } else {
51450
+ await mouse.scrollUp(Math.abs(deltaY));
51451
+ }
51452
+ }
51453
+ if (deltaX !== 0) {
51454
+ if (deltaX > 0) {
51455
+ await mouse.scrollRight(Math.abs(deltaX));
51456
+ } else {
51457
+ await mouse.scrollLeft(Math.abs(deltaX));
51458
+ }
51459
+ }
51460
+ }
51461
+ async getCursorPosition() {
51462
+ this.assertInitialized();
51463
+ const { mouse } = this._nut;
51464
+ const pos = await mouse.getPosition();
51465
+ return this.toPhysical(pos.x, pos.y);
51466
+ }
51467
+ // ===== Keyboard =====
51468
+ async keyboardType(text, delay) {
51469
+ this.assertInitialized();
51470
+ const { keyboard } = this._nut;
51471
+ const prevDelay = keyboard.config.autoDelayMs;
51472
+ if (delay !== void 0) {
51473
+ keyboard.config.autoDelayMs = delay;
51474
+ }
51475
+ try {
51476
+ await keyboard.type(text);
51477
+ } finally {
51478
+ if (delay !== void 0) {
51479
+ keyboard.config.autoDelayMs = prevDelay;
51480
+ }
51481
+ }
51482
+ }
51483
+ async keyboardKey(keys) {
51484
+ this.assertInitialized();
51485
+ const { keyboard, Key } = this._nut;
51486
+ const parsedKeys = parseKeyCombo(keys, Key);
51487
+ if (parsedKeys.length === 1) {
51488
+ await keyboard.pressKey(parsedKeys[0]);
51489
+ await keyboard.releaseKey(parsedKeys[0]);
51490
+ } else {
51491
+ for (const key of parsedKeys) {
51492
+ await keyboard.pressKey(key);
51493
+ }
51494
+ for (const key of [...parsedKeys].reverse()) {
51495
+ await keyboard.releaseKey(key);
51496
+ }
51497
+ }
51498
+ }
51499
+ // ===== Windows =====
51500
+ async getWindowList() {
51501
+ this.assertInitialized();
51502
+ const { getWindows } = this._nut;
51503
+ try {
51504
+ const windows = await getWindows();
51505
+ const result = [];
51506
+ this._windowCache.clear();
51507
+ for (const win of windows) {
51508
+ try {
51509
+ const handle = win.windowHandle;
51510
+ if (handle === void 0 || handle === null) continue;
51511
+ const title = await win.title;
51512
+ const region = await win.region;
51513
+ this._windowCache.set(handle, win);
51514
+ result.push({
51515
+ id: handle,
51516
+ title: title || "",
51517
+ bounds: region ? {
51518
+ x: Math.round(region.left * this._scaleFactor),
51519
+ y: Math.round(region.top * this._scaleFactor),
51520
+ width: Math.round(region.width * this._scaleFactor),
51521
+ height: Math.round(region.height * this._scaleFactor)
51522
+ } : void 0
51523
+ });
51524
+ } catch {
51525
+ }
51526
+ }
51527
+ return result;
51528
+ } catch {
51529
+ return [];
51530
+ }
51531
+ }
51532
+ async focusWindow(windowId) {
51533
+ this.assertInitialized();
51534
+ let target = this._windowCache.get(windowId);
51535
+ if (!target) {
51536
+ const { getWindows } = this._nut;
51537
+ const windows = await getWindows();
51538
+ target = windows.find((w) => w.windowHandle === windowId);
51539
+ }
51540
+ if (!target) {
51541
+ throw new Error(`Window with ID ${windowId} not found. Call desktop_window_list first to get current window IDs.`);
51542
+ }
51543
+ await target.focus();
51544
+ }
51545
+ };
51546
+
51547
+ // src/tools/desktop/getDriver.ts
51548
+ var defaultDriver = null;
51549
+ async function getDesktopDriver(config) {
51550
+ if (config?.driver) {
51551
+ if (!config.driver.isInitialized) {
51552
+ await config.driver.initialize();
51553
+ }
51554
+ return config.driver;
51555
+ }
51556
+ if (!defaultDriver) {
51557
+ defaultDriver = new NutTreeDriver();
51558
+ }
51559
+ if (!defaultDriver.isInitialized) {
51560
+ await defaultDriver.initialize();
51561
+ }
51562
+ return defaultDriver;
51563
+ }
51564
+ function resetDefaultDriver() {
51565
+ defaultDriver = null;
51566
+ }
51567
+
51568
+ // src/tools/desktop/screenshot.ts
51569
+ function createDesktopScreenshotTool(config) {
51570
+ return {
51571
+ definition: {
51572
+ type: "function",
51573
+ function: {
51574
+ name: "desktop_screenshot",
51575
+ description: `Take a screenshot of the entire screen or a specific region. Returns the screenshot image for visual analysis. Use this to see what's on screen before performing actions. IMPORTANT: If you capture a region, element positions in the image are relative to the region's top-left corner. To click an element at image position (ix, iy), you must use screen coordinates (ix + region.x, iy + region.y). Prefer full-screen screenshots to avoid coordinate offset errors.`,
51576
+ parameters: {
51577
+ type: "object",
51578
+ properties: {
51579
+ region: {
51580
+ type: "object",
51581
+ description: "Optional region to capture (in physical pixel coordinates). Omit to capture full screen.",
51582
+ properties: {
51583
+ x: { type: "number", description: "Left edge X coordinate" },
51584
+ y: { type: "number", description: "Top edge Y coordinate" },
51585
+ width: { type: "number", description: "Width in pixels" },
51586
+ height: { type: "number", description: "Height in pixels" }
51587
+ },
51588
+ required: ["x", "y", "width", "height"]
51589
+ }
51590
+ },
51591
+ required: []
51592
+ }
51593
+ }
51594
+ },
51595
+ describeCall: (args) => {
51596
+ if (args.region) {
51597
+ return `region (${args.region.x},${args.region.y}) ${args.region.width}x${args.region.height}`;
51598
+ }
51599
+ return "full screen";
51600
+ },
51601
+ execute: async (args) => {
51602
+ try {
51603
+ const driver = await getDesktopDriver(config);
51604
+ const screenshot = await driver.screenshot(args.region);
51605
+ return {
51606
+ success: true,
51607
+ width: screenshot.width,
51608
+ height: screenshot.height,
51609
+ base64: screenshot.base64,
51610
+ __images: [{ base64: screenshot.base64, mediaType: "image/png" }],
51611
+ // Include region info so the agent can compute screen coordinates:
51612
+ // screen_x = image_x + regionOffsetX, screen_y = image_y + regionOffsetY
51613
+ ...args.region ? { regionOffsetX: args.region.x, regionOffsetY: args.region.y } : {}
51614
+ };
51615
+ } catch (err) {
51616
+ return { success: false, error: err.message };
51617
+ }
51618
+ }
51619
+ };
51620
+ }
51621
+ var desktopScreenshot = createDesktopScreenshotTool();
51622
+
51623
+ // src/tools/desktop/mouseMove.ts
51624
+ function createDesktopMouseMoveTool(config) {
51625
+ return {
51626
+ definition: {
51627
+ type: "function",
51628
+ function: {
51629
+ name: "desktop_mouse_move",
51630
+ description: `Move the mouse cursor to the specified (x, y) position. Coordinates are in screenshot pixel space (full screen). Returns the actual cursor position after the move for verification.`,
51631
+ parameters: {
51632
+ type: "object",
51633
+ properties: {
51634
+ x: { type: "number", description: "X coordinate (in screenshot pixels)" },
51635
+ y: { type: "number", description: "Y coordinate (in screenshot pixels)" }
51636
+ },
51637
+ required: ["x", "y"]
51638
+ }
51639
+ }
51640
+ },
51641
+ describeCall: (args) => `(${args.x}, ${args.y})`,
51642
+ execute: async (args) => {
51643
+ try {
51644
+ const driver = await getDesktopDriver(config);
51645
+ await driver.mouseMove(args.x, args.y);
51646
+ await applyHumanDelay(config ?? {});
51647
+ const actual = await driver.getCursorPosition();
51648
+ return { success: true, x: actual.x, y: actual.y };
51649
+ } catch (err) {
51650
+ return { success: false, error: err.message };
51651
+ }
51652
+ }
51653
+ };
51654
+ }
51655
+ var desktopMouseMove = createDesktopMouseMoveTool();
51656
+
51657
+ // src/tools/desktop/mouseClick.ts
51658
+ function createDesktopMouseClickTool(config) {
51659
+ return {
51660
+ definition: {
51661
+ type: "function",
51662
+ function: {
51663
+ name: "desktop_mouse_click",
51664
+ description: `Click the mouse at the specified position or at the current cursor position. Supports left/right/middle button and single/double/triple click.`,
51665
+ parameters: {
51666
+ type: "object",
51667
+ properties: {
51668
+ x: { type: "number", description: "X coordinate to click (in screenshot pixels). Omit to click at current position." },
51669
+ y: { type: "number", description: "Y coordinate to click (in screenshot pixels). Omit to click at current position." },
51670
+ button: {
51671
+ type: "string",
51672
+ enum: ["left", "right", "middle"],
51673
+ description: 'Mouse button to click. Default: "left"'
51674
+ },
51675
+ clickCount: {
51676
+ type: "number",
51677
+ description: "Number of clicks (1=single, 2=double, 3=triple). Default: 1"
51678
+ }
51679
+ },
51680
+ required: []
51681
+ }
51682
+ }
51683
+ },
51684
+ describeCall: (args) => {
51685
+ const pos = args.x !== void 0 ? `(${args.x}, ${args.y})` : "current position";
51686
+ const btn = args.button && args.button !== "left" ? ` ${args.button}` : "";
51687
+ const count = args.clickCount && args.clickCount > 1 ? ` x${args.clickCount}` : "";
51688
+ return `${pos}${btn}${count}`;
51689
+ },
51690
+ execute: async (args) => {
51691
+ try {
51692
+ const driver = await getDesktopDriver(config);
51693
+ const button = args.button ?? "left";
51694
+ const clickCount = args.clickCount ?? 1;
51695
+ if (args.x !== void 0 && args.y !== void 0) {
51696
+ await driver.mouseClick(args.x, args.y, button, clickCount);
51697
+ } else {
51698
+ const pos = await driver.getCursorPosition();
51699
+ await driver.mouseClick(pos.x, pos.y, button, clickCount);
51700
+ }
51701
+ await applyHumanDelay(config ?? {});
51702
+ const actual = await driver.getCursorPosition();
51703
+ return { success: true, x: actual.x, y: actual.y, button, clickCount };
51704
+ } catch (err) {
51705
+ return { success: false, error: err.message };
51706
+ }
51707
+ }
51708
+ };
51709
+ }
51710
+ var desktopMouseClick = createDesktopMouseClickTool();
51711
+
51712
+ // src/tools/desktop/mouseDrag.ts
51713
+ function createDesktopMouseDragTool(config) {
51714
+ return {
51715
+ definition: {
51716
+ type: "function",
51717
+ function: {
51718
+ name: "desktop_mouse_drag",
51719
+ description: `Drag the mouse from one position to another. Presses the button at the start position, moves to the end position, then releases.`,
51720
+ parameters: {
51721
+ type: "object",
51722
+ properties: {
51723
+ startX: { type: "number", description: "Start X coordinate (in screenshot pixels)" },
51724
+ startY: { type: "number", description: "Start Y coordinate (in screenshot pixels)" },
51725
+ endX: { type: "number", description: "End X coordinate (in screenshot pixels)" },
51726
+ endY: { type: "number", description: "End Y coordinate (in screenshot pixels)" },
51727
+ button: {
51728
+ type: "string",
51729
+ enum: ["left", "right", "middle"],
51730
+ description: 'Mouse button to use for dragging. Default: "left"'
51731
+ }
51732
+ },
51733
+ required: ["startX", "startY", "endX", "endY"]
51734
+ }
51735
+ }
51736
+ },
51737
+ describeCall: (args) => `(${args.startX},${args.startY}) \u2192 (${args.endX},${args.endY})`,
51738
+ execute: async (args) => {
51739
+ try {
51740
+ const driver = await getDesktopDriver(config);
51741
+ await driver.mouseDrag(args.startX, args.startY, args.endX, args.endY, args.button ?? "left");
51742
+ await applyHumanDelay(config ?? {});
51743
+ return { success: true };
51744
+ } catch (err) {
51745
+ return { success: false, error: err.message };
51746
+ }
51747
+ }
51748
+ };
51749
+ }
51750
+ var desktopMouseDrag = createDesktopMouseDragTool();
51751
+
51752
+ // src/tools/desktop/mouseScroll.ts
51753
+ function createDesktopMouseScrollTool(config) {
51754
+ return {
51755
+ definition: {
51756
+ type: "function",
51757
+ function: {
51758
+ name: "desktop_mouse_scroll",
51759
+ description: `Scroll the mouse wheel. Positive deltaY scrolls down, negative scrolls up. Positive deltaX scrolls right, negative scrolls left. Optionally specify position to scroll at.`,
51760
+ parameters: {
51761
+ type: "object",
51762
+ properties: {
51763
+ deltaX: { type: "number", description: "Horizontal scroll amount. Positive=right, negative=left. Default: 0" },
51764
+ deltaY: { type: "number", description: "Vertical scroll amount. Positive=down, negative=up. Default: 0" },
51765
+ x: { type: "number", description: "X coordinate to scroll at (in screenshot pixels). Omit to scroll at current position." },
51766
+ y: { type: "number", description: "Y coordinate to scroll at (in screenshot pixels). Omit to scroll at current position." }
51767
+ },
51768
+ required: []
51769
+ }
51770
+ }
51771
+ },
51772
+ describeCall: (args) => {
51773
+ const parts = [];
51774
+ if (args.deltaY) parts.push(args.deltaY > 0 ? `down ${args.deltaY}` : `up ${Math.abs(args.deltaY)}`);
51775
+ if (args.deltaX) parts.push(args.deltaX > 0 ? `right ${args.deltaX}` : `left ${Math.abs(args.deltaX)}`);
51776
+ if (args.x !== void 0) parts.push(`at (${args.x},${args.y})`);
51777
+ return parts.join(", ") || "no-op";
51778
+ },
51779
+ execute: async (args) => {
51780
+ try {
51781
+ const driver = await getDesktopDriver(config);
51782
+ await driver.mouseScroll(args.deltaX ?? 0, args.deltaY ?? 0, args.x, args.y);
51783
+ await applyHumanDelay(config ?? {});
51784
+ return { success: true };
51785
+ } catch (err) {
51786
+ return { success: false, error: err.message };
51787
+ }
51788
+ }
51789
+ };
51790
+ }
51791
+ var desktopMouseScroll = createDesktopMouseScrollTool();
51792
+
51793
+ // src/tools/desktop/getCursor.ts
51794
+ function createDesktopGetCursorTool(config) {
51795
+ return {
51796
+ definition: {
51797
+ type: "function",
51798
+ function: {
51799
+ name: "desktop_get_cursor",
51800
+ description: `Get the current mouse cursor position in screenshot pixel coordinates.`,
51801
+ parameters: {
51802
+ type: "object",
51803
+ properties: {},
51804
+ required: []
51805
+ }
51806
+ }
51807
+ },
51808
+ describeCall: () => "get cursor position",
51809
+ execute: async () => {
51810
+ try {
51811
+ const driver = await getDesktopDriver(config);
51812
+ const pos = await driver.getCursorPosition();
51813
+ return { success: true, x: pos.x, y: pos.y };
51814
+ } catch (err) {
51815
+ return { success: false, error: err.message };
51816
+ }
51817
+ }
51818
+ };
51819
+ }
51820
+ var desktopGetCursor = createDesktopGetCursorTool();
51821
+
51822
+ // src/tools/desktop/keyboardType.ts
51823
+ function createDesktopKeyboardTypeTool(config) {
51824
+ return {
51825
+ definition: {
51826
+ type: "function",
51827
+ function: {
51828
+ name: "desktop_keyboard_type",
51829
+ description: `Type text using the keyboard. Each character is typed as a keypress. Use this for entering text into focused input fields.`,
51830
+ parameters: {
51831
+ type: "object",
51832
+ properties: {
51833
+ text: { type: "string", description: "The text to type" },
51834
+ delay: { type: "number", description: "Delay in ms between each keystroke. Default: uses system default." }
51835
+ },
51836
+ required: ["text"]
51837
+ }
51838
+ }
51839
+ },
51840
+ describeCall: (args) => {
51841
+ const preview = args.text.length > 30 ? args.text.slice(0, 27) + "..." : args.text;
51842
+ return `"${preview}"`;
51843
+ },
51844
+ execute: async (args) => {
51845
+ try {
51846
+ const driver = await getDesktopDriver(config);
51847
+ await driver.keyboardType(args.text, args.delay);
51848
+ await applyHumanDelay(config ?? {});
51849
+ return { success: true };
51850
+ } catch (err) {
51851
+ return { success: false, error: err.message };
51852
+ }
51853
+ }
51854
+ };
51855
+ }
51856
+ var desktopKeyboardType = createDesktopKeyboardTypeTool();
51857
+
51858
+ // src/tools/desktop/keyboardKey.ts
51859
+ function createDesktopKeyboardKeyTool(config) {
51860
+ return {
51861
+ definition: {
51862
+ type: "function",
51863
+ function: {
51864
+ name: "desktop_keyboard_key",
51865
+ description: `Press a keyboard shortcut or special key. Use "+" to combine keys (e.g., "ctrl+c", "cmd+shift+s", "enter", "tab", "escape"). Modifiers: ctrl, cmd/command, alt/option, shift. Special keys: enter, tab, escape, backspace, delete, space, up, down, left, right, f1-f12, home, end, pageup, pagedown.`,
51866
+ parameters: {
51867
+ type: "object",
51868
+ properties: {
51869
+ keys: {
51870
+ type: "string",
51871
+ description: 'Key combo string (e.g., "ctrl+c", "enter", "cmd+shift+s")'
51872
+ }
51873
+ },
51874
+ required: ["keys"]
51875
+ }
51876
+ }
51877
+ },
51878
+ describeCall: (args) => args.keys,
51879
+ execute: async (args) => {
51880
+ try {
51881
+ const driver = await getDesktopDriver(config);
51882
+ await driver.keyboardKey(args.keys);
51883
+ await applyHumanDelay(config ?? {});
51884
+ return { success: true };
51885
+ } catch (err) {
51886
+ return { success: false, error: err.message };
51887
+ }
51888
+ }
51889
+ };
51890
+ }
51891
+ var desktopKeyboardKey = createDesktopKeyboardKeyTool();
51892
+
51893
+ // src/tools/desktop/getScreenSize.ts
51894
+ function createDesktopGetScreenSizeTool(config) {
51895
+ return {
51896
+ definition: {
51897
+ type: "function",
51898
+ function: {
51899
+ name: "desktop_get_screen_size",
51900
+ description: `Get the screen dimensions. Returns physical pixel size (screenshot space), logical size (OS coordinates), and the scale factor (e.g., 2.0 on Retina displays). All desktop tool coordinates use physical pixel space.`,
51901
+ parameters: {
51902
+ type: "object",
51903
+ properties: {},
51904
+ required: []
51905
+ }
51906
+ }
51907
+ },
51908
+ describeCall: () => "get screen size",
51909
+ execute: async () => {
51910
+ try {
51911
+ const driver = await getDesktopDriver(config);
51912
+ const size = await driver.getScreenSize();
51913
+ return {
51914
+ success: true,
51915
+ physicalWidth: size.physicalWidth,
51916
+ physicalHeight: size.physicalHeight,
51917
+ logicalWidth: size.logicalWidth,
51918
+ logicalHeight: size.logicalHeight,
51919
+ scaleFactor: size.scaleFactor
51920
+ };
51921
+ } catch (err) {
51922
+ return { success: false, error: err.message };
51923
+ }
51924
+ }
51925
+ };
51926
+ }
51927
+ var desktopGetScreenSize = createDesktopGetScreenSizeTool();
51928
+
51929
+ // src/tools/desktop/windowList.ts
51930
+ function createDesktopWindowListTool(config) {
51931
+ return {
51932
+ definition: {
51933
+ type: "function",
51934
+ function: {
51935
+ name: "desktop_window_list",
51936
+ description: `List all visible windows on the desktop. Returns window IDs, titles, application names, and bounds. Use the window ID with desktop_window_focus to bring a window to the foreground.`,
51937
+ parameters: {
51938
+ type: "object",
51939
+ properties: {},
51940
+ required: []
51941
+ }
51942
+ }
51943
+ },
51944
+ describeCall: () => "list windows",
51945
+ execute: async () => {
51946
+ try {
51947
+ const driver = await getDesktopDriver(config);
51948
+ const windows = await driver.getWindowList();
51949
+ return { success: true, windows };
51950
+ } catch (err) {
51951
+ return { success: false, error: err.message };
51952
+ }
51953
+ }
51954
+ };
51955
+ }
51956
+ var desktopWindowList = createDesktopWindowListTool();
51957
+
51958
+ // src/tools/desktop/windowFocus.ts
51959
+ function createDesktopWindowFocusTool(config) {
51960
+ return {
51961
+ definition: {
51962
+ type: "function",
51963
+ function: {
51964
+ name: "desktop_window_focus",
51965
+ description: `Focus (bring to front) a window by its ID. Use desktop_window_list to get available window IDs.`,
51966
+ parameters: {
51967
+ type: "object",
51968
+ properties: {
51969
+ windowId: {
51970
+ type: "number",
51971
+ description: "The window ID from desktop_window_list"
51972
+ }
51973
+ },
51974
+ required: ["windowId"]
51975
+ }
51976
+ }
51977
+ },
51978
+ describeCall: (args) => `window ${args.windowId}`,
51979
+ execute: async (args) => {
51980
+ try {
51981
+ const driver = await getDesktopDriver(config);
51982
+ await driver.focusWindow(args.windowId);
51983
+ return { success: true };
51984
+ } catch (err) {
51985
+ return { success: false, error: err.message };
51986
+ }
51987
+ }
51988
+ };
51989
+ }
51990
+ var desktopWindowFocus = createDesktopWindowFocusTool();
51991
+
51992
+ // src/tools/desktop/index.ts
51993
+ var desktopTools = [
51994
+ desktopScreenshot,
51995
+ desktopMouseMove,
51996
+ desktopMouseClick,
51997
+ desktopMouseDrag,
51998
+ desktopMouseScroll,
51999
+ desktopGetCursor,
52000
+ desktopKeyboardType,
52001
+ desktopKeyboardKey,
52002
+ desktopGetScreenSize,
52003
+ desktopWindowList,
52004
+ desktopWindowFocus
52005
+ ];
52006
+
49552
52007
  // src/tools/registry.generated.ts
49553
52008
  var toolRegistry = [
49554
52009
  {
@@ -49560,6 +52015,105 @@ var toolRegistry = [
49560
52015
  tool: executeJavaScript,
49561
52016
  safeByDefault: false
49562
52017
  },
52018
+ {
52019
+ name: "desktop_get_cursor",
52020
+ exportName: "desktopGetCursor",
52021
+ displayName: "Desktop Get Cursor",
52022
+ category: "desktop",
52023
+ description: "Get the current mouse cursor position in screenshot pixel coordinates.",
52024
+ tool: desktopGetCursor,
52025
+ safeByDefault: false
52026
+ },
52027
+ {
52028
+ name: "desktop_get_screen_size",
52029
+ exportName: "desktopGetScreenSize",
52030
+ displayName: "Desktop Get Screen Size",
52031
+ category: "desktop",
52032
+ description: "Get the screen dimensions. Returns physical pixel size (screenshot space), logical size (OS coordinates), and the scale factor (e.g., 2.0 on Retina displays). All desktop tool coordinates use physical",
52033
+ tool: desktopGetScreenSize,
52034
+ safeByDefault: false
52035
+ },
52036
+ {
52037
+ name: "desktop_keyboard_key",
52038
+ exportName: "desktopKeyboardKey",
52039
+ displayName: "Desktop Keyboard Key",
52040
+ category: "desktop",
52041
+ description: 'Press a keyboard shortcut or special key. Use "+" to combine keys (e.g., "ctrl+c", "cmd+shift+s", "enter", "tab", "escape"). Modifiers: ctrl, cmd/command, alt/option, shift. Special keys: enter, tab, ',
52042
+ tool: desktopKeyboardKey,
52043
+ safeByDefault: false
52044
+ },
52045
+ {
52046
+ name: "desktop_keyboard_type",
52047
+ exportName: "desktopKeyboardType",
52048
+ displayName: "Desktop Keyboard Type",
52049
+ category: "desktop",
52050
+ description: "Type text using the keyboard. Each character is typed as a keypress. Use this for entering text into focused input fields.",
52051
+ tool: desktopKeyboardType,
52052
+ safeByDefault: false
52053
+ },
52054
+ {
52055
+ name: "desktop_mouse_click",
52056
+ exportName: "desktopMouseClick",
52057
+ displayName: "Desktop Mouse Click",
52058
+ category: "desktop",
52059
+ description: "Click the mouse at the specified position or at the current cursor position. Supports left/right/middle button and single/double/triple click.",
52060
+ tool: desktopMouseClick,
52061
+ safeByDefault: false
52062
+ },
52063
+ {
52064
+ name: "desktop_mouse_drag",
52065
+ exportName: "desktopMouseDrag",
52066
+ displayName: "Desktop Mouse Drag",
52067
+ category: "desktop",
52068
+ description: "Drag the mouse from one position to another. Presses the button at the start position, moves to the end position, then releases.",
52069
+ tool: desktopMouseDrag,
52070
+ safeByDefault: false
52071
+ },
52072
+ {
52073
+ name: "desktop_mouse_move",
52074
+ exportName: "desktopMouseMove",
52075
+ displayName: "Desktop Mouse Move",
52076
+ category: "desktop",
52077
+ description: "Move the mouse cursor to the specified (x, y) position. Coordinates are in screenshot pixel space (full screen). Returns the actual cursor position after the move for verification.",
52078
+ tool: desktopMouseMove,
52079
+ safeByDefault: false
52080
+ },
52081
+ {
52082
+ name: "desktop_mouse_scroll",
52083
+ exportName: "desktopMouseScroll",
52084
+ displayName: "Desktop Mouse Scroll",
52085
+ category: "desktop",
52086
+ description: "Scroll the mouse wheel. Positive deltaY scrolls down, negative scrolls up. Positive deltaX scrolls right, negative scrolls left. Optionally specify position to scroll at.",
52087
+ tool: desktopMouseScroll,
52088
+ safeByDefault: false
52089
+ },
52090
+ {
52091
+ name: "desktop_screenshot",
52092
+ exportName: "desktopScreenshot",
52093
+ displayName: "Desktop Screenshot",
52094
+ category: "desktop",
52095
+ description: "Take a screenshot of the entire screen or a specific region. Returns the screenshot image for visual analysis. Use this to see what's on screen before performing actions. IMPORTANT: If you capture a r",
52096
+ tool: desktopScreenshot,
52097
+ safeByDefault: false
52098
+ },
52099
+ {
52100
+ name: "desktop_window_focus",
52101
+ exportName: "desktopWindowFocus",
52102
+ displayName: "Desktop Window Focus",
52103
+ category: "desktop",
52104
+ description: "Focus (bring to front) a window by its ID. Use desktop_window_list to get available window IDs.",
52105
+ tool: desktopWindowFocus,
52106
+ safeByDefault: false
52107
+ },
52108
+ {
52109
+ name: "desktop_window_list",
52110
+ exportName: "desktopWindowList",
52111
+ displayName: "Desktop Window List",
52112
+ category: "desktop",
52113
+ description: "List all visible windows on the desktop. Returns window IDs, titles, application names, and bounds. Use the window ID with desktop_window_focus to bring a window to the foreground.",
52114
+ tool: desktopWindowList,
52115
+ safeByDefault: false
52116
+ },
49563
52117
  {
49564
52118
  name: "edit_file",
49565
52119
  exportName: "editFile",
@@ -49601,7 +52155,7 @@ var toolRegistry = [
49601
52155
  exportName: "readFile",
49602
52156
  displayName: "Read File",
49603
52157
  category: "filesystem",
49604
- description: "Read content from a file on the local filesystem.",
52158
+ description: "Read content from a file on the local filesystem. Supports text files AND binary document formats \u2014 PDF, DOCX, PPTX, XLSX, ODS, ODT, ODP, and images (PNG, JPG, GIF, WEBP) are automatically converted t",
49605
52159
  tool: readFile5,
49606
52160
  safeByDefault: true
49607
52161
  },
@@ -49637,7 +52191,7 @@ var toolRegistry = [
49637
52191
  exportName: "webFetch",
49638
52192
  displayName: "Web Fetch",
49639
52193
  category: "web",
49640
- description: "Fetch and extract text content from a web page URL.",
52194
+ description: "Fetch and extract content from a URL \u2014 works with web pages AND document files (PDF, DOCX, XLSX, PPTX, etc.). Document URLs are automatically detected and converted to markdown text.",
49641
52195
  tool: webFetch,
49642
52196
  safeByDefault: true
49643
52197
  }
@@ -49997,6 +52551,6 @@ REMEMBER: Keep it conversational, ask one question at a time, and only output th
49997
52551
  }
49998
52552
  };
49999
52553
 
50000
- export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DefaultCompactionStrategy, DependencyCycleError, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileStorage, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileMediaStorage, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createSearchCodeTool, createSearchFilesTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, defaultDescribeCall, detectDependencyCycle, detectServiceFromURL, developerTools, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, metrics, parseRepository, readClipboardImage, readFile5 as readFile, registerScrapeProvider, resolveConnector, resolveDependencies, resolveRepository, retryWithBackoff, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
52554
+ export { AGENT_DEFINITION_FORMAT_VERSION, AIError, APPROVAL_STATE_VERSION, Agent, AgentContextNextGen, ApproximateTokenEstimator, BaseMediaProvider, BasePluginNextGen, BaseProvider, BaseTextProvider, BraveProvider, CONNECTOR_CONFIG_VERSION, CONTEXT_SESSION_FORMAT_VERSION, CheckpointManager, CircuitBreaker, CircuitOpenError, Connector, ConnectorConfigStore, ConnectorTools, ConsoleMetrics, ContentType, ContextOverflowError, DEFAULT_ALLOWLIST, DEFAULT_BACKOFF_CONFIG, DEFAULT_BASE_DELAY_MS, DEFAULT_CHECKPOINT_STRATEGY, DEFAULT_CIRCUIT_BREAKER_CONFIG, DEFAULT_CONFIG2 as DEFAULT_CONFIG, DEFAULT_CONNECTOR_TIMEOUT, DEFAULT_CONTEXT_CONFIG, DEFAULT_DESKTOP_CONFIG, DEFAULT_FEATURES, DEFAULT_FILESYSTEM_CONFIG, DEFAULT_HISTORY_MANAGER_CONFIG, DEFAULT_MAX_DELAY_MS, DEFAULT_MAX_RETRIES, DEFAULT_MEMORY_CONFIG, DEFAULT_PERMISSION_CONFIG, DEFAULT_RATE_LIMITER_CONFIG, DEFAULT_RETRYABLE_STATUSES, DEFAULT_SHELL_CONFIG, DESKTOP_TOOL_NAMES, DefaultCompactionStrategy, DependencyCycleError, DocumentReader, ErrorHandler, ExecutionContext, ExternalDependencyHandler, FileAgentDefinitionStorage, FileConnectorStorage, FileContextStorage, FileMediaStorage as FileMediaOutputHandler, FileMediaStorage, FilePersistentInstructionsStorage, FileStorage, FormatDetector, FrameworkLogger, HookManager, IMAGE_MODELS, IMAGE_MODEL_REGISTRY, ImageGeneration, InContextMemoryPluginNextGen, InMemoryAgentStateStorage, InMemoryHistoryStorage, InMemoryMetrics, InMemoryPlanStorage, InMemoryStorage, InvalidConfigError, InvalidToolArgumentsError, LLM_MODELS, LoggingPlugin, MCPClient, MCPConnectionError, MCPError, MCPProtocolError, MCPRegistry, MCPResourceError, MCPTimeoutError, MCPToolError, MEMORY_PRIORITY_VALUES, MODEL_REGISTRY, MemoryConnectorStorage, MemoryEvictionCompactor, MemoryStorage, MessageBuilder, MessageRole, ModelNotSupportedError, NoOpMetrics, NutTreeDriver, OAuthManager, ParallelTasksError, PersistentInstructionsPluginNextGen, PlanningAgent, ProviderAuthError, ProviderConfigAgent, ProviderContextLengthError, ProviderError, ProviderErrorMapper, ProviderNotFoundError, ProviderRateLimitError, RapidAPIProvider, RateLimitError, SERVICE_DEFINITIONS, SERVICE_INFO, SERVICE_URL_PATTERNS, SIMPLE_ICONS_CDN, STT_MODELS, STT_MODEL_REGISTRY, ScopedConnectorRegistry, ScrapeProvider, SearchProvider, SerperProvider, Services, SpeechToText, StrategyRegistry, StreamEventType, StreamHelpers, StreamState, SummarizeCompactor, TERMINAL_TASK_STATUSES, TTS_MODELS, TTS_MODEL_REGISTRY, TaskTimeoutError, TaskValidationError, TavilyProvider, TextToSpeech, TokenBucketRateLimiter, ToolCallState, ToolExecutionError, ToolExecutionPipeline, ToolManager, ToolNotFoundError, ToolPermissionManager, ToolRegistry, ToolTimeoutError, TruncateCompactor, VENDORS, VENDOR_ICON_MAP, VIDEO_MODELS, VIDEO_MODEL_REGISTRY, Vendor, VideoGeneration, WorkingMemory, WorkingMemoryPluginNextGen, addJitter, allVendorTemplates, assertNotDestroyed, authenticatedFetch, backoffSequence, backoffWait, bash, buildAuthConfig, buildEndpointWithQuery, buildQueryString, calculateBackoff, calculateCost, calculateEntrySize, calculateImageCost, calculateSTTCost, calculateTTSCost, calculateVideoCost, canTaskExecute, createAgentStorage, createAuthenticatedFetch, createBashTool, createConnectorFromTemplate, createCreatePRTool, createDesktopGetCursorTool, createDesktopGetScreenSizeTool, createDesktopKeyboardKeyTool, createDesktopKeyboardTypeTool, createDesktopMouseClickTool, createDesktopMouseDragTool, createDesktopMouseMoveTool, createDesktopMouseScrollTool, createDesktopScreenshotTool, createDesktopWindowFocusTool, createDesktopWindowListTool, createEditFileTool, createEstimator, createExecuteJavaScriptTool, createFileAgentDefinitionStorage, createFileContextStorage, createFileMediaStorage, createGetPRTool, createGitHubReadFileTool, createGlobTool, createGrepTool, createImageGenerationTool, createImageProvider, createListDirectoryTool, createMessageWithImages, createMetricsCollector, createPRCommentsTool, createPRFilesTool, createPlan, createProvider, createReadFileTool, createSearchCodeTool, createSearchFilesTool, createSpeechToTextTool, createTask, createTextMessage, createTextToSpeechTool, createVideoProvider, createVideoTools, createWriteFileTool, defaultDescribeCall, desktopGetCursor, desktopGetScreenSize, desktopKeyboardKey, desktopKeyboardType, desktopMouseClick, desktopMouseDrag, desktopMouseMove, desktopMouseScroll, desktopScreenshot, desktopTools, desktopWindowFocus, desktopWindowList, detectDependencyCycle, detectServiceFromURL, developerTools, documentToContent, editFile, evaluateCondition, extractJSON, extractJSONField, extractNumber, findConnectorByServiceTypes, forPlan, forTasks, generateEncryptionKey, generateSimplePlan, generateWebAPITool, getActiveImageModels, getActiveModels, getActiveSTTModels, getActiveTTSModels, getActiveVideoModels, getAllBuiltInTools, getAllServiceIds, getAllVendorLogos, getAllVendorTemplates, getBackgroundOutput, getConnectorTools, getCredentialsSetupURL, getDesktopDriver, getDocsURL, getImageModelInfo, getImageModelsByVendor, getImageModelsWithFeature, getMediaOutputHandler, getMediaStorage, getModelInfo, getModelsByVendor, getNextExecutableTasks, getRegisteredScrapeProviders, getSTTModelInfo, getSTTModelsByVendor, getSTTModelsWithFeature, getServiceDefinition, getServiceInfo, getServicesByCategory, getTTSModelInfo, getTTSModelsByVendor, getTTSModelsWithFeature, getTaskDependencies, getToolByName, getToolCallDescription, getToolCategories, getToolRegistry, getToolsByCategory, getToolsRequiringConnector, getVendorAuthTemplate, getVendorColor, getVendorDefaultBaseURL, getVendorInfo, getVendorLogo, getVendorLogoCdnUrl, getVendorLogoSvg, getVendorTemplate, getVideoModelInfo, getVideoModelsByVendor, getVideoModelsWithAudio, getVideoModelsWithFeature, glob, globalErrorHandler, grep, hasClipboardImage, hasVendorLogo, isBlockedCommand, isErrorEvent, isExcludedExtension, isKnownService, isOutputTextDelta, isResponseComplete, isSimpleScope, isStreamEvent, isTaskAwareScope, isTaskBlocked, isTerminalMemoryStatus, isTerminalStatus, isToolCallArgumentsDelta, isToolCallArgumentsDone, isToolCallStart, isVendor, killBackgroundProcess, listConnectorsByServiceTypes, listDirectory, listVendorIds, listVendors, listVendorsByAuthType, listVendorsByCategory, listVendorsWithLogos, logger, mergeTextPieces, metrics, parseKeyCombo, parseRepository, readClipboardImage, readDocumentAsContent, readFile5 as readFile, registerScrapeProvider, resetDefaultDriver, resolveConnector, resolveDependencies, resolveRepository, retryWithBackoff, scopeEquals, scopeMatches, setMediaOutputHandler, setMediaStorage, setMetricsCollector, simpleTokenEstimator, toConnectorOptions, toolRegistry, tools_exports as tools, updateTaskStatus, validatePath, writeFile5 as writeFile };
50001
52555
  //# sourceMappingURL=index.js.map
50002
52556
  //# sourceMappingURL=index.js.map