@opensumi/ide-ai-native 3.9.1-next-1748593694.0 → 3.9.1-next-1748943529.0

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 (118) hide show
  1. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  2. package/lib/browser/chat/chat-model.js +3 -1
  3. package/lib/browser/chat/chat-model.js.map +1 -1
  4. package/lib/browser/chat/chat-proxy.service.d.ts +0 -2
  5. package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
  6. package/lib/browser/chat/chat-proxy.service.js +50 -57
  7. package/lib/browser/chat/chat-proxy.service.js.map +1 -1
  8. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  9. package/lib/browser/chat/chat.view.js +11 -7
  10. package/lib/browser/chat/chat.view.js.map +1 -1
  11. package/lib/browser/components/ChatMentionInput.d.ts.map +1 -1
  12. package/lib/browser/components/ChatMentionInput.js +123 -27
  13. package/lib/browser/components/ChatMentionInput.js.map +1 -1
  14. package/lib/browser/components/ChatToolRender.module.less +1 -0
  15. package/lib/browser/components/components.module.less +7 -0
  16. package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -1
  17. package/lib/browser/components/mention-input/mention-input.js +155 -13
  18. package/lib/browser/components/mention-input/mention-input.js.map +1 -1
  19. package/lib/browser/components/mention-input/mention-input.module.less +165 -0
  20. package/lib/browser/components/mention-input/types.d.ts +15 -1
  21. package/lib/browser/components/mention-input/types.d.ts.map +1 -1
  22. package/lib/browser/components/mention-input/types.js +1 -0
  23. package/lib/browser/components/mention-input/types.js.map +1 -1
  24. package/lib/browser/context/llm-context.service.d.ts +21 -2
  25. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  26. package/lib/browser/context/llm-context.service.js +162 -20
  27. package/lib/browser/context/llm-context.service.js.map +1 -1
  28. package/lib/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.d.ts.map +1 -1
  29. package/lib/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.js.map +1 -1
  30. package/lib/browser/contrib/intelligent-completions/diff-computer.js +1 -1
  31. package/lib/browser/contrib/intelligent-completions/diff-computer.js.map +1 -1
  32. package/lib/browser/contrib/terminal/terminal.feature.registry.js.map +1 -1
  33. package/lib/browser/index.d.ts.map +1 -1
  34. package/lib/browser/index.js +7 -0
  35. package/lib/browser/index.js.map +1 -1
  36. package/lib/browser/mcp/base-apply.service.d.ts +2 -2
  37. package/lib/browser/mcp/base-apply.service.d.ts.map +1 -1
  38. package/lib/browser/mcp/base-apply.service.js.map +1 -1
  39. package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -1
  40. package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -1
  41. package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -1
  42. package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -1
  43. package/lib/browser/preferences/schema.d.ts.map +1 -1
  44. package/lib/browser/preferences/schema.js +5 -0
  45. package/lib/browser/preferences/schema.js.map +1 -1
  46. package/lib/browser/rules/rules.contribution.d.ts +29 -0
  47. package/lib/browser/rules/rules.contribution.d.ts.map +1 -0
  48. package/lib/browser/rules/rules.contribution.js +94 -0
  49. package/lib/browser/rules/rules.contribution.js.map +1 -0
  50. package/lib/browser/rules/rules.module.less +174 -0
  51. package/lib/browser/rules/rules.service.d.ts +25 -0
  52. package/lib/browser/rules/rules.service.d.ts.map +1 -0
  53. package/lib/browser/rules/rules.service.js +180 -0
  54. package/lib/browser/rules/rules.service.js.map +1 -0
  55. package/lib/browser/rules/rules.view.d.ts +3 -0
  56. package/lib/browser/rules/rules.view.d.ts.map +1 -0
  57. package/lib/browser/rules/rules.view.js +76 -0
  58. package/lib/browser/rules/rules.view.js.map +1 -0
  59. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  60. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  61. package/lib/common/MDC_PARSER_README.md +171 -0
  62. package/lib/common/index.d.ts +2 -0
  63. package/lib/common/index.d.ts.map +1 -1
  64. package/lib/common/index.js +2 -0
  65. package/lib/common/index.js.map +1 -1
  66. package/lib/common/llm-context.d.ts +19 -0
  67. package/lib/common/llm-context.d.ts.map +1 -1
  68. package/lib/common/llm-context.js.map +1 -1
  69. package/lib/common/mdc-parser.d.ts +60 -0
  70. package/lib/common/mdc-parser.d.ts.map +1 -0
  71. package/lib/common/mdc-parser.js +246 -0
  72. package/lib/common/mdc-parser.js.map +1 -0
  73. package/lib/common/prompts/context-prompt-provider.d.ts +0 -2
  74. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  75. package/lib/common/prompts/context-prompt-provider.js +35 -29
  76. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  77. package/lib/common/prompts/system-prompt.d.ts +2 -0
  78. package/lib/common/prompts/system-prompt.d.ts.map +1 -0
  79. package/lib/common/prompts/system-prompt.js +5 -0
  80. package/lib/common/prompts/system-prompt.js.map +1 -0
  81. package/lib/common/types.d.ts +7 -0
  82. package/lib/common/types.d.ts.map +1 -1
  83. package/lib/node/base-language-model.d.ts.map +1 -1
  84. package/lib/node/base-language-model.js.map +1 -1
  85. package/package.json +25 -24
  86. package/src/browser/chat/chat-model.ts +3 -1
  87. package/src/browser/chat/chat-proxy.service.ts +68 -81
  88. package/src/browser/chat/chat.view.tsx +19 -7
  89. package/src/browser/components/ChatMentionInput.tsx +143 -31
  90. package/src/browser/components/ChatToolRender.module.less +1 -0
  91. package/src/browser/components/components.module.less +7 -0
  92. package/src/browser/components/mention-input/mention-input.module.less +165 -0
  93. package/src/browser/components/mention-input/mention-input.tsx +244 -29
  94. package/src/browser/components/mention-input/types.ts +15 -0
  95. package/src/browser/context/llm-context.service.ts +182 -21
  96. package/src/browser/contrib/intelligent-completions/decoration/additions-deletions.decoration.ts +1 -1
  97. package/src/browser/contrib/intelligent-completions/diff-computer.ts +1 -1
  98. package/src/browser/contrib/terminal/terminal.feature.registry.ts +1 -1
  99. package/src/browser/index.ts +8 -0
  100. package/src/browser/mcp/base-apply.service.ts +0 -1
  101. package/src/browser/mcp/tools/getDiagnosticsByPath.ts +1 -1
  102. package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +1 -1
  103. package/src/browser/mcp/tools/handlers/ListDir.ts +1 -1
  104. package/src/browser/mcp/tools/runTerminalCmd.ts +1 -1
  105. package/src/browser/preferences/schema.ts +5 -0
  106. package/src/browser/rules/rules.contribution.ts +105 -0
  107. package/src/browser/rules/rules.module.less +174 -0
  108. package/src/browser/rules/rules.service.ts +189 -0
  109. package/src/browser/rules/rules.view.tsx +127 -0
  110. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +0 -1
  111. package/src/common/MDC_PARSER_README.md +171 -0
  112. package/src/common/index.ts +3 -0
  113. package/src/common/llm-context.ts +23 -0
  114. package/src/common/mdc-parser.ts +295 -0
  115. package/src/common/prompts/context-prompt-provider.ts +55 -40
  116. package/src/common/prompts/system-prompt.ts +2 -0
  117. package/src/common/types.ts +8 -0
  118. package/src/node/base-language-model.ts +0 -1
