@rdmind/rdmind 0.0.21-alpha.2 → 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 +586 -490
  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.2";
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 = "9f074b0b";
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.2";
342122
+ return "0.0.21";
342027
342123
  }
342028
342124
  __name(getCliVersion, "getCliVersion");
342029
342125
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rdmind/rdmind",
3
- "version": "0.0.21-alpha.2",
3
+ "version": "0.0.21",
4
4
  "description": "RDMind - AI-powered coding assistant",
5
5
  "type": "module",
6
6
  "main": "cli.js",
@@ -19,7 +19,7 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "config": {
22
- "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.21-alpha.2"
22
+ "sandboxImageUri": "ghcr.io/qwenlm/qwen-code:0.0.21"
23
23
  },
24
24
  "publishConfig": {
25
25
  "access": "public"