-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(core): Add support for Lingma AI IDE #535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- 在 AI 工具配置中注册 Lingma 选项 - 创建 Lingma 配置器实现工具特定配置逻辑 - 集成 Lingma 到工具注册表中统一管理 - 添加 Lingma 命令配置器支持工作流命令 - 注册 Lingma 命令到命令注册表中 - 实现 Lingma 规则文件自动生成和更新机制
📝 WalkthroughWalkthroughThis PR adds Lingma, a new AI IDE tool, to OpenSpec by introducing configuration classes that handle Lingma-specific setup, registering them in tool and slash-command registries, and listing Lingma in the available AI tools. Changes
Sequence DiagramsequenceDiagram
actor User
participant Registry
participant LingmaConfigurator
participant TemplateManager
participant FileSystemUtils
User->>Registry: Request Lingma configuration
Registry->>LingmaConfigurator: Instantiate & call configure()
LingmaConfigurator->>TemplateManager: Get OpenSpec standard template
TemplateManager-->>LingmaConfigurator: Return template content
LingmaConfigurator->>FileSystemUtils: Update file with markers
FileSystemUtils->>FileSystemUtils: Wrap content with OPENSPEC_MARKERS
FileSystemUtils->>FileSystemUtils: Prepend trigger config if file exists
FileSystemUtils-->>LingmaConfigurator: File write complete
LingmaConfigurator-->>User: Configuration applied
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review CompleteYour review story is ready! Comment !reviewfast on this PR to re-generate the story. |
|
TongYi Lingma AI ide official website |
Greptile SummaryThis PR adds support for Lingma AI IDE by implementing configurators for the main rules file and slash commands, following established patterns from other tool integrations.
Critical Issue: The main configurator ( Confidence Score: 1/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant CLI as OpenSpec CLI
participant Registry as ToolRegistry
participant Lingma as LingmaConfigurator
participant FS as FileSystemUtils
participant Template as TemplateManager
User->>CLI: openspec init --tool lingma
CLI->>Registry: getTool('lingma')
Registry->>Lingma: new LingmaConfigurator()
Registry-->>CLI: configurator
CLI->>Lingma: configure(projectPath, openspecDir)
Lingma->>Template: getAgentsStandardTemplate()
Template-->>Lingma: template content
Lingma->>FS: updateFileWithMarkers(filePath, content, markers)
alt File doesn't exist
FS->>FS: Create .lingma/rules/openspec-rules.md
FS->>FS: Write markers + content
else File exists
FS->>FS: Read existing file
FS->>FS: Update content between markers
end
FS-->>Lingma: void
Note over Lingma,FS: Bug: Current code reads file again<br/>and prepends frontmatter,<br/>causing duplication
Lingma->>FS: fileExists(filePath)
FS-->>Lingma: true
Lingma->>FS: readFile(filePath)
FS-->>Lingma: existing content
Lingma->>Lingma: Prepend frontmatter
Lingma->>FS: writeFile(filePath, frontmatter + content)
FS-->>Lingma: void
Lingma-->>CLI: void
CLI-->>User: ✓ Configured Lingma
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 files reviewed, 2 comments
| // Create trigger configuration for Lingma rules | ||
| const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | ||
| let existingContent = ''; | ||
| if (await FileSystemUtils.fileExists(filePath)) { | ||
| existingContent = await FileSystemUtils.readFile(filePath); | ||
| existingContent = lingmaRulesTrigger + existingContent; | ||
| await FileSystemUtils.writeFile(filePath, existingContent); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: This logic is backwards and will fail. The frontmatter is only added if the file already exists, but should be added when creating a new file. Additionally, the file is rewritten after updateFileWithMarkers has already written it, causing duplication or incorrect output.
Compare with other configurators like qwen.ts which simply call updateFileWithMarkers - that method already handles both creating new files and updating existing ones with proper marker placement.
| // Create trigger configuration for Lingma rules | |
| const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | |
| let existingContent = ''; | |
| if (await FileSystemUtils.fileExists(filePath)) { | |
| existingContent = await FileSystemUtils.readFile(filePath); | |
| existingContent = lingmaRulesTrigger + existingContent; | |
| await FileSystemUtils.writeFile(filePath, existingContent); | |
| } | |
| // updateFileWithMarkers handles both file creation and updates | |
| // For new files, it creates: frontmatter + markers + content | |
| // For existing files, it updates content between markers | |
| const frontmatter = `---\ntrigger: always_on\nalwaysApply: true\n---\n\n`; | |
| const fullContent = frontmatter + content; | |
| await FileSystemUtils.updateFileWithMarkers( | |
| filePath, | |
| fullContent, | |
| OPENSPEC_MARKERS.start, | |
| OPENSPEC_MARKERS.end | |
| ); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/core/configurators/lingma.ts
Line: 53:60
Comment:
**logic:** This logic is backwards and will fail. The frontmatter is only added if the file already exists, but should be added when creating a new file. Additionally, the file is rewritten after `updateFileWithMarkers` has already written it, causing duplication or incorrect output.
Compare with other configurators like `qwen.ts` which simply call `updateFileWithMarkers` - that method already handles both creating new files and updating existing ones with proper marker placement.
```suggestion
// updateFileWithMarkers handles both file creation and updates
// For new files, it creates: frontmatter + markers + content
// For existing files, it updates content between markers
const frontmatter = `---\ntrigger: always_on\nalwaysApply: true\n---\n\n`;
const fullContent = frontmatter + content;
await FileSystemUtils.updateFileWithMarkers(
filePath,
fullContent,
OPENSPEC_MARKERS.start,
OPENSPEC_MARKERS.end
);
```
How can I resolve this? If you propose a fix, please make it concise.| async configure(projectPath: string, openspecDir: string): Promise<void> { | ||
| // Construct full path to .lingma/rules/openspec-rules.md | ||
| const filePath = path.join(projectPath, this.configFileName); | ||
|
|
||
| // Combine trigger configuration with agent-standard instructions | ||
| const content = TemplateManager.getAgentsStandardTemplate(); | ||
|
|
||
| // Write or update file with managed content between markers | ||
| // This allows future updates to refresh instructions automatically | ||
| await FileSystemUtils.updateFileWithMarkers( | ||
| filePath, | ||
| content, | ||
| OPENSPEC_MARKERS.start, | ||
| OPENSPEC_MARKERS.end | ||
| ); | ||
|
|
||
| // Create trigger configuration for Lingma rules | ||
| const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | ||
| let existingContent = ''; | ||
| if (await FileSystemUtils.fileExists(filePath)) { | ||
| existingContent = await FileSystemUtils.readFile(filePath); | ||
| existingContent = lingmaRulesTrigger + existingContent; | ||
| await FileSystemUtils.writeFile(filePath, existingContent); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Logic error causes file corruption on updates. After updateFileWithMarkers writes the file (line 46-51), the code reads it back and prepends frontmatter again (line 56-59). On subsequent runs, this creates duplicate frontmatter blocks.
Additionally, frontmatter is only added if file exists after the initial write, which is backwards - it should be added during initial creation.
Fix: Handle new files and updates separately, like SlashCommandConfigurator does (see slash/base.ts:32-43).
| async configure(projectPath: string, openspecDir: string): Promise<void> { | |
| // Construct full path to .lingma/rules/openspec-rules.md | |
| const filePath = path.join(projectPath, this.configFileName); | |
| // Combine trigger configuration with agent-standard instructions | |
| const content = TemplateManager.getAgentsStandardTemplate(); | |
| // Write or update file with managed content between markers | |
| // This allows future updates to refresh instructions automatically | |
| await FileSystemUtils.updateFileWithMarkers( | |
| filePath, | |
| content, | |
| OPENSPEC_MARKERS.start, | |
| OPENSPEC_MARKERS.end | |
| ); | |
| // Create trigger configuration for Lingma rules | |
| const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | |
| let existingContent = ''; | |
| if (await FileSystemUtils.fileExists(filePath)) { | |
| existingContent = await FileSystemUtils.readFile(filePath); | |
| existingContent = lingmaRulesTrigger + existingContent; | |
| await FileSystemUtils.writeFile(filePath, existingContent); | |
| } | |
| } | |
| async configure(projectPath: string, openspecDir: string): Promise<void> { | |
| const filePath = path.join(projectPath, this.configFileName); | |
| const content = TemplateManager.getAgentsStandardTemplate(); | |
| const frontmatter = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | |
| if (await FileSystemUtils.fileExists(filePath)) { | |
| // Update existing file: only update content between markers | |
| await FileSystemUtils.updateFileWithMarkers( | |
| filePath, | |
| content, | |
| OPENSPEC_MARKERS.start, | |
| OPENSPEC_MARKERS.end | |
| ); | |
| } else { | |
| // Create new file: frontmatter + markers + content | |
| const fullContent = `${frontmatter}\n${OPENSPEC_MARKERS.start}\n${content}\n${OPENSPEC_MARKERS.end}\n`; | |
| await FileSystemUtils.writeFile(filePath, fullContent); | |
| } | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/core/configurators/lingma.ts
Line: 37:61
Comment:
**logic:** Logic error causes file corruption on updates. After `updateFileWithMarkers` writes the file (line 46-51), the code reads it back and prepends frontmatter again (line 56-59). On subsequent runs, this creates duplicate frontmatter blocks.
Additionally, frontmatter is only added if file exists after the initial write, which is backwards - it should be added during initial creation.
Fix: Handle new files and updates separately, like `SlashCommandConfigurator` does (see `slash/base.ts:32-43`).
```suggestion
async configure(projectPath: string, openspecDir: string): Promise<void> {
const filePath = path.join(projectPath, this.configFileName);
const content = TemplateManager.getAgentsStandardTemplate();
const frontmatter = `---\ntrigger: always_on\nalwaysApply: true\n---\n`;
if (await FileSystemUtils.fileExists(filePath)) {
// Update existing file: only update content between markers
await FileSystemUtils.updateFileWithMarkers(
filePath,
content,
OPENSPEC_MARKERS.start,
OPENSPEC_MARKERS.end
);
} else {
// Create new file: frontmatter + markers + content
const fullContent = `${frontmatter}\n${OPENSPEC_MARKERS.start}\n${content}\n${OPENSPEC_MARKERS.end}\n`;
await FileSystemUtils.writeFile(filePath, fullContent);
}
}
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/core/configurators/lingma.ts`:
- Around line 53-60: The configure() logic currently prepends the
lingmaRulesTrigger every run causing duplicate frontmatter; update the code that
uses FileSystemUtils.readFile/fileExists and filePath to first read the file (if
exists) and check whether the content already begins with or contains the exact
lingmaRulesTrigger string before prepending—only call FileSystemUtils.writeFile
to add the trigger when it is missing (i.e., make the prepend idempotent by
checking existingContent.includes(lingmaRulesTrigger) or
startsWith(lingmaRulesTrigger) and skip writing if present).
| // Create trigger configuration for Lingma rules | ||
| const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | ||
| let existingContent = ''; | ||
| if (await FileSystemUtils.fileExists(filePath)) { | ||
| existingContent = await FileSystemUtils.readFile(filePath); | ||
| existingContent = lingmaRulesTrigger + existingContent; | ||
| await FileSystemUtils.writeFile(filePath, existingContent); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent duplicated trigger blocks on repeat runs.
configure() prepends the YAML trigger every time, so repeated runs will stack multiple frontmatter blocks (Line 54–59). This makes the file grow and can break Lingma parsing.
🛠️ Suggested fix (idempotent trigger prepend)
- const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`;
- let existingContent = '';
- if (await FileSystemUtils.fileExists(filePath)) {
- existingContent = await FileSystemUtils.readFile(filePath);
- existingContent = lingmaRulesTrigger + existingContent;
- await FileSystemUtils.writeFile(filePath, existingContent);
- }
+ const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`;
+ if (await FileSystemUtils.fileExists(filePath)) {
+ const existingContent = await FileSystemUtils.readFile(filePath);
+ if (!existingContent.startsWith(lingmaRulesTrigger)) {
+ await FileSystemUtils.writeFile(filePath, lingmaRulesTrigger + existingContent);
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Create trigger configuration for Lingma rules | |
| const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | |
| let existingContent = ''; | |
| if (await FileSystemUtils.fileExists(filePath)) { | |
| existingContent = await FileSystemUtils.readFile(filePath); | |
| existingContent = lingmaRulesTrigger + existingContent; | |
| await FileSystemUtils.writeFile(filePath, existingContent); | |
| } | |
| // Create trigger configuration for Lingma rules | |
| const lingmaRulesTrigger = `---\ntrigger: always_on\nalwaysApply: true\n---\n`; | |
| if (await FileSystemUtils.fileExists(filePath)) { | |
| const existingContent = await FileSystemUtils.readFile(filePath); | |
| if (!existingContent.startsWith(lingmaRulesTrigger)) { | |
| await FileSystemUtils.writeFile(filePath, lingmaRulesTrigger + existingContent); | |
| } | |
| } |
🤖 Prompt for AI Agents
In `@src/core/configurators/lingma.ts` around lines 53 - 60, The configure() logic
currently prepends the lingmaRulesTrigger every run causing duplicate
frontmatter; update the code that uses FileSystemUtils.readFile/fileExists and
filePath to first read the file (if exists) and check whether the content
already begins with or contains the exact lingmaRulesTrigger string before
prepending—only call FileSystemUtils.writeFile to add the trigger when it is
missing (i.e., make the prepend idempotent by checking
existingContent.includes(lingmaRulesTrigger) or startsWith(lingmaRulesTrigger)
and skip writing if present).
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.