@@ -1,10 +1,10 @@
1
- import { DataContent } from 'ai';
2
-
3
1
  import { Autowired, Injectable } from '@opensumi/di';
2
+ import { PreferenceService } from '@opensumi/ide-core-browser';
4
3
  import { AppConfig } from '@opensumi/ide-core-browser/lib/react-providers/config-provider';
4
+ import { AINativeSettingSectionsId, IApplicationService, RulesServiceToken } from '@opensumi/ide-core-common';
5
5
  import { WithEventBus } from '@opensumi/ide-core-common/lib/event-bus/event-decorator';
6
6
  import { MarkerSeverity } from '@opensumi/ide-core-common/lib/types/markers/markers';
7
- import { Emitter, URI } from '@opensumi/ide-core-common/lib/utils';
7
+ import { Emitter, OperatingSystem, URI, parseGlob } from '@opensumi/ide-core-common/lib/utils';
8
8
  import {
9
9
  EditorDocumentModelCreationEvent,
10
10
  EditorDocumentModelRemovalEvent,
@@ -15,8 +15,12 @@ import { EditorSelectionChangeEvent } from '@opensumi/ide-editor/lib/browser/typ
15
15
  import { FileType, IFileServiceClient } from '@opensumi/ide-file-service';
16
16
  import { IMarkerService } from '@opensumi/ide-markers/lib/common/types';
17
17
  import { Range } from '@opensumi/ide-monaco';
18
+ import { ITerminalApiService } from '@opensumi/ide-terminal-next';
19
+ import { isString, match } from '@opensumi/ide-utils';
18
20
 
19
21
  import { AttachFileContext, FileContext, LLMContextService, SerializedContext } from '../../common/llm-context';
22
+ import { ProjectRule } from '../../common/types';
23
+ import { RulesService } from '../rules/rules.service';
20
24
 
21
25
  @Injectable()
22
26
  export class LLMContextServiceImpl extends WithEventBus implements LLMContextService {
@@ -32,6 +36,18 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
32
36
  @Autowired(IFileServiceClient)
33
37
  protected readonly fileService: IFileServiceClient;
34
38
 
39
+ @Autowired(RulesServiceToken)
40
+ protected readonly rulesService: RulesService;
41
+
42
+ @Autowired(PreferenceService)
43
+ protected readonly preferenceService: PreferenceService;
44
+
45
+ @Autowired(ITerminalApiService)
46
+ protected readonly terminalService: ITerminalApiService;
47
+
48
+ @Autowired(IApplicationService)
49
+ protected readonly applicationService: IApplicationService;
50
+
35
51
  private isAutoCollecting = false;
36
52
 
37
53
  private contextVersion = 0;
@@ -41,11 +57,13 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
41
57
  private readonly maxViewFilesLimit = 20;
42
58
  private attachedFiles: FileContext[] = [];
43
59
  private attachedFolders: FileContext[] = [];
60
+ private attachedRules: ProjectRule[] = [];
44
61
  private readonly recentlyViewFiles: FileContext[] = [];
45
62
  private readonly onDidContextFilesChangeEmitter = new Emitter<{
46
63
  viewed: FileContext[];
47
64
  attached: FileContext[];
48
65
  attachedFolders: FileContext[];
66
+ attachedRules: ProjectRule[];
49
67
  version: number;
50
68
  }>();
51
69
  private hasUserManualReference = false;
@@ -80,6 +98,24 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
80
98
  }
81
99
  }
