@rdmind/rdmind 0.0.21-alpha.1 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/cli.js +617 -521
  2. package/package.json +2 -2
package/cli.js CHANGED
@@ -183747,7 +183747,7 @@ function createContentGeneratorConfig(config, authType, generationConfig) {
183747
183747
  };
183748
183748
  }
183749
183749
  async function createContentGenerator(config, gcConfig, sessionId2) {
183750
- const version2 = "0.0.21-alpha.1";
183750
+ const version2 = "0.0.21";
183751
183751
  const userAgent2 = `QwenCode/${version2} (${process.platform}; ${process.arch})`;
183752
183752
  const baseHeaders = {
183753
183753
  "User-Agent": userAgent2
@@ -200491,6 +200491,506 @@ ${[...this.pendingCitations].sort().join("\n")}`
200491
200491
  }
200492
200492
  });
200493
200493
 
200494
+ // packages/core/src/config/constants.ts
200495
+ var DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, DEFAULT_FILE_FILTERING_OPTIONS;
200496
+ var init_constants3 = __esm({
200497
+ "packages/core/src/config/constants.ts"() {
200498
+ "use strict";
200499
+ init_esbuild_shims();
200500
+ DEFAULT_MEMORY_FILE_FILTERING_OPTIONS = {
200501
+ respectGitIgnore: false,
200502
+ respectQwenIgnore: true
200503
+ };
200504
+ DEFAULT_FILE_FILTERING_OPTIONS = {
200505
+ respectGitIgnore: true,
200506
+ respectQwenIgnore: true
200507
+ };
200508
+ }
200509
+ });
200510
+
200511
+ // packages/core/src/utils/getFolderStructure.ts
200512
+ import * as fs24 from "node:fs/promises";
200513
+ import * as path21 from "node:path";
200514
+ async function readFullStructure(rootPath, options2) {
200515
+ const rootName = path21.basename(rootPath);
200516
+ const rootNode = {
200517
+ name: rootName,
200518
+ path: rootPath,
200519
+ files: [],
200520
+ subFolders: [],
200521
+ totalChildren: 0,
200522
+ totalFiles: 0
200523
+ };
200524
+ const queue = [
200525
+ { folderInfo: rootNode, currentPath: rootPath }
200526
+ ];
200527
+ let currentItemCount = 0;
200528
+ const processedPaths = /* @__PURE__ */ new Set();
200529
+ while (queue.length > 0) {
200530
+ const { folderInfo, currentPath } = queue.shift();
200531
+ if (processedPaths.has(currentPath)) {
200532
+ continue;
200533
+ }
200534
+ processedPaths.add(currentPath);
200535
+ if (currentItemCount >= options2.maxItems) {
200536
+ continue;
200537
+ }
200538
+ let entries;
200539
+ try {
200540
+ const rawEntries = await fs24.readdir(currentPath, { withFileTypes: true });
200541
+ entries = rawEntries.sort((a, b) => a.name.localeCompare(b.name));
200542
+ } catch (error) {
200543
+ if (isNodeError(error) && (error.code === "EACCES" || error.code === "ENOENT")) {
200544
+ console.warn(
200545
+ `Warning: Could not read directory ${currentPath}: ${error.message}`
200546
+ );
200547
+ if (currentPath === rootPath && error.code === "ENOENT") {
200548
+ return null;
200549
+ }
200550
+ continue;
200551
+ }
200552
+ throw error;
200553
+ }
200554
+ const filesInCurrentDir = [];
200555
+ const subFoldersInCurrentDir = [];
200556
+ for (const entry of entries) {
200557
+ if (entry.isFile()) {
200558
+ if (currentItemCount >= options2.maxItems) {
200559
+ folderInfo.hasMoreFiles = true;
200560
+ break;
200561
+ }
200562
+ const fileName = entry.name;
200563
+ const filePath = path21.join(currentPath, fileName);
200564
+ if (options2.fileService) {
200565
+ const shouldIgnore = options2.fileFilteringOptions.respectGitIgnore && options2.fileService.shouldGitIgnoreFile(filePath) || options2.fileFilteringOptions.respectQwenIgnore && options2.fileService.shouldQwenIgnoreFile(filePath);
200566
+ if (shouldIgnore) {
200567
+ continue;
200568
+ }
200569
+ }
200570
+ if (!options2.fileIncludePattern || options2.fileIncludePattern.test(fileName)) {
200571
+ filesInCurrentDir.push(fileName);
200572
+ currentItemCount++;
200573
+ folderInfo.totalFiles++;
200574
+ folderInfo.totalChildren++;
200575
+ }
200576
+ }
200577
+ }
200578
+ folderInfo.files = filesInCurrentDir;
200579
+ for (const entry of entries) {
200580
+ if (entry.isDirectory()) {
200581
+ if (currentItemCount >= options2.maxItems) {
200582
+ folderInfo.hasMoreSubfolders = true;
200583
+ break;
200584
+ }
200585
+ const subFolderName = entry.name;
200586
+ const subFolderPath = path21.join(currentPath, subFolderName);
200587
+ let isIgnored = false;
200588
+ if (options2.fileService) {
200589
+ isIgnored = options2.fileFilteringOptions.respectGitIgnore && options2.fileService.shouldGitIgnoreFile(subFolderPath) || options2.fileFilteringOptions.respectQwenIgnore && options2.fileService.shouldQwenIgnoreFile(subFolderPath);
200590
+ }
200591
+ if (options2.ignoredFolders.has(subFolderName) || isIgnored) {
200592
+ const ignoredSubFolder = {
200593
+ name: subFolderName,
200594
+ path: subFolderPath,
200595
+ files: [],
200596
+ subFolders: [],
200597
+ totalChildren: 0,
200598
+ totalFiles: 0,
200599
+ isIgnored: true
200600
+ };
200601
+ subFoldersInCurrentDir.push(ignoredSubFolder);
200602
+ currentItemCount++;
200603
+ folderInfo.totalChildren++;
200604
+ continue;
200605
+ }
200606
+ const subFolderNode = {
200607
+ name: subFolderName,
200608
+ path: subFolderPath,
200609
+ files: [],
200610
+ subFolders: [],
200611
+ totalChildren: 0,
200612
+ totalFiles: 0
200613
+ };
200614
+ subFoldersInCurrentDir.push(subFolderNode);
200615
+ currentItemCount++;
200616
+ folderInfo.totalChildren++;
200617
+ queue.push({ folderInfo: subFolderNode, currentPath: subFolderPath });
200618
+ }
200619
+ }
200620
+ folderInfo.subFolders = subFoldersInCurrentDir;
200621
+ }
200622
+ return rootNode;
200623
+ }
200624
+ function formatStructure(node, currentIndent, isLastChildOfParent, isProcessingRootNode, builder) {
200625
+ const connector = isLastChildOfParent ? "\u2514\u2500\u2500\u2500" : "\u251C\u2500\u2500\u2500";
200626
+ if (!isProcessingRootNode || node.isIgnored) {
200627
+ builder.push(
200628
+ `${currentIndent}${connector}${node.name}${path21.sep}${node.isIgnored ? TRUNCATION_INDICATOR : ""}`
200629
+ );
200630
+ }
200631
+ const indentForChildren = isProcessingRootNode ? "" : currentIndent + (isLastChildOfParent ? " " : "\u2502 ");
200632
+ const fileCount = node.files.length;
200633
+ for (let i = 0; i < fileCount; i++) {
200634
+ const isLastFileAmongSiblings = i === fileCount - 1 && node.subFolders.length === 0 && !node.hasMoreSubfolders;
200635
+ const fileConnector = isLastFileAmongSiblings ? "\u2514\u2500\u2500\u2500" : "\u251C\u2500\u2500\u2500";
200636
+ builder.push(`${indentForChildren}${fileConnector}${node.files[i]}`);
200637
+ }
200638
+ if (node.hasMoreFiles) {
200639
+ const isLastIndicatorAmongSiblings = node.subFolders.length === 0 && !node.hasMoreSubfolders;
200640
+ const fileConnector = isLastIndicatorAmongSiblings ? "\u2514\u2500\u2500\u2500" : "\u251C\u2500\u2500\u2500";
200641
+ builder.push(`${indentForChildren}${fileConnector}${TRUNCATION_INDICATOR}`);
200642
+ }
200643
+ const subFolderCount = node.subFolders.length;
200644
+ for (let i = 0; i < subFolderCount; i++) {
200645
+ const isLastSubfolderAmongSiblings = i === subFolderCount - 1 && !node.hasMoreSubfolders;
200646
+ formatStructure(
200647
+ node.subFolders[i],
200648
+ indentForChildren,
200649
+ isLastSubfolderAmongSiblings,
200650
+ false,
200651
+ builder
200652
+ );
200653
+ }
200654
+ if (node.hasMoreSubfolders) {
200655
+ builder.push(`${indentForChildren}\u2514\u2500\u2500\u2500${TRUNCATION_INDICATOR}`);
200656
+ }
200657
+ }
200658
+ async function getFolderStructure(directory, options2) {
200659
+ const resolvedPath = path21.resolve(directory);
200660
+ const mergedOptions = {
200661
+ maxItems: options2?.maxItems ?? MAX_ITEMS,
200662
+ ignoredFolders: options2?.ignoredFolders ?? DEFAULT_IGNORED_FOLDERS,
200663
+ fileIncludePattern: options2?.fileIncludePattern,
200664
+ fileService: options2?.fileService,
200665
+ fileFilteringOptions: options2?.fileFilteringOptions ?? DEFAULT_FILE_FILTERING_OPTIONS
200666
+ };
200667
+ try {
200668
+ let isTruncated2 = function(node) {
200669
+ if (node.hasMoreFiles || node.hasMoreSubfolders || node.isIgnored) {
200670
+ return true;
200671
+ }
200672
+ for (const sub of node.subFolders) {
200673
+ if (isTruncated2(sub)) {
200674
+ return true;
200675
+ }
200676
+ }
200677
+ return false;
200678
+ };
200679
+ var isTruncated = isTruncated2;
200680
+ __name(isTruncated2, "isTruncated");
200681
+ const structureRoot = await readFullStructure(resolvedPath, mergedOptions);
200682
+ if (!structureRoot) {
200683
+ return `Error: Could not read directory "${resolvedPath}". Check path and permissions.`;
200684
+ }
200685
+ const structureLines = [];
200686
+ formatStructure(structureRoot, "", true, true, structureLines);
200687
+ let summary = `Showing up to ${mergedOptions.maxItems} items (files + folders).`;
200688
+ if (isTruncated2(structureRoot)) {
200689
+ summary += ` Folders or files indicated with ${TRUNCATION_INDICATOR} contain more items not shown, were ignored, or the display limit (${mergedOptions.maxItems} items) was reached.`;
200690
+ }
200691
+ return `${summary}
200692
+
200693
+ ${resolvedPath}${path21.sep}
200694
+ ${structureLines.join("\n")}`;
200695
+ } catch (error) {
200696
+ console.error(`Error getting folder structure for ${resolvedPath}:`, error);
200697
+ return `Error processing directory "${resolvedPath}": ${getErrorMessage(error)}`;
200698
+ }
200699
+ }
200700
+ var MAX_ITEMS, TRUNCATION_INDICATOR, DEFAULT_IGNORED_FOLDERS;
200701
+ var init_getFolderStructure = __esm({
200702
+ "packages/core/src/utils/getFolderStructure.ts"() {
200703
+ "use strict";
200704
+ init_esbuild_shims();
200705
+ init_errors();
200706
+ init_constants3();
200707
+ MAX_ITEMS = 20;
200708
+ TRUNCATION_INDICATOR = "...";
200709
+ DEFAULT_IGNORED_FOLDERS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
200710
+ __name(readFullStructure, "readFullStructure");
200711
+ __name(formatStructure, "formatStructure");
200712
+ __name(getFolderStructure, "getFolderStructure");
200713
+ }
200714
+ });
200715
+
200716
+ // packages/core/src/utils/environmentContext.ts
200717
+ async function getDirectoryContextString(config) {
200718
+ const workspaceContext = config.getWorkspaceContext();
200719
+ const workspaceDirectories = workspaceContext.getDirectories();
200720
+ const folderStructures = await Promise.all(
200721
+ workspaceDirectories.map(
200722
+ (dir) => getFolderStructure(dir, {
200723
+ fileService: config.getFileService()
200724
+ })
200725
+ )
200726
+ );
200727
+ const folderStructure = folderStructures.join("\n");
200728
+ let workingDirPreamble;
200729
+ if (workspaceDirectories.length === 1) {
200730
+ workingDirPreamble = `I'm currently working in the directory: ${workspaceDirectories[0]}`;
200731
+ } else {
200732
+ const dirList = workspaceDirectories.map((dir) => ` - ${dir}`).join("\n");
200733
+ workingDirPreamble = `I'm currently working in the following directories:
200734
+ ${dirList}`;
200735
+ }
200736
+ return `${workingDirPreamble}
200737
+ Here is the folder structure of the current working directories:
200738
+
200739
+ ${folderStructure}`;
200740
+ }
200741
+ async function getEnvironmentContext(config) {
200742
+ const today = (/* @__PURE__ */ new Date()).toLocaleDateString(void 0, {
200743
+ weekday: "long",
200744
+ year: "numeric",
200745
+ month: "long",
200746
+ day: "numeric"
200747
+ });
200748
+ const platform14 = process.platform;
200749
+ const directoryContext = await getDirectoryContextString(config);
200750
+ const context2 = `
200751
+ This is the RDMind. We are setting up the context for our chat.
200752
+ Today's date is ${today} (formatted according to the user's locale).
200753
+ My operating system is: ${platform14}
200754
+ ${directoryContext}
200755
+ `.trim();
200756
+ const initialParts = [{ text: context2 }];
200757
+ const toolRegistry = config.getToolRegistry();
200758
+ if (config.getFullContext()) {
200759
+ try {
200760
+ const readManyFilesTool = toolRegistry.getTool("read_many_files");
200761
+ if (readManyFilesTool) {
200762
+ const invocation = readManyFilesTool.build({
200763
+ paths: ["**/*"],
200764
+ // Read everything recursively
200765
+ useDefaultExcludes: true
200766
+ // Use default excludes
200767
+ });
200768
+ const result = await invocation.execute(AbortSignal.timeout(3e4));
200769
+ if (result.llmContent) {
200770
+ initialParts.push({
200771
+ text: `
200772
+ --- Full File Context ---
200773
+ ${result.llmContent}`
200774
+ });
200775
+ } else {
200776
+ console.warn(
200777
+ "Full context requested, but read_many_files returned no content."
200778
+ );
200779
+ }
200780
+ } else {
200781
+ console.warn(
200782
+ "Full context requested, but read_many_files tool not found."
200783
+ );
200784
+ }
200785
+ } catch (error) {
200786
+ console.error("Error reading full file context:", error);
200787
+ initialParts.push({
200788
+ text: "\n--- Error reading full file context ---"
200789
+ });
200790
+ }
200791
+ }
200792
+ return initialParts;
200793
+ }
200794
+ async function getInitialChatHistory(config, extraHistory) {
200795
+ const envParts = await getEnvironmentContext(config);
200796
+ const envContextString = envParts.map((part) => part.text || "").join("\n\n");
200797
+ return [
200798
+ {
200799
+ role: "user",
200800
+ parts: [{ text: envContextString }]
200801
+ },
200802
+ {
200803
+ role: "model",
200804
+ parts: [{ text: "Got it. Thanks for the context!" }]
200805
+ },
200806
+ ...extraHistory ?? []
200807
+ ];
200808
+ }
200809
+ var init_environmentContext = __esm({
200810
+ "packages/core/src/utils/environmentContext.ts"() {
200811
+ "use strict";
200812
+ init_esbuild_shims();
200813
+ init_getFolderStructure();
200814
+ __name(getDirectoryContextString, "getDirectoryContextString");
200815
+ __name(getEnvironmentContext, "getEnvironmentContext");
200816
+ __name(getInitialChatHistory, "getInitialChatHistory");
200817
+ }
200818
+ });
200819
+
200820
+ // packages/core/src/services/chatCompressionService.ts
200821
+ function findCompressSplitPoint(contents, fraction) {
200822
+ if (fraction <= 0 || fraction >= 1) {
200823
+ throw new Error("Fraction must be between 0 and 1");
200824
+ }
200825
+ const charCounts = contents.map((content) => JSON.stringify(content).length);
200826
+ const totalCharCount = charCounts.reduce((a, b) => a + b, 0);
200827
+ const targetCharCount = totalCharCount * fraction;
200828
+ let lastSplitPoint = 0;
200829
+ let cumulativeCharCount = 0;
200830
+ for (let i = 0; i < contents.length; i++) {
200831
+ const content = contents[i];
200832
+ if (content.role === "user" && !content.parts?.some((part) => !!part.functionResponse)) {
200833
+ if (cumulativeCharCount >= targetCharCount) {
200834
+ return i;
200835
+ }
200836
+ lastSplitPoint = i;
200837
+ }
200838
+ cumulativeCharCount += charCounts[i];
200839
+ }
200840
+ const lastContent = contents[contents.length - 1];
200841
+ if (lastContent?.role === "model" && !lastContent?.parts?.some((part) => part.functionCall)) {
200842
+ return contents.length;
200843
+ }
200844
+ return lastSplitPoint;
200845
+ }
200846
+ var COMPRESSION_TOKEN_THRESHOLD, COMPRESSION_PRESERVE_THRESHOLD, ChatCompressionService;
200847
+ var init_chatCompressionService = __esm({
200848
+ "packages/core/src/services/chatCompressionService.ts"() {
200849
+ "use strict";
200850
+ init_esbuild_shims();
200851
+ init_turn();
200852
+ init_uiTelemetry();
200853
+ init_tokenLimits();
200854
+ init_prompts();
200855
+ init_partUtils();
200856
+ init_loggers();
200857
+ init_types3();
200858
+ init_environmentContext();
200859
+ COMPRESSION_TOKEN_THRESHOLD = 0.7;
200860
+ COMPRESSION_PRESERVE_THRESHOLD = 0.3;
200861
+ __name(findCompressSplitPoint, "findCompressSplitPoint");
200862
+ ChatCompressionService = class {
200863
+ static {
200864
+ __name(this, "ChatCompressionService");
200865
+ }
200866
+ async compress(chat, promptId, force, model, config, hasFailedCompressionAttempt) {
200867
+ const curatedHistory = chat.getHistory(true);
200868
+ if (curatedHistory.length === 0 || hasFailedCompressionAttempt && !force) {
200869
+ return {
200870
+ newHistory: null,
200871
+ info: {
200872
+ originalTokenCount: 0,
200873
+ newTokenCount: 0,
200874
+ compressionStatus: 5 /* NOOP */
200875
+ }
200876
+ };
200877
+ }
200878
+ const originalTokenCount = uiTelemetryService.getLastPromptTokenCount();
200879
+ const contextPercentageThreshold = config.getChatCompression()?.contextPercentageThreshold;
200880
+ if (!force) {
200881
+ const threshold = contextPercentageThreshold ?? COMPRESSION_TOKEN_THRESHOLD;
200882
+ if (originalTokenCount < threshold * tokenLimit(model)) {
200883
+ return {
200884
+ newHistory: null,
200885
+ info: {
200886
+ originalTokenCount,
200887
+ newTokenCount: originalTokenCount,
200888
+ compressionStatus: 5 /* NOOP */
200889
+ }
200890
+ };
200891
+ }
200892
+ }
200893
+ const splitPoint = findCompressSplitPoint(
200894
+ curatedHistory,
200895
+ 1 - COMPRESSION_PRESERVE_THRESHOLD
200896
+ );
200897
+ const historyToCompress = curatedHistory.slice(0, splitPoint);
200898
+ const historyToKeep = curatedHistory.slice(splitPoint);
200899
+ if (historyToCompress.length === 0) {
200900
+ return {
200901
+ newHistory: null,
200902
+ info: {
200903
+ originalTokenCount,
200904
+ newTokenCount: originalTokenCount,
200905
+ compressionStatus: 5 /* NOOP */
200906
+ }
200907
+ };
200908
+ }
200909
+ const summaryResponse = await config.getContentGenerator().generateContent(
200910
+ {
200911
+ model,
200912
+ contents: [
200913
+ ...historyToCompress,
200914
+ {
200915
+ role: "user",
200916
+ parts: [
200917
+ {
200918
+ text: "First, reason in your scratchpad. Then, generate the <state_snapshot>."
200919
+ }
200920
+ ]
200921
+ }
200922
+ ],
200923
+ config: {
200924
+ systemInstruction: getCompressionPrompt()
200925
+ }
200926
+ },
200927
+ promptId
200928
+ );
200929
+ const summary = getResponseText(summaryResponse) ?? "";
200930
+ const isSummaryEmpty = !summary || summary.trim().length === 0;
200931
+ let newTokenCount = originalTokenCount;
200932
+ let extraHistory = [];
200933
+ if (!isSummaryEmpty) {
200934
+ extraHistory = [
200935
+ {
200936
+ role: "user",
200937
+ parts: [{ text: summary }]
200938
+ },
200939
+ {
200940
+ role: "model",
200941
+ parts: [{ text: "Got it. Thanks for the additional context!" }]
200942
+ },
200943
+ ...historyToKeep
200944
+ ];
200945
+ const fullNewHistory = await getInitialChatHistory(config, extraHistory);
200946
+ newTokenCount = Math.floor(
200947
+ fullNewHistory.reduce(
200948
+ (total, content) => total + JSON.stringify(content).length,
200949
+ 0
200950
+ ) / 4
200951
+ );
200952
+ }
200953
+ logChatCompression(
200954
+ config,
200955
+ makeChatCompressionEvent({
200956
+ tokens_before: originalTokenCount,
200957
+ tokens_after: newTokenCount
200958
+ })
200959
+ );
200960
+ if (isSummaryEmpty) {
200961
+ return {
200962
+ newHistory: null,
200963
+ info: {
200964
+ originalTokenCount,
200965
+ newTokenCount: originalTokenCount,
200966
+ compressionStatus: 4 /* COMPRESSION_FAILED_EMPTY_SUMMARY */
200967
+ }
200968
+ };
200969
+ } else if (newTokenCount > originalTokenCount) {
200970
+ return {
200971
+ newHistory: null,
200972
+ info: {
200973
+ originalTokenCount,
200974
+ newTokenCount,
200975
+ compressionStatus: 2 /* COMPRESSION_FAILED_INFLATED_TOKEN_COUNT */
200976
+ }
200977
+ };
200978
+ } else {
200979
+ uiTelemetryService.setLastPromptTokenCount(newTokenCount);
200980
+ return {
200981
+ newHistory: extraHistory,
200982
+ info: {
200983
+ originalTokenCount,
200984
+ newTokenCount,
200985
+ compressionStatus: 1 /* COMPRESSED */
200986
+ }
200987
+ };
200988
+ }
200989
+ }
200990
+ };
200991
+ }
200992
+ });
200993
+
200494
200994
  // packages/core/src/services/loopDetectionService.ts
