-
Notifications
You must be signed in to change notification settings - Fork 4.6k
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,62 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import path from 'path'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { ToolConfigurator } from './base.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { FileSystemUtils } from '../../utils/file-system.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { TemplateManager } from '../templates/index.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { OPENSPEC_MARKERS } from '../config.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Lingma IDE AI Tool Configurator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Configures OpenSpec integration for Lingma IDE AI coding assistant. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Creates and manages .lingma/rules/openspec-rules.md configuration file with OpenSpec instructions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @implements {ToolConfigurator} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export class LingmaConfigurator implements ToolConfigurator { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Display name for the Lingma tool */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name = 'Lingma'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Configuration file name in .lingma/rules directory */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configFileName = '.lingma/rules/openspec-rules.md'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** Indicates tool is available for configuration */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isAvailable = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Configure Lingma integration for a project | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Creates or updates .lingma/rules/openspec-rules.md file with OpenSpec instructions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Includes trigger configuration for automatic application. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Uses agent-standard template for instruction content. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Wrapped with OpenSpec markers for future updates. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {string} projectPath - Absolute path to project root directory | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {string} openspecDir - Path to openspec directory (unused but required by interface) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {Promise<void>} Resolves when configuration is complete | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (await FileSystemUtils.fileExists(filePath)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const existingContent = await FileSystemUtils.readFile(filePath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!existingContent.startsWith(lingmaRulesTrigger)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await FileSystemUtils.writeFile(filePath, lingmaRulesTrigger + existingContent); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
lifegoon marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+37
to
+61
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Logic error causes file corruption on updates. After 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
Suggested change
Prompt To Fix With AIThis 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. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import { SlashCommandConfigurator } from './base.js'; | ||
| import { SlashCommandId } from '../../templates/index.js'; | ||
|
|
||
| /** | ||
| * File paths for Lingma slash commands | ||
| * Maps each OpenSpec workflow stage to its command file location | ||
| * Commands are stored in .lingma/rules/workflows/ directory | ||
| */ | ||
| const FILE_PATHS: Record<SlashCommandId, string> = { | ||
| // Create and validate new change proposals | ||
| proposal: '.lingma/rules/workflows/openspec-proposal.md', | ||
|
|
||
| // Implement approved changes with task tracking | ||
| apply: '.lingma/rules/workflows/openspec-apply.md', | ||
|
|
||
| // Archive completed changes and update specs | ||
| archive: '.lingma/rules/workflows/openspec-archive.md' | ||
| }; | ||
|
|
||
| /** | ||
| * Lingma Slash Command Configurator | ||
| * | ||
| * Manages OpenSpec slash commands for Lingma IDE AI assistant. | ||
| * Creates three workflow commands: proposal, apply, and archive. | ||
| * Uses manual trigger configuration for command execution. | ||
| * | ||
| * @extends {SlashCommandConfigurator} | ||
| */ | ||
| export class LingmaSlashCommandConfigurator extends SlashCommandConfigurator { | ||
| /** Unique identifier for Lingma tool */ | ||
| readonly toolId = 'lingma'; | ||
|
|
||
| /** Indicates slash commands are available for this tool */ | ||
| readonly isAvailable = true; | ||
|
|
||
| /** | ||
| * Get relative file path for a slash command | ||
| * | ||
| * @param {SlashCommandId} id - Command identifier (proposal, apply, or archive) | ||
| * @returns {string} Relative path from project root to command file | ||
| */ | ||
| protected getRelativePath(id: SlashCommandId): string { | ||
| return FILE_PATHS[id]; | ||
| } | ||
|
|
||
| /** | ||
| * Get frontmatter and header for a slash command | ||
| * | ||
| * Includes manual trigger configuration and OpenSpec command instructions. | ||
| * The trigger setting ensures commands are executed manually by the user. | ||
| * | ||
| * @param {SlashCommandId} id - Command identifier (proposal, apply, or archive) | ||
| * @returns {string | undefined} Manual trigger configuration and command header | ||
| */ | ||
| protected getFrontmatter(id: SlashCommandId): string | undefined { | ||
| // Define descriptions for each command type | ||
| const descriptions: Record<SlashCommandId, string> = { | ||
| proposal: 'Scaffold a new OpenSpec change and validate strictly.', | ||
| apply: 'Implement an approved OpenSpec change and keep tasks in sync.', | ||
| archive: 'Archive a deployed OpenSpec change and update specs.' | ||
| }; | ||
|
|
||
| // Create manual trigger configuration for Lingma rules | ||
| const lingmaRulesTrigger = `---\ntrigger: manual\n---\n`; | ||
|
|
||
| // Get the appropriate description for the command | ||
| const description = descriptions[id]; | ||
|
|
||
| // Combine trigger configuration with command header and description | ||
| return `${lingmaRulesTrigger}# OpenSpec: ${id.charAt(0).toUpperCase() + id.slice(1)}\n\n${description}`; | ||
| } | ||
| } |
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
updateFileWithMarkershas already written it, causing duplication or incorrect output.Compare with other configurators like
qwen.tswhich simply callupdateFileWithMarkers- that method already handles both creating new files and updating existing ones with proper marker placement.Prompt To Fix With AI