82
100
 
101
+ addRuleToContext(uri: URI): void {
102
+ if (!uri) {
103
+ return;
104
+ }
105
+
106
+ if (this.attachedRules.some((rule) => rule.path === uri.toString())) {
107
+ return;
108
+ }
109
+
110
+ const rule = this.rulesService.projectRules.find((rule) => rule.path === uri.toString());
111
+ if (!rule) {
112
+ return;
113
+ }
114
+
115
+ this.attachedRules.push(rule);
116
+ this.notifyContextChange();
117
+ }
118
+
83
119
  addFileToContext(uri: URI, selection?: [number, number], isManual = false): void {
84
120
  if (!uri) {
85
121
  return;
@@ -117,6 +153,7 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
117
153
  this.attachedFiles = [];
118
154
  this.attachedFolders = [];
119
155
  this.hasUserManualReference = false;
156
+ this.attachedRules = [];
120
157
  this.notifyContextChange();
121
158
  }
122
159
 
@@ -125,6 +162,7 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
125
162
  viewed: this.recentlyViewFiles,
126
163
  attached: this.attachedFiles,
127
164
  attachedFolders: this.attachedFolders,
165
+ attachedRules: this.attachedRules,
128
166
  version: this.contextVersion++,
129
167
  };
130
168
  }