200495
200995
  import { createHash as createHash3 } from "node:crypto";
200496
200996
  var TOOL_CALL_LOOP_THRESHOLD, CONTENT_LOOP_THRESHOLD, CONTENT_CHUNK_SIZE, MAX_HISTORY_LENGTH, LLM_LOOP_CHECK_HISTORY_COUNT, LLM_CHECK_AFTER_TURNS, DEFAULT_LLM_CHECK_INTERVAL, MIN_LLM_CHECK_INTERVAL, MAX_LLM_CHECK_INTERVAL, LOOP_DETECTION_SYSTEM_PROMPT, LoopDetectionService;
@@ -200872,316 +201372,6 @@ var init_types6 = __esm({
200872
201372
  }
200873
201373
  });
200874
201374
 
200875
- // packages/core/src/config/constants.ts
200876
- var DEFAULT_MEMORY_FILE_FILTERING_OPTIONS, DEFAULT_FILE_FILTERING_OPTIONS;
200877
- var init_constants3 = __esm({
200878
- "packages/core/src/config/constants.ts"() {
200879
- "use strict";
200880
- init_esbuild_shims();
200881
- DEFAULT_MEMORY_FILE_FILTERING_OPTIONS = {
200882
- respectGitIgnore: false,
200883
- respectQwenIgnore: true
200884
- };
200885
- DEFAULT_FILE_FILTERING_OPTIONS = {
200886
- respectGitIgnore: true,
200887
- respectQwenIgnore: true
200888
- };
200889
- }
200890
- });
200891
-
200892
- // packages/core/src/utils/getFolderStructure.ts
200893
- import * as fs24 from "node:fs/promises";
200894
- import * as path21 from "node:path";
200895
- async function readFullStructure(rootPath, options2) {
200896
- const rootName = path21.basename(rootPath);
200897
- const rootNode = {
200898
- name: rootName,
200899
- path: rootPath,
200900
- files: [],
200901
- subFolders: [],
200902
- totalChildren: 0,
200903
- totalFiles: 0
200904
- };
200905
- const queue = [
200906
- { folderInfo: rootNode, currentPath: rootPath }
200907
- ];
200908
- let currentItemCount = 0;
200909
- const processedPaths = /* @__PURE__ */ new Set();
200910
- while (queue.length > 0) {
200911
- const { folderInfo, currentPath } = queue.shift();
200912
- if (processedPaths.has(currentPath)) {
200913
- continue;
200914
- }
200915
- processedPaths.add(currentPath);
200916
- if (currentItemCount >= options2.maxItems) {
200917
- continue;
200918
- }
200919
- let entries;
200920
- try {
200921
- const rawEntries = await fs24.readdir(currentPath, { withFileTypes: true });
200922
- entries = rawEntries.sort((a, b) => a.name.localeCompare(b.name));
200923
- } catch (error) {
200924
- if (isNodeError(error) && (error.code === "EACCES" || error.code === "ENOENT")) {
200925
- console.warn(
200926
- `Warning: Could not read directory ${currentPath}: ${error.message}`
200927
- );
200928
- if (currentPath === rootPath && error.code === "ENOENT") {
200929
- return null;
200930
- }
200931
- continue;
200932
- }
200933
- throw error;
200934
- }
200935
- const filesInCurrentDir = [];
200936
- const subFoldersInCurrentDir = [];
200937
- for (const entry of entries) {
200938
- if (entry.isFile()) {
200939
- if (currentItemCount >= options2.maxItems) {
200940
- folderInfo.hasMoreFiles = true;
200941
- break;
200942
- }
200943
- const fileName = entry.name;
200944
- const filePath = path21.join(currentPath, fileName);
200945
- if (options2.fileService) {
200946
- const shouldIgnore = options2.fileFilteringOptions.respectGitIgnore && options2.fileService.shouldGitIgnoreFile(filePath) || options2.fileFilteringOptions.respectQwenIgnore && options2.fileService.shouldQwenIgnoreFile(filePath);
200947
- if (shouldIgnore) {
200948
- continue;
200949
- }
200950
- }
200951
- if (!options2.fileIncludePattern || options2.fileIncludePattern.test(fileName)) {
200952
- filesInCurrentDir.push(fileName);
200953
- currentItemCount++;
200954
- folderInfo.totalFiles++;
200955
- folderInfo.totalChildren++;
200956
- }
200957
- }
200958
- }
200959
- folderInfo.files = filesInCurrentDir;
200960
- for (const entry of entries) {
200961
- if (entry.isDirectory()) {
200962
- if (currentItemCount >= options2.maxItems) {
200963
- folderInfo.hasMoreSubfolders = true;
200964
- break;
200965
- }
200966
- const subFolderName = entry.name;
200967
- const subFolderPath = path21.join(currentPath, subFolderName);
200968
- let isIgnored = false;
200969
- if (options2.fileService) {
200970
- isIgnored = options2.fileFilteringOptions.respectGitIgnore && options2.fileService.shouldGitIgnoreFile(subFolderPath) || options2.fileFilteringOptions.respectQwenIgnore && options2.fileService.shouldQwenIgnoreFile(subFolderPath);
200971
- }
200972
- if (options2.ignoredFolders.has(subFolderName) || isIgnored) {
200973
- const ignoredSubFolder = {
200974
- name: subFolderName,
200975
- path: subFolderPath,
200976
- files: [],
200977
- subFolders: [],
200978
- totalChildren: 0,
200979
- totalFiles: 0,
200980
- isIgnored: true
200981
- };
200982
- subFoldersInCurrentDir.push(ignoredSubFolder);
200983
- currentItemCount++;
200984
- folderInfo.totalChildren++;
200985
- continue;
200986
- }
200987
- const subFolderNode = {
200988
- name: subFolderName,
200989
- path: subFolderPath,
200990
- files: [],
200991
- subFolders: [],
200992
- totalChildren: 0,
200993
- totalFiles: 0
200994
- };
200995
- subFoldersInCurrentDir.push(subFolderNode);
200996
- currentItemCount++;
200997
- folderInfo.totalChildren++;
200998
- queue.push({ folderInfo: subFolderNode, currentPath: subFolderPath });
200999
- }
201000
- }
201001
- folderInfo.subFolders = subFoldersInCurrentDir;
201002
- }
201003
- return rootNode;
201004
- }
201005
- function formatStructure(node, currentIndent, isLastChildOfParent, isProcessingRootNode, builder) {
201006
- const connector = isLastChildOfParent ? "\u2514\u2500\u2500\u2500" : "\u251C\u2500\u2500\u2500";
201007
- if (!isProcessingRootNode || node.isIgnored) {
201008
- builder.push(
201009
- `${currentIndent}${connector}${node.name}${path21.sep}${node.isIgnored ? TRUNCATION_INDICATOR : ""}`
201010
- );
201011
- }
201012
- const indentForChildren = isProcessingRootNode ? "" : currentIndent + (isLastChildOfParent ? " " : "\u2502 ");
201013
- const fileCount = node.files.length;
201014
- for (let i = 0; i < fileCount; i++) {
201015
- const isLastFileAmongSiblings = i === fileCount - 1 && node.subFolders.length === 0 && !node.hasMoreSubfolders;
201016
- const fileConnector = isLastFileAmongSiblings ? "\u2514\u2500\u2500\u2500" : "\u251C\u2500\u2500\u2500";
201017
- builder.push(`${indentForChildren}${fileConnector}${node.files[i]}`);
201018
- }
201019
- if (node.hasMoreFiles) {
201020
- const isLastIndicatorAmongSiblings = node.subFolders.length === 0 && !node.hasMoreSubfolders;
201021
- const fileConnector = isLastIndicatorAmongSiblings ? "\u2514\u2500\u2500\u2500" : "\u251C\u2500\u2500\u2500";
201022
- builder.push(`${indentForChildren}${fileConnector}${TRUNCATION_INDICATOR}`);
201023
- }
201024
- const subFolderCount = node.subFolders.length;
201025
- for (let i = 0; i < subFolderCount; i++) {
201026
- const isLastSubfolderAmongSiblings = i === subFolderCount - 1 && !node.hasMoreSubfolders;
201027
- formatStructure(
201028
- node.subFolders[i],
201029
- indentForChildren,
201030
- isLastSubfolderAmongSiblings,
201031
- false,
201032
- builder
201033
- );
201034
- }
201035
- if (node.hasMoreSubfolders) {
201036
- builder.push(`${indentForChildren}\u2514\u2500\u2500\u2500${TRUNCATION_INDICATOR}`);
201037
- }
201038
- }
201039
- async function getFolderStructure(directory, options2) {
201040
- const resolvedPath = path21.resolve(directory);
201041
- const mergedOptions = {
201042
- maxItems: options2?.maxItems ?? MAX_ITEMS,
201043
- ignoredFolders: options2?.ignoredFolders ?? DEFAULT_IGNORED_FOLDERS,
201044
- fileIncludePattern: options2?.fileIncludePattern,
201045
- fileService: options2?.fileService,
201046
- fileFilteringOptions: options2?.fileFilteringOptions ?? DEFAULT_FILE_FILTERING_OPTIONS
201047
- };
201048
- try {
201049
- let isTruncated2 = function(node) {
201050
- if (node.hasMoreFiles || node.hasMoreSubfolders || node.isIgnored) {
201051
- return true;
201052
- }
201053
- for (const sub of node.subFolders) {
201054
- if (isTruncated2(sub)) {
201055
- return true;
201056
- }
201057
- }
201058
- return false;
201059
- };
201060
- var isTruncated = isTruncated2;
201061
- __name(isTruncated2, "isTruncated");
201062
- const structureRoot = await readFullStructure(resolvedPath, mergedOptions);
201063
- if (!structureRoot) {
201064
- return `Error: Could not read directory "${resolvedPath}". Check path and permissions.`;
201065
- }
201066
- const structureLines = [];
201067
- formatStructure(structureRoot, "", true, true, structureLines);
201068
- let summary = `Showing up to ${mergedOptions.maxItems} items (files + folders).`;
201069
- if (isTruncated2(structureRoot)) {
201070
- summary += ` Folders or files indicated with ${TRUNCATION_INDICATOR} contain more items not shown, were ignored, or the display limit (${mergedOptions.maxItems} items) was reached.`;
201071
- }
201072
- return `${summary}
201073
-
201074
- ${resolvedPath}${path21.sep}
201075
- ${structureLines.join("\n")}`;
201076
- } catch (error) {
201077
- console.error(`Error getting folder structure for ${resolvedPath}:`, error);
201078
- return `Error processing directory "${resolvedPath}": ${getErrorMessage(error)}`;
201079
- }
201080
- }
201081
- var MAX_ITEMS, TRUNCATION_INDICATOR, DEFAULT_IGNORED_FOLDERS;
201082
- var init_getFolderStructure = __esm({
201083
- "packages/core/src/utils/getFolderStructure.ts"() {
201084
- "use strict";
201085
- init_esbuild_shims();
201086
- init_errors();
201087
- init_constants3();
201088
- MAX_ITEMS = 20;
201089
- TRUNCATION_INDICATOR = "...";
201090
- DEFAULT_IGNORED_FOLDERS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist"]);
201091
- __name(readFullStructure, "readFullStructure");
201092
- __name(formatStructure, "formatStructure");
201093
- __name(getFolderStructure, "getFolderStructure");
201094
- }
201095
- });
201096
-
201097
- // packages/core/src/utils/environmentContext.ts
201098
- async function getDirectoryContextString(config) {
201099
- const workspaceContext = config.getWorkspaceContext();
201100
- const workspaceDirectories = workspaceContext.getDirectories();
201101
- const folderStructures = await Promise.all(
201102
- workspaceDirectories.map(
201103
- (dir) => getFolderStructure(dir, {
201104
- fileService: config.getFileService()
201105
- })
201106
- )
201107
- );
201108
- const folderStructure = folderStructures.join("\n");
201109
- let workingDirPreamble;
201110
- if (workspaceDirectories.length === 1) {
201111
- workingDirPreamble = `I'm currently working in the directory: ${workspaceDirectories[0]}`;
201112
- } else {
201113
- const dirList = workspaceDirectories.map((dir) => ` - ${dir}`).join("\n");
201114
- workingDirPreamble = `I'm currently working in the following directories:
201115
- ${dirList}`;
201116
- }
201117
- return `${workingDirPreamble}
201118
- Here is the folder structure of the current working directories:
201119
-
201120
- ${folderStructure}`;
201121
- }
201122
- async function getEnvironmentContext(config) {
201123
- const today = (/* @__PURE__ */ new Date()).toLocaleDateString(void 0, {
201124
- weekday: "long",
201125
- year: "numeric",
201126
- month: "long",
201127
- day: "numeric"
201128
- });
201129
- const platform14 = process.platform;
201130
- const directoryContext = await getDirectoryContextString(config);
201131
- const context2 = `
201132
- This is the RDMind. We are setting up the context for our chat.
201133
- Today's date is ${today} (formatted according to the user's locale).
201134
- My operating system is: ${platform14}
201135
- ${directoryContext}
201136
- `.trim();
201137
- const initialParts = [{ text: context2 }];
201138
- const toolRegistry = config.getToolRegistry();
201139
- if (config.getFullContext()) {
201140
- try {
201141
- const readManyFilesTool = toolRegistry.getTool("read_many_files");
201142
- if (readManyFilesTool) {
201143
- const invocation = readManyFilesTool.build({
201144
- paths: ["**/*"],
201145
- // Read everything recursively
201146
- useDefaultExcludes: true
201147
- // Use default excludes
201148
- });
201149
- const result = await invocation.execute(AbortSignal.timeout(3e4));
201150
- if (result.llmContent) {
201151
- initialParts.push({
201152
- text: `
201153
- --- Full File Context ---
201154
- ${result.llmContent}`
201155
- });
201156
- } else {
201157
- console.warn(
201158
- "Full context requested, but read_many_files returned no content."
201159
- );
201160
- }
201161
- } else {
201162
- console.warn(
201163
- "Full context requested, but read_many_files tool not found."
201164
- );
201165
- }
201166
- } catch (error) {
201167
- console.error("Error reading full file context:", error);
201168
- initialParts.push({
201169
- text: "\n--- Error reading full file context ---"
201170
- });
201171
- }
201172
- }
201173
- return initialParts;
201174
- }
201175
- var init_environmentContext = __esm({
201176
- "packages/core/src/utils/environmentContext.ts"() {
201177
- "use strict";
201178
- init_esbuild_shims();
201179
- init_getFolderStructure();
201180
- __name(getDirectoryContextString, "getDirectoryContextString");
201181
- __name(getEnvironmentContext, "getEnvironmentContext");
201182
- }
201183
- });
201184
-
201185
201375
  // packages/core/src/subagents/subagent-events.ts
