Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 116 additions & 2 deletions cli/src/commands/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@ const IDE_CONFIGS: Record<string, IdeConfig> = {
common: { commandsDir: '.agents/commands', skillsDir: '.agents/skills' },
};

// Entry file templates configuration
const ENTRY_TEMPLATES = {
AGENTS: {
template: 'AGENTS.md.template',
output: 'AGENTS.md',
displayName: 'AGENTS.md (通用入口文件)',
},
CLAUDE: {
template: 'CLAUDE.md.template',
output: 'CLAUDE.md',
displayName: 'CLAUDE.md (Claude Code 入口文件)',
},
CURSOR: {
template: 'cursor-rule.mdc.template',
outputDir: '.cursor/rules',
output: 'openmemory.mdc',
displayName: '.cursor/rules/openmemory.mdc (Cursor 规则文件)',
},
} as const;

const BANNER = `
╔═══════════════════════════════════════════════════════════════╗
║ ║
Expand Down Expand Up @@ -389,11 +409,101 @@ agent:
`;
}

function processTemplate(content: string, projectName: string): string {
function processTemplate(content: string, projectName: string, ideList?: string[]): string {
const now = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
return content
.replace(/\{\{PROJECT_NAME\}\}/g, projectName)
.replace(/\{\{CREATED_AT\}\}/g, now);
.replace(/\{\{CREATED_AT\}\}/g, now)
.replace(/\{\{IDE_LIST\}\}/g, ideList?.join(', ') || 'common');
}

// ============================================================================
// Entry File Generation
// ============================================================================

/**
* Generate entry files (AGENTS.md, CLAUDE.md, etc.) based on selected IDEs
* Entry files are what AI agents read at startup to understand the project
*/
function generateEntryFiles(
targetDir: string,
projectName: string,
selectedIdes: string[],
templatesDir: string,
force: boolean
): void {
const entryTemplatesDir = join(templatesDir, 'entry');

// Check if entry templates exist
if (!existsSync(entryTemplatesDir)) {
console.log(chalk.yellow(' ⚠ 入口文件模板不存在,跳过生成'));
return;
}

// Helper function to safely generate entry file
const generateFile = (
templatePath: string,
targetPath: string,
displayName: string,
createDir?: string
): void => {
try {
if (!existsSync(templatePath)) {
return;
}

if (!existsSync(targetPath) || force) {
if (createDir) {
mkdirSync(createDir, { recursive: true });
}
const template = readFileSync(templatePath, 'utf-8');
const content = processTemplate(template, projectName, selectedIdes);
writeFileSync(targetPath, content);
console.log(chalk.green(` ✓ 创建 ${displayName}`));
} else {
console.log(chalk.gray(` ○ ${displayName} 已存在 (使用 --force 覆盖)`));
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.log(chalk.red(` ✗ 创建 ${displayName} 失败: ${errorMessage}`));
}
};

// Always generate AGENTS.md (universal entry file)
generateFile(
join(entryTemplatesDir, ENTRY_TEMPLATES.AGENTS.template),
join(targetDir, ENTRY_TEMPLATES.AGENTS.output),
ENTRY_TEMPLATES.AGENTS.displayName
);

// Generate IDE-specific entry files
for (const ide of selectedIdes) {
switch (ide) {
case 'claude':
case 'claude-desktop':
generateFile(
join(entryTemplatesDir, ENTRY_TEMPLATES.CLAUDE.template),
join(targetDir, ENTRY_TEMPLATES.CLAUDE.output),
ENTRY_TEMPLATES.CLAUDE.displayName
);
break;

case 'cursor': {
const cursorRulesDir = join(targetDir, ENTRY_TEMPLATES.CURSOR.outputDir);
generateFile(
join(entryTemplatesDir, ENTRY_TEMPLATES.CURSOR.template),
join(cursorRulesDir, ENTRY_TEMPLATES.CURSOR.output),
ENTRY_TEMPLATES.CURSOR.displayName,
cursorRulesDir
);
break;
}

// augment, gemini, common use AGENTS.md only (already generated above)
default:
break;
}
}
}

// ============================================================================
Expand Down Expand Up @@ -954,6 +1064,10 @@ async function phase2_initProject(options: InstallOptions): Promise<string> {
console.log(chalk.green(` ✓ 配置 ${ide} (${config.commandsDir}/)`));
}

// Generate entry files (AGENTS.md, CLAUDE.md, etc.)
console.log(chalk.bold('\n📄 生成入口文件...\n'));
generateEntryFiles(cwd, projectName, selectedIdes, templatesDir, shouldForce);

// Show summary for multi-select (Fix L2)
if (selectedIdes.length > 1) {
console.log(chalk.green(`\n ✓ 已为 ${selectedIdes.length} 个 IDE 配置完成: ${selectedIdes.join(', ')}`));
Expand Down
118 changes: 118 additions & 0 deletions cli/templates/entry/AGENTS.md.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# {{PROJECT_NAME}} - Agent Instructions

This project uses **OpenMemory Plus** for persistent agent memory management.

---

## 🧠 Memory System (Auto-Enabled)

> **Core Principle**: Agent automatically extracts memories without user intervention

### Session Lifecycle

#### 🚀 Session Start (Auto)

1. **Load project context**
```
Read _omp/memory/project.yaml
Read _omp/memory/activeContext.md
```

2. **Load user preferences** (if openmemory MCP available)
```
search_memory_openmemory: "user preferences for {{PROJECT_NAME}}"
```

3. **Restore work state**
```
Read _omp/memory/progress.md
```

#### ⚡ During Session - Auto-Extraction

**When detecting trigger events, automatically dispatch memory-extraction subagent:**

| Priority | Trigger | Detection Signal | Storage |
|----------|---------|------------------|---------|
| P0 | Task complete | Task marked complete | `progress.md` |
| P0 | Tech decision | "decide/choose/use" or "决定/选择/采用" | `decisions.yaml` |
| P1 | Config change | .env, config file modified | `project.yaml` |
| P1 | Deployment | deploy/vercel/wrangler output | `project.yaml` |
| P2 | User preference | "I prefer/like" or "我喜欢/偏好" | `openmemory` |
| P2 | Architecture | "pattern/architecture/design" | `systemPatterns.md` |
| P3 | Checkpoint | Every 10 exchanges | `activeContext.md` |

**Subagent dispatch template**:
```
Use sub-agent-explore or Task tool:
name: memory-extract-{timestamp}
instruction: See _omp/skills/memory-extraction/subagent-prompt.md
```

#### 🏁 Session End (Auto)

Dispatch final memory-extraction subagent:
- Session summary → `activeContext.md`
- Unextracted learnings → appropriate memory files
- Progress updates → `progress.md`

---

## 📁 Project Structure

```
_omp/ # OpenMemory Plus core
├── commands/ # Agent commands
│ └── memory.md # /memory entry point
├── workflows/ # Multi-step workflows
│ └── memory/ # Memory management workflow
├── skills/ # Agent skills
│ └── memory-extraction/ # Auto-extract learnings
│ ├── SKILL.md # Skill definition
│ ├── subagent-prompt.md # Subagent dispatch template
│ └── triggers.md # Trigger definitions
└── memory/ # Project memory files
├── project.yaml # Project config (SSOT)
├── activeContext.md # Current session context
├── productContext.md # Product/feature context
├── progress.md # Development progress
├── projectbrief.md # Project overview
├── systemPatterns.md # Architecture patterns
├── techContext.md # Technical decisions
└── decisions.yaml # Decision records
```

---

## 🎯 Manual Commands

Use `/memory` for manual memory operations:

| Command | Description |
|---------|-------------|
| `/memory` | Open memory management menu |
| `/memory save` | Force save current context |
| `/memory load` | Load specific memory file |
| `/memory search <query>` | Search through memories |
| `/memory sync` | Sync with external memory (Qdrant) |

---

## ⚙️ Integration

This project is configured for: {{IDE_LIST}}

### Dual-Layer Memory Architecture

| Layer | Storage | Purpose |
|-------|---------|---------|
| Project | `_omp/memory/` | Project config, decisions, progress |
| User | `openmemory` MCP | User preferences, cross-project context |

### MCP Configuration

For MCP setup, see your IDE-specific settings file or run:
```bash
npx openmemory-plus install --show-mcp
```

78 changes: 78 additions & 0 deletions cli/templates/entry/CLAUDE.md.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# {{PROJECT_NAME}} - Claude Code Instructions

This project uses **OpenMemory Plus** for persistent memory management.

---

## 🧠 Memory System (Auto-Enabled)

> **Core Principle**: Agent automatically extracts memories without user intervention

### Session Lifecycle

**🚀 Session Start** - Auto-load:
```
Read _omp/memory/project.yaml # Project config
Read _omp/memory/activeContext.md # Recent context
Search openmemory # User preferences
```

**⚡ During Session** - Auto-extraction triggers:

| Trigger | Detection Signal | Storage |
|---------|------------------|---------|
| Task complete | Task marked complete | `progress.md` |
| Tech decision | "decide/choose" or "决定/选择" | `decisions.yaml` |
| Config change | .env/config modified | `project.yaml` |
| User preference | "I prefer" or "我喜欢" | `openmemory` |

**🏁 Session End** - Auto-save:
- Session summary → `activeContext.md`
- Progress updates → `progress.md`

---

## 📁 Project Memory (`_omp/memory/`)

| File | Purpose |
|------|---------|
| `project.yaml` | Project config (SSOT) |
| `decisions.yaml` | Technical decisions |
| `activeContext.md` | Current working context |
| `productContext.md` | Product/feature requirements |
| `progress.md` | Development milestones |
| `projectbrief.md` | Project overview |
| `systemPatterns.md` | Architecture patterns |
| `techContext.md` | Technical stack info |

---

## 🎯 Manual Commands

Use `/memory` for manual operations:

| Command | Description |
|---------|-------------|
| `/memory` | Open memory menu |
| `/memory save` | Force save context |
| `/memory search <query>` | Search memories |

---

## 📍 Locations

- Commands: `.claude/commands/`
- Skills: `.claude/skills/`
- Core: `_omp/`
- Subagent Prompt: `_omp/skills/memory-extraction/subagent-prompt.md`

---

## ⚙️ MCP Integration

Memory backed by Qdrant vector database via MCP.

Config: `~/Library/Application Support/Claude/claude_desktop_config.json`

Run for setup: `npx openmemory-plus install --show-mcp`

36 changes: 36 additions & 0 deletions cli/templates/entry/cursor-rule.mdc.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
description: OpenMemory Plus - Agent Memory System
globs: ["**/*"]
alwaysApply: true
---

# {{PROJECT_NAME}} - Memory System

This project uses **OpenMemory Plus** for persistent agent memory.

## Quick Start

```
/memory
```

## Memory Files (`_omp/memory/`)

- `activeContext.md` - Current session context
- `productContext.md` - Product requirements
- `progress.md` - Development progress
- `systemPatterns.md` - Architecture patterns
- `techContext.md` - Technical decisions

## Workflow

1. Load context: `@_omp/memory/activeContext.md`
2. Work on tasks with memory awareness
3. Save learnings with `/memory save`

## Commands & Skills

- Commands: `.cursor/commands/`
- Skills: `.cursor/skills/`
- Core: `_omp/`

Loading