@@ -143,6 +181,24 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
143
181
  this.notifyContextChange();
144
182
  }
145
183
 
184
+ removeFolderFromContext(uri: URI): void {
185
+ const targetList = this.attachedFolders;
186
+ const index = targetList.findIndex((folder) => folder.uri.toString() === uri.toString());
187
+ if (index > -1) {
188
+ targetList.splice(index, 1);
189
+ }
190
+ this.notifyContextChange();
191
+ }
192
+
193
+ removeRuleFromContext(uri: URI): void {
194
+ const targetList = this.attachedRules;
195
+ const index = targetList.findIndex((rule) => rule.path === uri.toString());
196
+ if (index > -1) {
197
+ targetList.splice(index, 1);
198
+ }
199
+ this.notifyContextChange();
200
+ }
201
+
146
202
  startAutoCollection(): void {
147
203
  if (this.isAutoCollecting) {
148
204
  return;
@@ -217,25 +273,35 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
217
273
  return {
218
274
  recentlyViewFiles: this.serializeRecentlyViewFiles(files.viewed, workspaceRoot),
219
275
  attachedFiles: this.serializeAttachedFiles(files.attached, workspaceRoot),
220
- attachedFolders: await this.serializeAttachedFolders(files.attachedFolders, workspaceRoot),
276
+ attachedFolders: await this.serializeAttachedFolders(files.attachedFolders),
277
+ attachedRules: this.serializeAttachedRules(files.attachedRules),
278
+ globalRules: this.serializeGlobalRules(),
221
279
  };
222
280
  }
223
281
 
224
- private async serializeAttachedFolders(folders: FileContext[], workspaceRoot: URI): Promise<string[]> {
282
+ private async serializeAttachedFolders(folders: FileContext[]): Promise<string[]> {
225
283
  // 去重
226
284
  const folderPath = Array.from(new Set(folders.map((folder) => folder.uri.toString())));
227
- return Promise.all(
285
+ const header = 'Here are some folder(s) I manually attached to my message:';
286
+ const folderSections = await Promise.all(
228
287
  folderPath.map(async (folder) => {
229
288
  const folderUri = new URI(folder);
230
- const root = workspaceRoot.relative(folderUri)?.toString() || '/';
231
- return `\`\`\`\n${root}\n${(await this.getPartiaFolderStructure(folderUri.codeUri.fsPath))
232
- .map((line) => `- ${line}`)
233
- .join('\n')}\n\`\`\`\n`;
289
+ const absolutePath = folderUri.codeUri.fsPath;
290
+ const folderStructure = await this.getFormattedFolderStructure(absolutePath);
291
+
292
+ return `Folder: ${absolutePath}
293
+ Contents of directory:
294
+
295
+ ${folderStructure}`;
234
296
  }),
235
297
  );
298
+ if (folderSections.length > 0) {
299
+ return [header, ...folderSections, ''];
300
+ }
301
+ return [];
236
302
  }
237
303
 
238
- private async getPartiaFolderStructure(folder: string, level = 2): Promise<string[]> {
304
+ private async getFormattedFolderStructure(folder: string): Promise<string> {
239
305
  const result: string[] = [];
240
306
  try {
241
307
  const stat = await this.fileService.getFileStat(folder);
@@ -247,28 +313,27 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
247
313
  // 处理软链接
248
314
  const target = await this.fileService.getFileStat(child.realUri || child.uri);
249
315
  if (target) {
250
- result.push(`${relativePath} -> ${target} (symbolic link)`);
316
+ result.push(`[link] ${relativePath} -> ${target}`);
251
317
  } else {
252
- result.push(`${relativePath} (broken symbolic link)`);
318
+ result.push(`[link] ${relativePath} (broken)`);
253
319
  }
254
320
  continue;
255
321
  }
256
322
 
257
323
  if (child.type === FileType.Directory) {
258
- result.push(`${relativePath}/`);
259
- if (level > 1) {
260
- const subDirStructure = await this.getPartiaFolderStructure(child.uri, level - 1);
261
- result.push(...subDirStructure.map((subEntry) => `${relativePath}/${subEntry}`));
262
- }
324
+ // 计算目录下的项目数量
325
+ const childStat = await this.fileService.getFileStat(child.uri);
326
+ const itemCount = childStat?.children?.length || 0;
327
+ result.push(`[dir] ${relativePath}/ (${itemCount} items)`);
263
328
  } else if (child.type === FileType.File) {
264
- result.push(relativePath);
329
+ result.push(`[file] ${relativePath}`);
265
330
  }
266
331
  }
267
332
  } catch {
268
- return result;
333
+ return '';
269
334
  }
270
335
 
271
- return result;
336
+ return result.join('\n');
272
337
  }
273
338
 
274
339
  private serializeRecentlyViewFiles(files: FileContext[], workspaceRoot: URI): string[] {
@@ -295,6 +360,7 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
295
360
  lineErrors: this.getFileErrors(file.uri),
296
361
  path: workspaceRoot.relative(file.uri)!.toString(),
297
362
  language: ref.instance.languageId!,
363
+ selection: file.selection,
298
364
  };
299
365
  } catch (e) {
300
366
  return null;
@@ -310,4 +376,99 @@ export class LLMContextServiceImpl extends WithEventBus implements LLMContextSer
310
376
  })