201186
201376
  import { EventEmitter as EventEmitter5 } from "events";
201187
201377
  var SubAgentEventEmitter;
@@ -201785,11 +201975,7 @@ var init_subagent = __esm({
201785
201975
  "PromptConfig cannot have both `systemPrompt` and `initialMessages` defined."
201786
201976
  );
201787
201977
  }
201788
- const envParts = await getEnvironmentContext(this.runtimeContext);
201789
- const envHistory = [
201790
- { role: "user", parts: envParts },
201791
- { role: "model", parts: [{ text: "Got it. Thanks for the context!" }] }
201792
- ];
201978
+ const envHistory = await getInitialChatHistory(this.runtimeContext);
201793
201979
  const start_history = [
201794
201980
  ...envHistory,
201795
201981
  ...this.promptConfig.initialMessages ?? []
@@ -206856,32 +207042,7 @@ var init_types8 = __esm({
206856
207042
  function isThinkingSupported(model) {
206857
207043
  return model.startsWith("gemini-2.5") || model === DEFAULT_GEMINI_MODEL_AUTO;
206858
207044
  }
206859
- function findCompressSplitPoint(contents, fraction) {
206860
- if (fraction <= 0 || fraction >= 1) {
206861
- throw new Error("Fraction must be between 0 and 1");
206862
- }
206863
- const charCounts = contents.map((content) => JSON.stringify(content).length);
206864
- const totalCharCount = charCounts.reduce((a, b) => a + b, 0);
206865
- const targetCharCount = totalCharCount * fraction;
206866
- let lastSplitPoint = 0;
206867
- let cumulativeCharCount = 0;
206868
- for (let i = 0; i < contents.length; i++) {
206869
- const content = contents[i];
206870
- if (content.role === "user" && !content.parts?.some((part) => !!part.functionResponse)) {
206871
- if (cumulativeCharCount >= targetCharCount) {
206872
- return i;
206873
- }
206874
- lastSplitPoint = i;
206875
- }
206876
- cumulativeCharCount += charCounts[i];
206877
- }
206878
- const lastContent = contents[contents.length - 1];
206879
- if (lastContent?.role === "model" && !lastContent?.parts?.some((part) => part.functionCall)) {
206880
- return contents.length;
206881
- }
206882
- return lastSplitPoint;
206883
- }
206884
- var MAX_TURNS, COMPRESSION_TOKEN_THRESHOLD, COMPRESSION_PRESERVE_THRESHOLD, GeminiClient;
207045
+ var MAX_TURNS, GeminiClient;
206885
207046
  var init_client2 = __esm({
206886
207047
  "packages/core/src/core/client.ts"() {
206887
207048
  "use strict";
@@ -206890,9 +207051,9 @@ var init_client2 = __esm({
206890
207051
  init_models();
206891
207052
  init_geminiChat();
206892
207053
  init_prompts();
206893
- init_tokenLimits();
206894
207054
  init_turn();
206895
207055
  init_chatRecordingService();
207056
+ init_chatCompressionService();
206896
207057
  init_loopDetectionService();
206897
207058
  init_task();
206898
207059
  init_telemetry();
@@ -206906,10 +207067,7 @@ var init_client2 = __esm({
206906
207067
  init_types8();
206907
207068
  init_handler();
206908
207069
  __name(isThinkingSupported, "isThinkingSupported");
206909
- __name(findCompressSplitPoint, "findCompressSplitPoint");
206910
207070
  MAX_TURNS = 100;
206911
- COMPRESSION_TOKEN_THRESHOLD = 0.7;
206912
- COMPRESSION_PRESERVE_THRESHOLD = 0.3;
206913
207071
  GeminiClient = class {
206914
207072
  constructor(config) {
206915
207073
  this.config = config;
@@ -206992,21 +207150,10 @@ var init_client2 = __esm({
206992
207150
  async startChat(extraHistory) {
206993
207151
  this.forceFullIdeContext = true;
206994
207152
  this.hasFailedCompressionAttempt = false;
206995
- const envParts = await getEnvironmentContext(this.config);
206996
207153
  const toolRegistry = this.config.getToolRegistry();
206997
207154
  const toolDeclarations = toolRegistry.getFunctionDeclarations();
206998
207155
  const tools = [{ functionDeclarations: toolDeclarations }];
206999
- const history = [
207000
- {
207001
- role: "user",
207002
- parts: envParts
207003
- },
207004
- {
207005
- role: "model",
207006
- parts: [{ text: "Got it. Thanks for the context!" }]
207007
- },
207008
- ...extraHistory ?? []
207009
- ];
207156
+ const history = await getInitialChatHistory(this.config, extraHistory);
207010
207157
  try {
207011
207158
  const userMemory = this.config.getUserMemory();
207012
207159
  const model = this.config.getModel();
@@ -207195,12 +207342,13 @@ var init_client2 = __esm({
207195
207342
  userMemory,
207196
207343
  this.config.getModel()
207197
207344
  );
207198
- const environment = await getEnvironmentContext(this.config);
207345
+ const initialHistory = await getInitialChatHistory(this.config);
207199
207346
  const mockRequestContent = [
207200
207347
  {
207201
207348
  role: "system",
207202
- parts: [{ text: systemPrompt }, ...environment]
207349
+ parts: [{ text: systemPrompt }]
207203
207350
  },
207351
+ ...initialHistory,
207204
207352
  ...currentHistory
207205
207353
  ];
207206
207354
  const { totalTokens: totalRequestTokens } = await this.config.getContentGenerator().countTokens({
@@ -207360,99 +207508,26 @@ var init_client2 = __esm({
207360
207508
  }
207361
207509
  }
207362
207510
  async tryCompressChat(prompt_id, force = false) {
207363
- const model = this.config.getModel();
207364
- const curatedHistory = this.getChat().getHistory(true);
207365
- if (curatedHistory.length === 0 || this.hasFailedCompressionAttempt && !force) {
207366
- return {
207367
- originalTokenCount: 0,
207368
- newTokenCount: 0,
207369
- compressionStatus: 4 /* NOOP */
207370
- };
207371
- }
207372
- const originalTokenCount = uiTelemetryService.getLastPromptTokenCount();
207373
- const contextPercentageThreshold = this.config.getChatCompression()?.contextPercentageThreshold;
207374
- if (!force) {
207375
- const threshold = contextPercentageThreshold ?? COMPRESSION_TOKEN_THRESHOLD;
207376
- if (originalTokenCount < threshold * tokenLimit(model)) {
207377
- return {
207378
- originalTokenCount,
207379
- newTokenCount: originalTokenCount,
207380
- compressionStatus: 4 /* NOOP */
207381
- };
207382
- }
207383
- }
207384
- const splitPoint = findCompressSplitPoint(
207385
- curatedHistory,
207386
- 1 - COMPRESSION_PRESERVE_THRESHOLD
207387
- );
207388
- const historyToCompress = curatedHistory.slice(0, splitPoint);
207389
- const historyToKeep = curatedHistory.slice(splitPoint);
207390
- const summaryResponse = await this.config.getContentGenerator().generateContent(
207391
- {
207392
- model,
207393
- contents: [
207394
- ...historyToCompress,
207395
- {
207396
- role: "user",
207397
- parts: [
207398
- {
207399
- text: "First, reason in your scratchpad. Then, generate the <state_snapshot>."
207400
- }
207401
- ]
207402
- }
207403
- ],
207404
- config: {
207405
- systemInstruction: { text: getCompressionPrompt() }
207406
- }
207407
- },
207408
- prompt_id
207409
- );
207410
- const summary = getResponseText(summaryResponse) ?? "";
207411
- const chat = await this.startChat([
207412
- {
207413
- role: "user",
207414
- parts: [{ text: summary }]
207415
- },
207416
- {
207417
- role: "model",
207418
- parts: [{ text: "Got it. Thanks for the additional context!" }]
207419
- },
207420
- ...historyToKeep
207421
- ]);
207422
- this.forceFullIdeContext = true;
207423
- const newTokenCount = Math.floor(
207424
- chat.getHistory().reduce((total, content) => total + JSON.stringify(content).length, 0) / 4
207425
- );
207426
- logChatCompression(
207511
+ const compressionService = new ChatCompressionService();
207512
+ const { newHistory, info } = await compressionService.compress(
207513
+ this.getChat(),
207514
+ prompt_id,
207515
+ force,
207516
+ this.config.getModel(),
207427
207517
  this.config,
207428
- makeChatCompressionEvent({
207429
- tokens_before: originalTokenCount,
207430
- tokens_after: newTokenCount
207431
- })
207518
+ this.hasFailedCompressionAttempt
207432
207519
  );
207433
- if (newTokenCount > originalTokenCount) {
207434
- this.hasFailedCompressionAttempt = !force && true;
207435
- return {
207436
- originalTokenCount,
207437
- newTokenCount,
207438
- compressionStatus: 2 /* COMPRESSION_FAILED_INFLATED_TOKEN_COUNT */
207439
- };
207440
- } else {
207441
- this.chat = chat;
207442
- uiTelemetryService.setLastPromptTokenCount(newTokenCount);
207520
+ if (info.compressionStatus === 1 /* COMPRESSED */) {
207521
+ if (newHistory) {
207522
+ this.chat = await this.startChat(newHistory);
207523
+ this.forceFullIdeContext = true;
207524
+ }
207525
+ } else if (info.compressionStatus === 2 /* COMPRESSION_FAILED_INFLATED_TOKEN_COUNT */ || info.compressionStatus === 4 /* COMPRESSION_FAILED_EMPTY_SUMMARY */) {
207526
+ if (!force) {
207527
+ this.hasFailedCompressionAttempt = true;
207528
+ }
207443
207529
  }
207444
- logChatCompression(
207445
- this.config,
207446
- makeChatCompressionEvent({
207447
- tokens_before: originalTokenCount,
207448
- tokens_after: newTokenCount
207449
- })
207450
- );
207451
- return {
207452
- originalTokenCount,
207453
- newTokenCount,
207454
- compressionStatus: 1 /* COMPRESSED */
207455
- };
207530
+ return info;
207456
207531
  }
207457
207532
  };
207458
207533
  }
@@ -235724,38 +235799,13 @@ async function listKnowledgeExt(subPath = "", debugMode = false) {
235724
235799
  }
235725
235800
  }
235726
235801
  function findKnowledgeDirectory() {
235727
- const candidatePaths = [
235728
- // 1. 用户当前工作目录(用户自己的 .knowledge)
235729
- path43.resolve(process.cwd(), ".knowledge"),
235730
- // 2. npm 安装后:从 core 包找到 cli 包中的 .knowledge
235731
- // core 包位置: node_modules/@rdmind/rdmind/node_modules/@rdmind/rdmind-core/dist/src/tools/
235732
- // cli 包位置: node_modules/@rdmind/rdmind/.knowledge
235733
- // 从 __dirname (dist/src/tools) 回退到 cli 包根目录
235734
- path43.resolve(__dirname4, "../../../../../.knowledge"),
235735
- // 从 core 包的 dist/src/tools 回退到 cli 包
235736
- path43.resolve(__dirname4, "../../../../../../.knowledge"),
235737
- // 兼容不同的安装结构
235738
- // 3. npm 全局安装:从 core 包所在位置找到 rdmind 包
235739
- // 全局: /usr/local/lib/node_modules/@rdmind/rdmind/node_modules/@rdmind/rdmind-core/dist/src/tools
235740
- path43.resolve(__dirname4, "../../../../../../../@rdmind/rdmind/.knowledge"),
235741
- // 4. 开发环境:相对于项目根目录
235742
- path43.resolve(__dirname4, "../../../../../../../.knowledge"),
235743
- // 从 packages/core/dist/src/tools 到项目根
235744
- path43.resolve(__dirname4, "../../../../../../.knowledge"),
235745
- path43.resolve(__dirname4, "../../../../../.knowledge"),
235746
- path43.resolve(__dirname4, "../../../../.knowledge"),
235747
- path43.resolve(__dirname4, "../../../.knowledge"),
235748
- path43.resolve(__dirname4, "../../.knowledge"),
235749
- path43.resolve(__dirname4, "../.knowledge")
235750
- ];
235751
- for (const candidatePath of candidatePaths) {
235752
- try {
235753
- if (fsSync2.existsSync(candidatePath) && fsSync2.statSync(candidatePath).isDirectory()) {
235754
- return candidatePath;
235755
- }
235756
- } catch {
235757
- continue;
235758
- }
235802
+ const userKnowledgePath = path43.resolve(process.cwd(), ".knowledge");
235803
+ if (fsSync2.existsSync(userKnowledgePath) && fsSync2.statSync(userKnowledgePath).isDirectory()) {
235804
+ return userKnowledgePath;
235805
+ }
235806
+ const packageKnowledgePath = path43.join(__dirname4, ".knowledge");
235807
+ if (fsSync2.existsSync(packageKnowledgePath) && fsSync2.statSync(packageKnowledgePath).isDirectory()) {
235808
+ return packageKnowledgePath;
235759
235809
  }
235760
235810
  return null;
235761
235811
  }
@@ -245048,16 +245098,30 @@ var init_redoc_fetch = __esm({
245048
245098
  if (!responseData.data) {
245049
245099
  const errorMessage = "Redoc API response does not contain data field";
245050
245100
  console.error(`[RedocFetchTool] ${errorMessage}`);
245051
- console.error(`[RedocFetchTool] \u5B8C\u6574\u54CD\u5E94\u6570\u636E:`, JSON.stringify(responseData, null, 2));
245101
+ console.error(
245102
+ `[RedocFetchTool] \u5B8C\u6574\u54CD\u5E94\u6570\u636E:`,
245103
+ JSON.stringify(responseData, null, 2)
245104
+ );
245052
245105
  throw new Error(errorMessage);
245053
245106
  }
245054
245107
  if (!responseData.data.content) {
245055
245108
  const errorMessage = "Redoc API response does not contain content field in data";
245056
245109
  console.error(`[RedocFetchTool] ${errorMessage}`);
245057
- console.error(`[RedocFetchTool] \u5B8C\u6574\u54CD\u5E94\u6570\u636E:`, JSON.stringify(responseData, null, 2));
245058
- console.error(`[RedocFetchTool] data \u5B57\u6BB5\u5185\u5BB9:`, JSON.stringify(responseData.data, null, 2));
245059
- console.error(`[RedocFetchTool] data \u5B57\u6BB5\u7684\u6240\u6709\u952E:`, Object.keys(responseData.data));
245060
- throw new Error(`${errorMessage}. \u53EF\u7528\u5B57\u6BB5: ${Object.keys(responseData.data).join(", ")}`);
245110
+ console.error(
245111
+ `[RedocFetchTool] \u5B8C\u6574\u54CD\u5E94\u6570\u636E:`,
245112
+ JSON.stringify(responseData, null, 2)
245113
+ );
245114
+ console.error(
245115
+ `[RedocFetchTool] data \u5B57\u6BB5\u5185\u5BB9:`,
245116
+ JSON.stringify(responseData.data, null, 2)
245117
+ );
245118
+ console.error(
245119
+ `[RedocFetchTool] data \u5B57\u6BB5\u7684\u6240\u6709\u952E:`,
245120
+ Object.keys(responseData.data)
245121
+ );
245122
+ throw new Error(
245123
+ `${errorMessage}. \u53EF\u7528\u5B57\u6BB5: ${Object.keys(responseData.data).join(", ")}`
245124
+ );
245061
245125
  }
245062
245126
  console.debug(
245063
245127
  `[RedocFetchTool] Successfully fetched content for doc_id: ${docId}, title: ${responseData.data.title}`
@@ -319835,7 +319899,7 @@ function CompressionMessage({
319835
319899
  return "Chat history compression did not reduce size. This may indicate issues with the compression prompt.";
319836
319900
  case 3 /* COMPRESSION_FAILED_TOKEN_COUNT_ERROR */:
319837
319901
  return "Could not compress chat history due to a token counting error.";
319838
- case 4 /* NOOP */:
319902
+ case 5 /* NOOP */:
319839
319903
  return "Chat history is already compressed.";
319840
319904
  default:
319841
319905
  return "";
@@ -319912,7 +319976,7 @@ init_esbuild_shims();
319912
319976
 
319913
319977
  // packages/cli/src/generated/git-commit.ts
319914
319978
  init_esbuild_shims();
319915
- var GIT_COMMIT_INFO2 = "34a4d574";
319979
+ var GIT_COMMIT_INFO2 = "bf55c089";
319916
319980
 
319917
319981
  // packages/cli/src/ui/components/AboutBox.tsx
319918
319982
  var import_jsx_runtime43 = __toESM(require_jsx_runtime(), 1);
@@ -329514,6 +329578,8 @@ var USER_SETTINGS_PATH = Storage.getGlobalSettingsPath();
329514
329578
  var USER_SETTINGS_DIR2 = path72.dirname(USER_SETTINGS_PATH);
329515
329579
  var DEFAULT_EXCLUDED_ENV_VARS = ["DEBUG", "DEBUG_MODE"];
329516
329580
  var MIGRATE_V2_OVERWRITE = true;
329581
+ var SETTINGS_VERSION = 2;
329582
+ var SETTINGS_VERSION_KEY = "$version";
329517
329583
  var MIGRATION_MAP = {
329518
329584
  accessibility: "ui.accessibility",
329519
329585
  allowedTools: "tools.allowed",
@@ -329639,6 +329705,12 @@ function setNestedProperty(obj, path109, value) {
329639
329705
  }
329640
329706
  __name(setNestedProperty, "setNestedProperty");
329641
329707
  function needsMigration(settings) {
329708
+ if (SETTINGS_VERSION_KEY in settings) {
329709
+ const version2 = settings[SETTINGS_VERSION_KEY];
329710
+ if (typeof version2 === "number" && version2 >= SETTINGS_VERSION) {
329711
+ return false;
329712
+ }
329713
+ }
329642
329714
  const hasV1Keys = Object.entries(MIGRATION_MAP).some(([v1Key, v2Path]) => {
329643
329715
  if (v1Key === v2Path || !(v1Key in settings)) {
329644
329716
  return false;
@@ -329659,6 +329731,11 @@ function migrateSettingsToV2(flatSettings) {
329659
329731
  const flatKeys = new Set(Object.keys(flatSettings));
329660
329732
  for (const [oldKey, newPath] of Object.entries(MIGRATION_MAP)) {
329661
329733
  if (flatKeys.has(oldKey)) {
329734
+ if (KNOWN_V2_CONTAINERS.has(oldKey) && typeof flatSettings[oldKey] === "object" && flatSettings[oldKey] !== null && !Array.isArray(flatSettings[oldKey])) {
329735
+ v2Settings[oldKey] = flatSettings[oldKey];
329736
+ flatKeys.delete(oldKey);
329737
+ continue;
329738
+ }
329662
329739
  setNestedProperty(v2Settings, newPath, flatSettings[oldKey]);
329663
329740
  flatKeys.delete(oldKey);
329664
329741
  }
@@ -329682,6 +329759,7 @@ function migrateSettingsToV2(flatSettings) {
329682
329759
  v2Settings[remainingKey] = newValue;
329683
329760
  }
329684
329761
  }
329762
+ v2Settings[SETTINGS_VERSION_KEY] = SETTINGS_VERSION;
329685
329763
  return v2Settings;
329686
329764
  }
329687
329765
  __name(migrateSettingsToV2, "migrateSettingsToV2");
@@ -329718,6 +329796,9 @@ function migrateSettingsToV1(v2Settings) {
329718
329796
  v2Keys.delete("mcpServers");
329719
329797
  }
329720
329798
  for (const remainingKey of v2Keys) {
329799
+ if (remainingKey === SETTINGS_VERSION_KEY) {
329800
+ continue;
329801
+ }
329721
329802
  const value = v2Settings[remainingKey];
329722
329803
  if (value === void 0) {
329723
329804
  continue;
@@ -329923,6 +330004,21 @@ function loadSettings(workspaceDir = process27.cwd()) {
329923
330004
  }
329924
330005
  settingsObject = migratedSettings;
329925
330006
  }
330007
+ } else if (!(SETTINGS_VERSION_KEY in settingsObject)) {
330008
+ settingsObject[SETTINGS_VERSION_KEY] = SETTINGS_VERSION;
330009
+ if (MIGRATE_V2_OVERWRITE) {
330010
+ try {
330011
+ fs70.writeFileSync(
330012
+ filePath,
330013
+ JSON.stringify(settingsObject, null, 2),
330014
+ "utf-8"
330015
+ );
330016
+ } catch (e2) {
330017
+ console.error(
330018
+ `Error adding version to settings file: ${getErrorMessage(e2)}`
330019
+ );
330020
+ }
330021
+ }
329926
330022
  }
329927
330023
  return { settings: settingsObject, rawJson: content };
329928
330024
  }
@@ -342023,7 +342119,7 @@ __name(getPackageJson, "getPackageJson");
342023
342119
  // packages/cli/src/utils/version.ts
342024
342120
  async function getCliVersion() {
342025
342121
  const pkgJson = await getPackageJson();
342026
- return "0.0.21-alpha.1";
342122
+ return "0.0.21";
342027
342123
  }
342028
342124
  __name(getCliVersion, "getCliVersion");
342029
342125
 
@@ -342476,24 +342572,24 @@ async function parseArguments(settings) {
342476
342572
  "\u4F7F\u7528\u65B9\u6CD5: rdmind [options] [command]\n\nRDMind - \u542F\u52A8\u4EA4\u4E92\u5F0F CLI\uFF0C\u4F7F\u7528 -p/--prompt \u8FDB\u5165\u975E\u4EA4\u4E92\u6A21\u5F0F"
342477
342573
  ).option("telemetry", {
342478
342574
  type: "boolean",
342479
- description: "\u542F\u7528\u9065\u6D4B\uFF1F\u63A7\u5236\u662F\u5426\u53D1\u9001\u9065\u6D4B\u6570\u636E"
342575
+ description: "Enable telemetry? This flag specifically controls if telemetry is sent. Other --telemetry-* flags set specific values but do not enable telemetry on their own."
342480
342576
  }).option("telemetry-target", {
342481
342577
  type: "string",
342482
342578
  choices: ["local", "gcp"],
342483
- description: "\u8BBE\u7F6E\u9065\u6D4B\u76EE\u6807"
342579
+ description: "Set the telemetry target (local or gcp). Overrides settings files."
342484
342580
  }).option("telemetry-otlp-endpoint", {
342485
342581
  type: "string",
342486
- description: "\u8BBE\u7F6E\u9065\u6D4B\u7684 OTLP \u7AEF\u70B9"
342582
+ description: "Set the OTLP endpoint for telemetry. Overrides environment variables and settings files."
342487
342583
  }).option("telemetry-otlp-protocol", {
342488
342584
  type: "string",
342489
342585
  choices: ["grpc", "http"],
342490
- description: "\u8BBE\u7F6E\u9065\u6D4B\u7684 OTLP \u534F\u8BAE"
342586
+ description: "Set the OTLP protocol for telemetry (grpc or http). Overrides settings files."
342491
342587
  }).option("telemetry-log-prompts", {
342492
342588
  type: "boolean",
342493
- description: "\u542F\u7528\u6216\u7981\u7528\u9065\u6D4B\u4E2D\u7528\u6237\u63D0\u793A\u8BCD\u7684\u65E5\u5FD7\u8BB0\u5F55"
342589
+ description: "Enable or disable logging of user prompts for telemetry. Overrides settings files."
342494
342590
  }).option("telemetry-outfile", {
342495
342591
  type: "string",
342496
- description: "\u5C06\u6240\u6709\u9065\u6D4B\u8F93\u51FA\u91CD\u5B9A\u5411\u5230\u6307\u5B9A\u6587\u4EF6"
342592
+ description: "Redirect all telemetry output to the specified file."
342497
342593
  }).deprecateOption(
342498
342594
  "telemetry",
342499
342595
  'Use the "telemetry.enabled" setting in settings.json instead. This flag will be removed in a future version.'
@@ -342531,52 +342627,52 @@ async function parseArguments(settings) {
342531
342627
  }).option("model", {
342532
342628
  alias: "m",
342533
342629
  type: "string",
342534
- description: `\u6A21\u578B`
342630
+ description: `Model`
342535
342631
  }).option("prompt", {
342536
342632
  alias: "p",
342537
342633
  type: "string",
342538
- description: "\u63D0\u793A\u8BCD"
342634
+ description: "Prompt. Appended to input on stdin (if any)."
342539
342635
  }).option("prompt-interactive", {
342540
342636
  alias: "i",
342541
342637
  type: "string",
342542
- description: "\u6839\u636E\u63D0\u4F9B\u7684\u63D0\u793A\u8BCD\u6267\u884C\u5E76\u7EE7\u7EED\u4EA4\u4E92\u6A21\u5F0F"
342638
+ description: "Execute the provided prompt and continue in interactive mode"
342543
342639
  }).option("sandbox", {
342544
342640
  alias: "s",
342545
342641
  type: "boolean",
342546
- description: "\u5728\u6C99\u76D2\u4E2D\u8FD0\u884C\uFF1F"
342642
+ description: "Run in sandbox?"
342547
342643
  }).option("sandbox-image", {
342548
342644
  type: "string",
342549
- description: "\u6C99\u76D2\u955C\u50CF"
342645
+ description: "Sandbox image URI."
342550
342646
  }).option("all-files", {
342551
342647
  alias: ["a"],
342552
342648
  type: "boolean",
342553
- description: "\u4E0A\u4E0B\u6587\u4E2D\u5305\u542B\u6240\u6709\u6587\u4EF6\uFF1F",
342649
+ description: "Include ALL files in context?",
342554
342650
  default: false
342555
342651
  }).option("show-memory-usage", {
342556
342652
  type: "boolean",
342557
- description: "\u72B6\u6001\u680F\u663E\u793A\u4F7F\u7528\u60C5\u51B5\uFF1F",
342653
+ description: "Show memory usage in status bar",
342558
342654
  default: false
342559
342655
  }).option("yolo", {
342560
342656
  alias: "y",
342561
342657
  type: "boolean",
342562
- description: "\u9ED8\u8BA4\u63A5\u53D7\u6240\u6709\u64CD\u4F5C\uFF08YOLO \u6A21\u5F0F\uFF09\uFF1F",
342658
+ description: "Automatically accept all actions (aka YOLO mode, see https://www.youtube.com/watch?v=xvFZjo5PgG0 for more details)?",
342563
342659
  default: false
342564
342660
  }).option("approval-mode", {
342565
342661
  type: "string",
342566
342662
  choices: ["plan", "default", "auto-edit", "yolo"],
342567
- description: "\u8BBE\u7F6E\u5BA1\u6279\u6A21\u5F0F\uFF1Aplan\uFF08\u53EA\u505A\u89C4\u5212\uFF09\u3001default\uFF08\u63D0\u793A\u786E\u8BA4\uFF09\u3001auto_edit\uFF08\u63A5\u53D7\u7F16\u8F91\uFF09\u3001yolo\uFF08\u63A5\u53D7\u6240\u6709\u5DE5\u5177\uFF09"
342663
+ description: "Set the approval mode: plan (plan only), default (prompt for approval), auto-edit (auto-approve edit tools), yolo (auto-approve all tools)"
342568
342664
  }).option("checkpointing", {
342569
342665
  alias: "c",
342570
342666
  type: "boolean",
342571
- description: "\u542F\u7528\u68C0\u67E5\u70B9\u529F\u80FD",
342667
+ description: "Enables checkpointing of file edits",
342572
342668
  default: false
342573
342669
  }).option("experimental-acp", {
342574
342670
  type: "boolean",
342575
- description: "\u5728 ACP \u6A21\u5F0F\u4E0B\u542F\u52A8\u4EE3\u7406"
342671
+ description: "Starts the agent in ACP mode"
342576
342672
  }).option("allowed-mcp-server-names", {
342577
342673
  type: "array",
342578
342674
  string: true,
342579
- description: "\u5141\u8BB8\u7684 MCP \u670D\u52A1\u540D\u79F0",
342675
+ description: "Allowed MCP server names",
342580
342676
  coerce: /* @__PURE__ */ __name((mcpServerNames) => (
342581
342677
  // Handle comma-separated values
342582
342678
  mcpServerNames.flatMap(
@@ -342586,7 +342682,7 @@ async function parseArguments(settings) {
342586
342682
  }).option("allowed-tools", {
342587
342683
  type: "array",
342588
342684
  string: true,
342589
- description: "\u65E0\u9700\u786E\u8BA4\u5373\u53EF\u8FD0\u884C\u7684\u5DE5\u5177",
342685
+ description: "Tools that are allowed to run without confirmation",
342590
342686
  coerce: /* @__PURE__ */ __name((tools) => (
342591
342687
  // Handle comma-separated values
342592
342688
  tools.flatMap((tool) => tool.split(",").map((t2) => t2.trim()))
@@ -342595,7 +342691,7 @@ async function parseArguments(settings) {
342595
342691
  alias: "e",
342596
342692
  type: "array",
342597
342693
  string: true,
342598
- description: "\u8981\u4F7F\u7528\u7684\u6269\u5C55\u5217\u8868\u3002\u672A\u63D0\u4F9B\u5219\u4F7F\u7528\u6240\u6709\u6269\u5C55",
342694
+ description: "A list of extensions to use. If not provided, all extensions are used.",
342599
342695
  coerce: /* @__PURE__ */ __name((extensions) => (
342600
342696
  // Handle comma-separated values
342601
342697
  extensions.flatMap(
@@ -342605,34 +342701,34 @@ async function parseArguments(settings) {
342605
342701
  }).option("list-extensions", {
342606
342702
  alias: "l",
342607
342703
  type: "boolean",
342608
- description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u6269\u5C55\u5E76\u9000\u51FA"
342704
+ description: "List all available extensions and exit."
342609
342705
  }).option("include-directories", {
342610
342706
  type: "array",
342611
342707
  string: true,
342612
- description: "\u5DE5\u4F5C\u533A\u4E2D\u7684\u989D\u5916\u76EE\u5F55\uFF08\u9017\u53F7\u5206\u9694\u6216\u591A\u4E2A --include-directories\uFF09",
342708
+ description: "Additional directories to include in the workspace (comma-separated or multiple --include-directories)",
342613
342709
  coerce: /* @__PURE__ */ __name((dirs) => (
342614
342710
  // Handle comma-separated values
342615
342711
  dirs.flatMap((dir) => dir.split(",").map((d) => d.trim()))
342616
342712
  ), "coerce")
342617
342713
  }).option("openai-logging", {
342618
342714
  type: "boolean",
342619
- description: "\u542F\u7528 OpenAI API \u8C03\u7528\u65E5\u5FD7\u8BB0\u5F55"
342715
+ description: "Enable logging of OpenAI API calls for debugging and analysis"
342620
342716
  }).option("openai-api-key", {
342621
342717
  type: "string",
342622
- description: "\u7528\u4E8E\u8EAB\u4EFD\u9A8C\u8BC1\u7684 OpenAI API \u5BC6\u94A5"
342718
+ description: "OpenAI API key to use for authentication"
342623
342719
  }).option("openai-base-url", {
342624
342720
  type: "string",
342625
- description: "OpenAI base URL"
342721
+ description: "OpenAI base URL (for custom endpoints)"
342626
342722
  }).option("tavily-api-key", {
342627
342723
  type: "string",
342628
- description: "Tavily API \u5BC6\u94A5"
342724
+ description: "Tavily API key for web search functionality"
342629
342725
  }).option("screen-reader", {
342630
342726
  type: "boolean",
342631
- description: "\u542F\u7528 screen-reader"
342727
+ description: "Enable screen reader mode for accessibility."
342632
342728
  }).option("vlm-switch-mode", {
342633
342729
  type: "string",
342634
342730
  choices: ["once", "session", "persist"],
342635
- description: "\u68C0\u6D4B\u5230\u8F93\u5165\u4E2D\u5305\u542B\u56FE\u50CF\u65F6\u7684\u9ED8\u8BA4\u884C\u4E3A\u3002\u53EF\u9009\u503C\uFF1Aonce\uFF08\u5207\u6362\u4E00\u6B21\uFF09\u3001session\uFF08\u6574\u4E2A\u4F1A\u8BDD\u671F\u95F4\u5207\u6362\uFF09\u3001persist\uFF08\u7EE7\u7EED\u4F7F\u7528\u5F53\u524D\u6A21\u578B\uFF09\u3002\u4F1A\u8986\u76D6\u8BBE\u7F6E\u6587\u4EF6\u7684\u914D\u7F6E",
342731
+ description: "Default behavior when images are detected in input. Values: once (one-time switch), session (switch for entire session), persist (continue with current model). Overrides settings files.",
342636
342732
  default: process.env["VLM_SWITCH_MODE"]
342637
342733
  }).option("output-format", {
342638
342734
  alias: "o",
@@ -342662,13 +342758,13 @@ async function parseArguments(settings) {
342662
342758
  const query = argv["query"];
342663
342759
  const hasPositionalQuery = Array.isArray(query) ? query.length > 0 : !!query;
342664
342760
  if (argv["prompt"] && hasPositionalQuery) {
342665
- return "\u4E0D\u80FD\u540C\u65F6\u4F7F\u7528\u4F4D\u7F6E\u53C2\u6570\u63D0\u793A\u8BCD\u548C --prompt (-p) \u6807\u5FD7";
342761
+ return "Cannot use both a positional prompt and the --prompt (-p) flag together";
342666
342762
  }
342667
342763
  if (argv["prompt"] && argv["promptInteractive"]) {
342668
- return "\u4E0D\u80FD\u540C\u65F6\u4F7F\u7528 --prompt (-p) \u548C --prompt-interactive (-i)";
342764
+ return "Cannot use both --prompt (-p) and --prompt-interactive (-i) together";
342669
342765
  }
342670
342766
  if (argv["yolo"] && argv["approvalMode"]) {
342671
- return "\u4E0D\u80FD\u540C\u65F6\u4F7F\u7528 --yolo (-y) \u548C --approval-mode\u3002\u8BF7\u4F7F\u7528 --approval-mode=yolo \u66FF\u4EE3";
342767
+ return "Cannot use both --yolo (-y) and --approval-mode together. Use --approval-mode=yolo instead.";
342672
342768
  }
342673
342769
  return true;
342674
342770
  })