311
377
  .map((marker) => marker.message);
312
378
  }
379
+
380
+ private serializeGlobalRules(): string[] {
381
+ const globalRules = this.preferenceService.get<string>(AINativeSettingSectionsId.GlobalRules);
382
+ if (!globalRules) {
383
+ return [];
384
+ }
385
+
386
+ const platform =
387
+ this.applicationService.backendOS === OperatingSystem.Windows
388
+ ? 'windows'
389
+ : this.applicationService.backendOS === OperatingSystem.Linux
390
+ ? 'linux'
391
+ : 'darwin';
392
+ const shell = this.preferenceService.get<string>('terminal.type', 'zsh');
393
+ let shellName = shell;
394
+ if (shell === 'default') {
395
+ shellName = this.applicationService.backendOS === OperatingSystem.Windows ? 'cmd' : 'zsh';
396
+ }
397
+ const userInfoSection = `<user_info>
398
+ The user's OS version is ${platform}. The absolute path of the user's workspace is ${this.appConfig.workspaceDir}. The user's shell is /bin/${shellName}.
399
+ </user_info>`;
400
+
401
+ const rulesSection = `
402
+
403
+ <rules>
404
+ The rules section has a number of possible rules/memories/context that you should consider. In each subsection, we provide instructions about what information the subsection contains and how you should consider/follow the contents of the subsection.
405
+
406
+
407
+ <user_specific_rule description="This is a rule set by the user that the agent must follow.">
408
+ ${globalRules}
409
+ </user_specific_rule>
410
+
411
+ </rules>`;
412
+
413
+ return [userInfoSection, rulesSection];
414
+ }
415
+
416
+ private findApplicableRules(attachedRules: ProjectRule[]): ProjectRule[] {
417
+ const otherRules = this.rulesService.projectRules.filter(
418
+ (rule) => !attachedRules.some((attachedRule) => attachedRule.path === rule.path),
419
+ );
420
+ const requestedByAgentRules = otherRules.filter((rule) => rule.description);
421
+ const alwaysApplyRules = otherRules.filter((rule) => rule.alwaysApply);
422
+ const requestedByFileRules = this.findFileMatchingRules(otherRules);
423
+
424
+ return [...requestedByFileRules, ...requestedByAgentRules, ...alwaysApplyRules];
425
+ }
426
+ private findFileMatchingRules(otherRules: ProjectRule[]): ProjectRule[] {
427
+ const requestedByFileRules = otherRules.filter((rule) => rule.globs);
428
+ const filePaths = this.attachedFiles.map((file) => file.uri.toString());
429
+ const folderPaths = this.attachedFolders.map((folder) => folder.uri.toString());
430
+
431
+ return requestedByFileRules.filter((rule) => {
432
+ let globs = rule.globs;
433
+ if (isString(globs)) {
434
+ globs = this.normalizeGlobs(globs.split(','));
435
+ } else {
436
+ globs = this.normalizeGlobs(globs || []);
437
+ }
438
+ const patterns = globs.map((pattern) => parseGlob(pattern));
439
+ return patterns.some((match) => filePaths.some((path) => match(path)) || folderPaths.some((path) => match(path)));
440
+ });
441
+ }
442
+ private normalizeGlobs(globs: string | string[]): string[] {
443
+ const globArray = isString(globs) ? globs.split(',') : globs || [];
444
+ return globArray.map((glob) => {
445
+ const p = glob.trim();
446
+ return p.startsWith('**') ? p : `**/${p}`;
447
+ });
448
+ }
449
+
450
+ private serializeAttachedRules(rules: ProjectRule[] = []): string[] {
451
+ rules = this.findApplicableRules(rules);
452
+ if (rules.length === 0) {
453
+ return [];
454
+ }
455
+
456
+ const header =
457
+ '\n<rules_context>\n\nRules are extra documentation provided by the user to help the AI understand the codebase.\nUse them if they seem useful to the users most recent query, but do not use them if they seem unrelated.\n\n';
458
+
459
+ const rulesSections = rules
460
+ .map((rule) => {
461
+ const ruleName =
462
+ rule.path
463
+ .split('/')
464
+ .pop()
465
+ ?.replace(/.md(c)?$/, '') || 'Unnamed Rule';
466
+ return `Rule Name: ${ruleName}\nDescription: \n${rule.description || rule.content}`;
467
+ })
468
+ .join('\n\n');
469
+
470
+ const footer = '\n</rules_context>\n';
471
+
472
+ return [header, rulesSections, footer];
473
+ }
313
474
  }
@@ -1,4 +1,4 @@
1
- import { ICodeEditor, IModelDeltaDecoration, IRange, TrackedRangeStickiness } from '@opensumi/ide-monaco';
1
+ import { ICodeEditor, IRange, TrackedRangeStickiness } from '@opensumi/ide-monaco';
2
2
 
3
3
  import { EnhanceDecorationsCollection } from '../../../model/enhanceDecorationsCollection';
4
4
  import { REWRITE_DECORATION_INLINE_ADD } from '../../../widget/rewrite/rewrite-widget';
@@ -267,7 +267,7 @@ export const computeMultiLineDiffChanges = (
267
267
  lineNumber: number,
268
268
  eol: string,
269
269
  ) => {
270
- let rewriteDiffResult: IMultiLineDiffChangeResult[] =
270
+ const rewriteDiffResult: IMultiLineDiffChangeResult[] =
271
271
  rewriteDiffComputer.diff(originalContent, modifiedContent) || [];
272
272
  let multiLineDiffResult: IMultiLineDiffChangeResult[] =
273
273
  multiLineDiffComputer.diff(originalContent, modifiedContent) || [];
@@ -1,6 +1,6 @@
1
1
  import { Injectable } from '@opensumi/di';
2
2
  import { CancellationToken, Disposable } from '@opensumi/ide-core-common';
3
- import { IReadableStream, isReadableStream, listenGroupReadable, listenReadable } from '@opensumi/ide-utils/lib/stream';
3
+ import { IReadableStream, isReadableStream, listenGroupReadable } from '@opensumi/ide-utils/lib/stream';
4
4
 
5
5
  import { ITerminalCommandSuggestionDesc } from '../../../common/index';
6
6
  import {
@@ -17,6 +17,7 @@ import {
17
17
  IntelligentCompletionsRegistryToken,
18
18
  MCPConfigServiceToken,
19
19
  ProblemFixRegistryToken,
20
+ RulesServiceToken,
20
21
  TerminalRegistryToken,
21
22
  } from '@opensumi/ide-core-common';
22
23
  import { FolderFilePreferenceProvider } from '@opensumi/ide-preferences/lib/browser/folder-file-preference-provider';
@@ -77,6 +78,8 @@ import { ListDirTool } from './mcp/tools/listDir';
77
78
  import { ReadFileTool } from './mcp/tools/readFile';
78
79
  import { RunTerminalCommandTool } from './mcp/tools/runTerminalCmd';
79
80
  import { AINativePreferencesContribution } from './preferences';
81
+ import { RulesContribution } from './rules/rules.contribution';
82
+ import { RulesService } from './rules/rules.service';
80
83
  import { AINativeCoreContribution, MCPServerContribution, TokenMCPServerRegistry } from './types';
81
84
  import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
82
85
  import { InlineChatService } from './widget/inline-chat/inline-chat.service';
@@ -119,6 +122,7 @@ export class AINativeModule extends BrowserModule {
119
122
 
120
123
  // Context Service
121
124
  LlmContextContribution,
125
+ RulesContribution,
122
126
  {
123
127
  token: LLMContextServiceToken,
124
128
  useClass: LLMContextServiceImpl,
@@ -216,6 +220,10 @@ export class AINativeModule extends BrowserModule {
216
220
  token: MCPConfigServiceToken,
217
221
  useClass: MCPConfigService,
218
222
  },
223
+ {
224
+ token: RulesServiceToken,
225
+ useClass: RulesService,
226
+ },
219
227
  {
220
228
  token: FolderFilePreferenceProvider,
221
229
  useClass: MCPFolderPreferenceProvider,
@@ -8,7 +8,6 @@ import {
8
8
  AppConfig,
9
9
  IAIReporter,
10
10
  IChatProgress,
11
- IMarker,
12
11
  MarkerSeverity,
13
12
  OnEvent,
14
13
  WithEventBus,
@@ -2,7 +2,7 @@ import * as path from 'path';
2
2
 
3
3
  import { z } from 'zod';
4
4
 
5
- import { Autowired, Injectable } from '@opensumi/di';
5
+ import { Autowired } from '@opensumi/di';
6
6
  import { Domain, URI } from '@opensumi/ide-core-common';
7
7
  import { IWorkspaceService } from '@opensumi/ide-workspace';
8
8
  import { URI as MonacoURI } from '@opensumi/monaco-editor-core/esm/vs/base/common/uri';
@@ -2,7 +2,7 @@ import * as path from 'path';
2
2
 
3
3
  import { z } from 'zod';
4
4
 
5
- import { Autowired, Injectable } from '@opensumi/di';
5
+ import { Autowired } from '@opensumi/di';
6
6
  import { Domain, URI } from '@opensumi/ide-core-common';
7
7
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
8
8
  import { IWorkspaceService } from '@opensumi/ide-workspace';
@@ -1,5 +1,5 @@
1
1
  import { Autowired, Injectable } from '@opensumi/di';
2
- import { AppConfig, Throttler, URI } from '@opensumi/ide-core-browser';
2
+ import { AppConfig, URI } from '@opensumi/ide-core-browser';
3
3
  import { IFileServiceClient } from '@opensumi/ide-file-service';
4
4
 
5
5
  /**
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
 
3
3
  import { Autowired } from '@opensumi/di';
4
4
  import { AppConfig } from '@opensumi/ide-core-browser';
5
- import { Deferred, Domain } from '@opensumi/ide-core-common';
5
+ import { Domain } from '@opensumi/ide-core-common';
6
6
  import { ITerminalController, ITerminalGroupViewService } from '@opensumi/ide-terminal-next/lib/common/controller';
7
7
 
8
8
  import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
@@ -177,5 +177,10 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
177
177
  type: 'string',
178
178
  description: '%preference.ai.native.chat.system.prompt.description%',
179
179
  },
180
+ [AINativeSettingSectionsId.GlobalRules]: {
181
+ type: 'string',
182
+ default: '',
183
+ description: '%preference.ai.native.globalRules.description%',
184
+ },
180
185
  },
181
186
  };
@@ -0,0 +1,105 @@
1
+ import { Autowired } from '@opensumi/di';
2
+ import { getIcon } from '@opensumi/ide-components';
3
+ import { ClientAppContribution } from '@opensumi/ide-core-browser';
4
+ import { LabelService } from '@opensumi/ide-core-browser/lib/services';
5
+ import {
6
+ CommandContribution,
7
+ CommandRegistry,
8
+ Domain,
9
+ RulesServiceToken,
10
+ URI,
11
+ localize,
12
+ } from '@opensumi/ide-core-common';
13
+ import {
14
+ BrowserEditorContribution,
15
+ EditorComponentRegistry,
16
+ EditorComponentRenderMode,
17
+ IResource,
18
+ ResourceService,
19
+ WorkbenchEditorService,
20
+ } from '@opensumi/ide-editor/lib/browser/types';
21
+ import { IconService } from '@opensumi/ide-theme/lib/browser';
22
+ import { IWorkspaceService } from '@opensumi/ide-workspace/lib/common';
23
+
24
+ import { RulesService } from './rules.service';
25
+ import { RulesView } from './rules.view';
26
+
27
+ export namespace RulesCommands {
28
+ export const OPEN_RULES_FILE = {
29
+ id: 'rules.openRulesConfig',
30
+ label: 'Open Rules Configuration',
31
+ };
32
+ }
33
+
34
+ const COMPONENTS_ID = 'opensumi-rules-viewer';
35
+ export const RULES_COMPONENTS_SCHEME_ID = 'rules';
36
+
37
+ export type IRulesResource = IResource<{ configType: string }>;
38
+
39
+ @Domain(BrowserEditorContribution, CommandContribution, ClientAppContribution)
40
+ export class RulesContribution implements BrowserEditorContribution, CommandContribution, ClientAppContribution {
41
+ @Autowired(IWorkspaceService)
42
+ protected readonly workspaceService: IWorkspaceService;
43
+
44
+ @Autowired(IconService)
45
+ protected readonly iconService: IconService;
46
+
47
+ @Autowired(WorkbenchEditorService)
48
+ protected readonly editorService: WorkbenchEditorService;
49
+
50
+ @Autowired()
51
+ labelService: LabelService;
52
+
53
+ @Autowired(RulesServiceToken)
54
+ protected readonly rulesService: RulesService;
55
+
56
+ onStart() {
57
+ this.rulesService.initProjectRules();
58
+ }
59
+
60
+ registerEditorComponent(registry: EditorComponentRegistry) {
61
+ registry.registerEditorComponent({
62
+ uid: COMPONENTS_ID,
63
+ scheme: RULES_COMPONENTS_SCHEME_ID,
64
+ component: RulesView,
65
+ renderMode: EditorComponentRenderMode.ONE_PER_WORKBENCH,
66
+ });
67
+
68
+ registry.registerEditorComponentResolver(RULES_COMPONENTS_SCHEME_ID, (resource, results) => {
69
+ results.push({
70
+ type: 'component',
71
+ componentId: COMPONENTS_ID,
72
+ });
73
+ });
74
+ }
75
+
76
+ registerResource(service: ResourceService) {
77
+ service.registerResourceProvider({
78
+ scheme: RULES_COMPONENTS_SCHEME_ID,
79
+ provideResource: async (uri: URI): Promise<IRulesResource> => {
80
+ const { configType } = uri.getParsedQuery();
81
+
82
+ return {
83
+ uri,
84
+ name: localize('ai.native.rules.title'),
85
+ icon: getIcon('rules'),
86
+ metadata: {
87
+ configType,
88
+ },
89
+ };
90
+ },
91
+ });
92
+ }
93
+
94
+ registerCommands(registry: CommandRegistry) {
95
+ registry.registerCommand(RulesCommands.OPEN_RULES_FILE, {
96
+ execute: () => {
97
+ const uri = new URI().withScheme(RULES_COMPONENTS_SCHEME_ID);
98
+ this.editorService.open(uri, {
99
+ preview: false,
100
+ focus: true,
101
+ });
102
+ },
103
+ });
104
+ }
105
+ }