@modus-ai/modus 0.1.5 → 0.1.6

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.
@@ -0,0 +1,220 @@
1
+ import path from 'node:path';
2
+ import { writeFile, readTemplate, fileExists, readFile } from '../utils/file-system.js';
3
+ const RULES_BASE = path.join('.cursor', 'rules');
4
+ const MCP_PATH = path.join('.cursor', 'mcp.json');
5
+ // ---------------------------------------------------------------------------
6
+ // Framework Skills → individual .mdc rules
7
+ // ---------------------------------------------------------------------------
8
+ const SKILL_RULES = [
9
+ {
10
+ id: 'modus-init',
11
+ templatePath: 'skills/modus-init/SKILL.md',
12
+ description: 'Run /modus:init to scan the codebase and build Business Skills for each domain',
13
+ },
14
+ {
15
+ id: 'modus-vibe',
16
+ templatePath: 'skills/modus-vibe/SKILL.md',
17
+ description: 'Run /modus:vibe to start context-aware vibe coding with business Skill preloading',
18
+ },
19
+ {
20
+ id: 'modus-plan',
21
+ templatePath: 'skills/modus-plan/SKILL.md',
22
+ description: 'Run /modus:plan to create structured feature proposals with complexity grading',
23
+ },
24
+ {
25
+ id: 'modus-spec',
26
+ templatePath: 'skills/modus-spec/SKILL.md',
27
+ description: 'Run /modus:spec for OpenSpec-driven development with delta specs and GIVEN/WHEN/THEN scenarios',
28
+ },
29
+ {
30
+ id: 'modus-auto',
31
+ templatePath: 'skills/modus-auto/SKILL.md',
32
+ description: 'Run /modus:auto with a TAPD story URL to get AI-recommended mode (vibe/plan/spec/harness)',
33
+ },
34
+ {
35
+ id: 'modus-harness',
36
+ templatePath: 'skills/modus-harness/SKILL.md',
37
+ description: 'Run /modus:harness to execute the full dual-loop multi-agent development pipeline',
38
+ },
39
+ ];
40
+ // Harness sub-agent templates to merge into the single harness rule
41
+ const HARNESS_SUB_AGENT_TEMPLATES = [
42
+ { id: '00-skills-builder', templatePath: 'skills/modus-harness-agents/00-skills-builder/SKILL.md' },
43
+ { id: '01-analysis', templatePath: 'skills/modus-harness-agents/01-analysis/SKILL.md' },
44
+ { id: '02-dev', templatePath: 'skills/modus-harness-agents/02-dev/SKILL.md' },
45
+ { id: '03-test', templatePath: 'skills/modus-harness-agents/03-test/SKILL.md' },
46
+ { id: '04-perf', templatePath: 'skills/modus-harness-agents/04-perf/SKILL.md' },
47
+ { id: '05-security', templatePath: 'skills/modus-harness-agents/05-security/SKILL.md' },
48
+ { id: '06-review', templatePath: 'skills/modus-harness-agents/06-review/SKILL.md' },
49
+ { id: '07-deploy', templatePath: 'skills/modus-harness-agents/07-deploy/SKILL.md' },
50
+ ];
51
+ // ---------------------------------------------------------------------------
52
+ // Main entry
53
+ // ---------------------------------------------------------------------------
54
+ export function generateCursorFiles(projectRoot, config, _opts = {}) {
55
+ generateCursorSkillRules(projectRoot, config);
56
+ generateCursorHarnessRule(projectRoot);
57
+ generateCursorConstitution(projectRoot, config);
58
+ generateCursorAutoVibe(projectRoot);
59
+ generateCursorMcp(projectRoot, config);
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // Individual skill rules
63
+ // ---------------------------------------------------------------------------
64
+ function generateCursorSkillRules(projectRoot, config) {
65
+ const enabled = new Set(config.commands.enabled);
66
+ for (const skill of SKILL_RULES) {
67
+ // Only generate command-backed skills if the command is enabled
68
+ const cmdId = skill.id.replace('modus-', '');
69
+ if (['init', 'vibe', 'plan', 'spec', 'auto', 'harness'].includes(cmdId) && !enabled.has(cmdId)) {
70
+ continue;
71
+ }
72
+ let body;
73
+ try {
74
+ body = readTemplate(skill.templatePath);
75
+ }
76
+ catch {
77
+ continue;
78
+ }
79
+ const content = buildMdcFile(skill.description, false, body);
80
+ writeFile(path.join(projectRoot, RULES_BASE, `${skill.id}.mdc`), content);
81
+ }
82
+ }
83
+ // ---------------------------------------------------------------------------
84
+ // Harness rule — single-agent degradation
85
+ // ---------------------------------------------------------------------------
86
+ function generateCursorHarnessRule(projectRoot) {
87
+ const sections = [
88
+ '# Modus Harness — Single-Agent Mode',
89
+ '',
90
+ '> **Note:** Cursor does not support native Sub-Agents. The Harness pipeline runs in',
91
+ '> single-agent mode: the orchestrator executes each step sequentially within one context.',
92
+ '> For full parallel Sub-Agent support, use CodeBuddy or Claude Code.',
93
+ '',
94
+ '## Pipeline Steps (sequential)',
95
+ '',
96
+ ];
97
+ for (const agent of HARNESS_SUB_AGENT_TEMPLATES) {
98
+ let body;
99
+ try {
100
+ body = readTemplate(agent.templatePath);
101
+ }
102
+ catch {
103
+ continue;
104
+ }
105
+ sections.push(`### Step ${agent.id}`, '', body, '', '---', '');
106
+ }
107
+ const content = buildMdcFile('Modus Harness orchestration steps (single-agent mode for Cursor)', false, sections.join('\n'));
108
+ writeFile(path.join(projectRoot, RULES_BASE, 'modus-harness-agents.mdc'), content);
109
+ }
110
+ // ---------------------------------------------------------------------------
111
+ // Constitution rule
112
+ // ---------------------------------------------------------------------------
113
+ function generateCursorConstitution(projectRoot, config) {
114
+ const any = config;
115
+ const constitution = any['constitution'] ?? {};
116
+ const techStack = String(constitution['tech_stack'] ?? config.techStack ?? '');
117
+ const buildCmd = String(constitution['build_command'] ?? '');
118
+ const testCmd = String(constitution['test_command'] ?? '');
119
+ const context = config.context ?? '';
120
+ const hardRules = Array.isArray(constitution['hard_rules'])
121
+ ? constitution['hard_rules'].map((r) => `- ${r}`).join('\n')
122
+ : '';
123
+ const keyPatterns = Array.isArray(constitution['key_patterns'])
124
+ ? constitution['key_patterns'].map((p) => `- ${p}`).join('\n')
125
+ : '';
126
+ const lines = ['# Modus Project Constitution', ''];
127
+ if (context) {
128
+ lines.push(`> ${context}`, '');
129
+ }
130
+ if (techStack) {
131
+ lines.push(`**Tech Stack:** ${techStack}`, '');
132
+ }
133
+ if (buildCmd) {
134
+ lines.push(`**Build Command:** \`${buildCmd}\``, '');
135
+ }
136
+ if (testCmd) {
137
+ lines.push(`**Test Command:** \`${testCmd}\``, '');
138
+ }
139
+ if (hardRules) {
140
+ lines.push('**Hard Rules (must never violate):**', hardRules, '');
141
+ }
142
+ if (keyPatterns) {
143
+ lines.push('**Key Patterns:**', keyPatterns, '');
144
+ }
145
+ lines.push('**Modus Commands:** `/modus:init` · `/modus:vibe` · `/modus:plan` · `/modus:spec` · `/modus:auto` · `/modus:harness`');
146
+ const content = buildMdcFile('Modus project constitution — tech stack, hard rules, and key patterns', true, lines.join('\n'));
147
+ writeFile(path.join(projectRoot, RULES_BASE, 'modus-constitution.mdc'), content);
148
+ }
149
+ // ---------------------------------------------------------------------------
150
+ // Auto-vibe — always-on rule that activates vibe behavior automatically
151
+ // ---------------------------------------------------------------------------
152
+ function generateCursorAutoVibe(projectRoot) {
153
+ const body = [
154
+ '# Modus Auto-Vibe Mode',
155
+ '',
156
+ 'This project has Modus initialized. **For every conversation, automatically apply',
157
+ 'vibe-mode behavior** — do not wait for the user to type `/modus:vibe`.',
158
+ '',
159
+ '## Auto-Vibe Instructions',
160
+ '',
161
+ '1. At the start of each conversation, read `modus/knowledge-catalog.md` to understand',
162
+ ' available Business Skills and their domains.',
163
+ '2. Based on the user\'s request, identify the relevant business domain(s).',
164
+ '3. Load the corresponding `.cursor/rules/modus-biz-{domain}.mdc` rule(s) to get',
165
+ ' business context (entities, rules, pitfalls, key files).',
166
+ '4. Respond as a developer who deeply understands this project — apply the',
167
+ ' business rules, naming conventions, and known pitfalls from the loaded Skills.',
168
+ '5. If the user explicitly triggers `/modus:plan`, `/modus:spec`, or `/modus:harness`,',
169
+ ' switch to that mode\'s workflow.',
170
+ '',
171
+ '## Token Efficiency',
172
+ '',
173
+ '- Load Skills **on demand** (only for domains relevant to the current request).',
174
+ '- Skip loading if the request is clearly out of project scope (e.g. general questions).',
175
+ '- Re-use already-loaded Skill context within the same conversation.',
176
+ ].join('\n');
177
+ const content = buildMdcFile('Auto-apply Modus vibe mode for every conversation — load Business Skills based on user request', true, body);
178
+ writeFile(path.join(projectRoot, RULES_BASE, 'modus-auto-vibe.mdc'), content);
179
+ }
180
+ // ---------------------------------------------------------------------------
181
+ // MCP config — .cursor/mcp.json
182
+ // ---------------------------------------------------------------------------
183
+ function generateCursorMcp(projectRoot, config) {
184
+ if (!config.mcpServers || Object.keys(config.mcpServers).length === 0)
185
+ return;
186
+ const mcpPath = path.join(projectRoot, MCP_PATH);
187
+ let existing = {};
188
+ if (fileExists(mcpPath)) {
189
+ try {
190
+ existing = JSON.parse(readFile(mcpPath));
191
+ }
192
+ catch {
193
+ existing = {};
194
+ }
195
+ }
196
+ const existingServers = existing['mcpServers'] ?? {};
197
+ existing['mcpServers'] = { ...config.mcpServers, ...existingServers };
198
+ writeFile(mcpPath, JSON.stringify(existing, null, 2) + '\n');
199
+ }
200
+ // ---------------------------------------------------------------------------
201
+ // Helpers
202
+ // ---------------------------------------------------------------------------
203
+ /**
204
+ * Wrap markdown body in a Cursor .mdc frontmatter header.
205
+ */
206
+ function buildMdcFile(description, alwaysApply, body) {
207
+ return `---\ndescription: "${description.replace(/"/g, '\\"')}"\nalwaysApply: ${alwaysApply}\n---\n\n${body}\n`;
208
+ }
209
+ // ---------------------------------------------------------------------------
210
+ // Business Skill sync
211
+ // ---------------------------------------------------------------------------
212
+ /**
213
+ * Sync a single business Skill to Cursor format.
214
+ * Creates a rule at .cursor/rules/modus-biz-{domain}.mdc
215
+ */
216
+ export function syncBizSkillToCursor(projectRoot, domain, skillContent) {
217
+ const content = buildMdcFile(`Business rules and conventions for the ${domain} domain`, false, skillContent);
218
+ writeFile(path.join(projectRoot, RULES_BASE, `modus-biz-${domain}.mdc`), content);
219
+ }
220
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/generators/cursor.ts"],"names":[],"mappings":"AAKA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAIxF,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAElD,8EAA8E;AAC9E,2CAA2C;AAC3C,8EAA8E;AAE9E,MAAM,WAAW,GAAqE;IACpF;QACE,EAAE,EAAE,YAAY;QAChB,YAAY,EAAE,4BAA4B;QAC1C,WAAW,EAAE,gFAAgF;KAC9F;IACD;QACE,EAAE,EAAE,YAAY;QAChB,YAAY,EAAE,4BAA4B;QAC1C,WAAW,EAAE,mFAAmF;KACjG;IACD;QACE,EAAE,EAAE,YAAY;QAChB,YAAY,EAAE,4BAA4B;QAC1C,WAAW,EAAE,gFAAgF;KAC9F;IACD;QACE,EAAE,EAAE,YAAY;QAChB,YAAY,EAAE,4BAA4B;QAC1C,WAAW,EAAE,gGAAgG;KAC9G;IACD;QACE,EAAE,EAAE,YAAY;QAChB,YAAY,EAAE,4BAA4B;QAC1C,WAAW,EAAE,2FAA2F;KACzG;IACD;QACE,EAAE,EAAE,eAAe;QACnB,YAAY,EAAE,+BAA+B;QAC7C,WAAW,EAAE,mFAAmF;KACjG;CACF,CAAC;AAEF,oEAAoE;AACpE,MAAM,2BAA2B,GAAG;IAClC,EAAE,EAAE,EAAE,mBAAmB,EAAE,YAAY,EAAE,wDAAwD,EAAE;IACnG,EAAE,EAAE,EAAE,aAAa,EAAQ,YAAY,EAAE,kDAAkD,EAAE;IAC7F,EAAE,EAAE,EAAE,QAAQ,EAAa,YAAY,EAAE,6CAA6C,EAAE;IACxF,EAAE,EAAE,EAAE,SAAS,EAAY,YAAY,EAAE,8CAA8C,EAAE;IACzF,EAAE,EAAE,EAAE,SAAS,EAAY,YAAY,EAAE,8CAA8C,EAAE;IACzF,EAAE,EAAE,EAAE,aAAa,EAAQ,YAAY,EAAE,kDAAkD,EAAE;IAC7F,EAAE,EAAE,EAAE,WAAW,EAAU,YAAY,EAAE,gDAAgD,EAAE;IAC3F,EAAE,EAAE,EAAE,WAAW,EAAU,YAAY,EAAE,gDAAgD,EAAE;CAC5F,CAAC;AAEF,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,MAAmB,EACnB,QAAyB,EAAE;IAE3B,wBAAwB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC9C,yBAAyB,CAAC,WAAW,CAAC,CAAC;IACvC,0BAA0B,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAChD,sBAAsB,CAAC,WAAW,CAAC,CAAC;IACpC,iBAAiB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AACzC,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E,SAAS,wBAAwB,CAAC,WAAmB,EAAE,MAAmB;IACxE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAEjD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,gEAAgE;QAChE,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/F,SAAS;QACX,CAAC;QAED,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC7D,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,0CAA0C;AAC1C,8EAA8E;AAE9E,SAAS,yBAAyB,CAAC,WAAmB;IACpD,MAAM,QAAQ,GAAa;QACzB,qCAAqC;QACrC,EAAE;QACF,qFAAqF;QACrF,2FAA2F;QAC3F,sEAAsE;QACtE,EAAE;QACF,gCAAgC;QAChC,EAAE;KACH,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,2BAA2B,EAAE,CAAC;QAChD,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,YAAY,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAC1B,kEAAkE,EAClE,KAAK,EACL,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CACpB,CAAC;IACF,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,0BAA0B,CAAC,EAAE,OAAO,CAAC,CAAC;AACrF,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,SAAS,0BAA0B,CAAC,WAAmB,EAAE,MAAmB;IAC1E,MAAM,GAAG,GAAG,MAA4C,CAAC;IACzD,MAAM,YAAY,GAAI,GAAG,CAAC,cAAc,CAAyC,IAAI,EAAE,CAAC;IACxF,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAG,MAAM,CAAC,YAAY,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;IACrC,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QACzD,CAAC,CAAE,YAAY,CAAC,YAAY,CAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1E,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC;QAC7D,CAAC,CAAE,YAAY,CAAC,cAAc,CAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC5E,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,KAAK,GAAa,CAAC,8BAA8B,EAAE,EAAE,CAAC,CAAC;IAC7D,IAAI,OAAO,EAAM,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAAC,CAAC;IACpD,IAAI,SAAS,EAAI,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IAAC,CAAC;IACpE,IAAI,QAAQ,EAAK,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,QAAQ,IAAI,EAAE,EAAE,CAAC,CAAC;IAAC,CAAC;IAC1E,IAAI,OAAO,EAAM,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,OAAO,IAAI,EAAE,EAAE,CAAC,CAAC;IAAC,CAAC;IACxE,IAAI,SAAS,EAAI,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,sCAAsC,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;IAAC,CAAC;IACvF,IAAI,WAAW,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;IAAC,CAAC;IACtE,KAAK,CAAC,IAAI,CACR,sHAAsH,CACvH,CAAC;IAEF,MAAM,OAAO,GAAG,YAAY,CAC1B,uEAAuE,EACvE,IAAI,EACJ,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CACjB,CAAC;IACF,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,wBAAwB,CAAC,EAAE,OAAO,CAAC,CAAC;AACnF,CAAC;AAED,8EAA8E;AAC9E,wEAAwE;AACxE,8EAA8E;AAE9E,SAAS,sBAAsB,CAAC,WAAmB;IACjD,MAAM,IAAI,GAAG;QACX,wBAAwB;QACxB,EAAE;QACF,mFAAmF;QACnF,wEAAwE;QACxE,EAAE;QACF,2BAA2B;QAC3B,EAAE;QACF,uFAAuF;QACvF,iDAAiD;QACjD,4EAA4E;QAC5E,iFAAiF;QACjF,6DAA6D;QAC7D,2EAA2E;QAC3E,mFAAmF;QACnF,uFAAuF;QACvF,qCAAqC;QACrC,EAAE;QACF,qBAAqB;QACrB,EAAE;QACF,iFAAiF;QACjF,yFAAyF;QACzF,qEAAqE;KACtE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,OAAO,GAAG,YAAY,CAC1B,gGAAgG,EAChG,IAAI,EACJ,IAAI,CACL,CAAC;IACF,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,qBAAqB,CAAC,EAAE,OAAO,CAAC,CAAC;AAChF,CAAC;AAED,8EAA8E;AAC9E,gCAAgC;AAChC,8EAA8E;AAE9E,SAAS,iBAAiB,CAAC,WAAmB,EAAE,MAAmB;IACjE,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAE9E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACjD,IAAI,QAAQ,GAA4B,EAAE,CAAC;IAE3C,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA4B,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GAAI,QAAQ,CAAC,YAAY,CAA6B,IAAI,EAAE,CAAC;IAClF,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,GAAG,eAAe,EAAE,CAAC;IAEtE,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC/D,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;GAEG;AACH,SAAS,YAAY,CAAC,WAAmB,EAAE,WAAoB,EAAE,IAAY;IAC3E,OAAO,sBAAsB,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,mBAAmB,WAAW,YAAY,IAAI,IAAI,CAAC;AAClH,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAAmB,EACnB,MAAc,EACd,YAAoB;IAEpB,MAAM,OAAO,GAAG,YAAY,CAC1B,0CAA0C,MAAM,SAAS,EACzD,KAAK,EACL,YAAY,CACb,CAAC;IACF,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,MAAM,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;AACpF,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type GenerateOptions } from './codebuddy.js';
2
+ import type { ModusConfig } from '../utils/config.js';
3
+ export type { GenerateOptions };
4
+ /**
5
+ * Generate configuration files for every platform listed in `config.platforms`.
6
+ * Defaults to ['codebuddy'] when the field is absent to preserve backward compat.
7
+ */
8
+ export declare function generateAllPlatformFiles(projectRoot: string, config: ModusConfig, opts?: GenerateOptions): void;
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAI9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,IAAI,GAAE,eAAoB,GACzB,IAAI,CAeN"}
@@ -0,0 +1,26 @@
1
+ // Platform dispatcher — generates configuration files for all selected AI platforms.
2
+ // Called by `modus init` and `modus update`; replaces direct calls to generateCodeBuddyFiles.
3
+ import { generateCodeBuddyFiles } from './codebuddy.js';
4
+ import { generateClaudeFiles } from './claude.js';
5
+ import { generateCursorFiles } from './cursor.js';
6
+ import { generateCopilotFiles } from './copilot.js';
7
+ /**
8
+ * Generate configuration files for every platform listed in `config.platforms`.
9
+ * Defaults to ['codebuddy'] when the field is absent to preserve backward compat.
10
+ */
11
+ export function generateAllPlatformFiles(projectRoot, config, opts = {}) {
12
+ const platforms = config.platforms ?? ['codebuddy'];
13
+ if (platforms.includes('codebuddy')) {
14
+ generateCodeBuddyFiles(projectRoot, config, opts);
15
+ }
16
+ if (platforms.includes('claude')) {
17
+ generateClaudeFiles(projectRoot, config, opts);
18
+ }
19
+ if (platforms.includes('cursor')) {
20
+ generateCursorFiles(projectRoot, config, opts);
21
+ }
22
+ if (platforms.includes('copilot')) {
23
+ generateCopilotFiles(projectRoot, config, opts);
24
+ }
25
+ }
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,8FAA8F;AAC9F,OAAO,EAAE,sBAAsB,EAAwB,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKpD;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,MAAmB,EACnB,OAAwB,EAAE;IAE1B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,CAAC;IAEpD,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpC,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
@@ -1,3 +1,5 @@
1
+ /** Supported AI platform targets for file generation. */
2
+ export type PlatformId = 'codebuddy' | 'claude' | 'cursor' | 'copilot';
1
3
  export interface ModusAnalyticsConfig {
2
4
  /** Whether to send usage events. Defaults to true. */
3
5
  enabled?: boolean;
@@ -23,6 +25,19 @@ export interface ModusConfig {
23
25
  mcpServers?: Record<string, unknown>;
24
26
  /** Usage analytics — sends command/subagent events to the Collector API. */
25
27
  analytics?: ModusAnalyticsConfig;
28
+ /**
29
+ * AI platforms to generate configuration files for.
30
+ * Set during `modus init`; refreshed by `modus update`.
31
+ * Defaults to ['codebuddy'] when omitted.
32
+ */
33
+ platforms?: PlatformId[];
34
+ /**
35
+ * The modus CLI version that last wrote the platform files.
36
+ * Written by `modus init` and `modus update`.
37
+ * The session-start hook compares this against the currently installed version
38
+ * and auto-runs `modus update` when they differ (silent auto-update).
39
+ */
40
+ modusBuildVersion?: string;
26
41
  }
27
42
  export declare function getConfigPath(projectRoot: string): string;
28
43
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,4EAA4E;IAC5E,SAAS,CAAC,EAAE,oBAAoB,CAAC;CAClC;AASD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAK3D;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAIzE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAKA,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,4EAA4E;IAC5E,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,UAAU,EAAE,CAAC;IACzB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AASD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAK3D;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAIzE"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA8BnE,MAAM,cAAc,GAAgB;IAClC,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE;QACR,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;KACrD;CACF,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC1D,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAgB,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,MAAmB;IACjE,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA8CnE,MAAM,cAAc,GAAgB;IAClC,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE;QACR,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;KACrD;CACF,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC1D,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAgB,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,MAAmB;IACjE,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modus-ai/modus",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Modus — Business-grounded AI coding accelerator for CodeBuddy IDE",
5
5
  "keywords": [
6
6
  "ai",
@@ -65,12 +65,54 @@ def read_file_safe(path: str, max_bytes: int = 8000) -> str:
65
65
  return ""
66
66
 
67
67
 
68
+ def _silent_auto_update(project_dir: str) -> bool:
69
+ """
70
+ Compare the modus CLI version that generated the current project files
71
+ (stored in modus/config.yaml modusBuildVersion) with the currently installed
72
+ modus version. If they differ, silently re-run `modus update` so users get
73
+ new templates automatically after an npm upgrade — no manual action needed.
74
+
75
+ Returns True if an update was performed.
76
+ """
77
+ try:
78
+ import subprocess
79
+ import yaml # type: ignore[import-untyped]
80
+
81
+ config_path = os.path.join(project_dir, "modus", "config.yaml")
82
+ with open(config_path, encoding="utf-8") as f:
83
+ config = yaml.safe_load(f) or {}
84
+
85
+ stored_version = (config.get("modusBuildVersion") or "").strip()
86
+ if not stored_version:
87
+ return False # Never stamped — skip (pre-feature install)
88
+
89
+ result = subprocess.run(
90
+ ["modus", "--version"],
91
+ capture_output=True, text=True, timeout=5,
92
+ )
93
+ current_version = result.stdout.strip()
94
+ if not current_version or current_version == stored_version:
95
+ return False # Up to date
96
+
97
+ # Versions differ — silently regenerate all platform files
98
+ subprocess.run(
99
+ ["modus", "update", "--root", project_dir],
100
+ capture_output=True, timeout=60,
101
+ )
102
+ return True
103
+ except Exception:
104
+ return False # Non-fatal — never break the session
105
+
106
+
68
107
  def main() -> int:
69
108
  input_data = json.loads(sys.stdin.read())
70
109
  project_dir = os.environ.get("CODEBUDDY_PROJECT_DIR") or os.environ.get(
71
110
  "CLAUDE_PROJECT_DIR", input_data.get("cwd", "")
72
111
  )
73
112
 
113
+ # Auto-update: silently regenerate files if modus CLI was upgraded since last init/update
114
+ was_updated = _silent_auto_update(project_dir)
115
+
74
116
  context_parts: list[str] = []
75
117
 
76
118
  # 1. knowledge-catalog — Level 1 index (~200 tokens)
@@ -113,10 +155,18 @@ def main() -> int:
113
155
  if not context_parts:
114
156
  output = {"continue": True}
115
157
  else:
158
+ update_notice = "\n🔄 [Modus 已自动升级] 平台文件已静默刷新至最新版本。" if was_updated else ""
116
159
  additional_context = (
117
160
  "=== Modus 项目上下文(自动注入)===\n\n"
118
161
  + "\n\n".join(context_parts)
119
- + "\n\n提示:使用 /modus:vibe、/modus:plan、/modus:spec 或 /modus:harness 开始工作。"
162
+ + update_notice
163
+ + "\n\n**[自动 Vibe 模式已启用]**\n"
164
+ "本会话无需用户输入 /modus:vibe,请自动以「懂项目的开发者」身份响应:\n"
165
+ "1. 根据用户请求,从知识目录中匹配相关业务域\n"
166
+ "2. 按需加载对应的 Business Skill(.codebuddy/skills/modus-biz-*/SKILL.md)\n"
167
+ "3. 以 Skill 中的业务规则、命名约定和已知坑作为约束回答或编码\n"
168
+ "4. 若用户显式运行 /modus:plan、/modus:spec 或 /modus:harness,切换到对应模式\n"
169
+ "完整 Vibe 工作流程见 modus-vibe Skill。"
120
170
  )
121
171
  output = {
122
172
  "continue": True,
@@ -164,6 +164,76 @@ SubAgent-3 (user域) ──► 扫描用户相关文件 ──► 生成 modu
164
164
 
165
165
  每个 Skill 文件遵循 Business Skill 标准格式(含 maturity/last_referenced/usage_count 字段)。
166
166
 
167
+ ### Step 3.5:多平台同步(Business Skills)
168
+
169
+ Business Skills 全部生成后,读取 `modus/config.yaml` 的 `platforms` 字段,将每个业务 Skill 同步到其他已选平台。
170
+
171
+ **读取 platforms 配置:**
172
+
173
+ ```bash
174
+ # 检查已选平台
175
+ grep -A5 "^platforms:" modus/config.yaml
176
+ ```
177
+
178
+ **各平台同步规则(仅处理 codebuddy 以外的平台):**
179
+
180
+ #### Claude Code(`.claude/agents/modus-biz-{domain}.md`)
181
+
182
+ 对每个业务域,创建 Claude Sub-Agent 定义文件:
183
+
184
+ ```markdown
185
+ ---
186
+ name: modus-biz-{domain}
187
+ description: Business knowledge for the {domain} domain — {核心职责一句话}
188
+ ---
189
+
190
+ {.codebuddy/skills/modus-biz-{domain}/SKILL.md 的完整内容}
191
+ ```
192
+
193
+ #### Cursor(`.cursor/rules/modus-biz-{domain}.mdc`)
194
+
195
+ 对每个业务域,创建 Cursor 规则文件(带 frontmatter):
196
+
197
+ ```markdown
198
+ ---
199
+ description: "Business rules and conventions for the {domain} domain — {核心职责一句话}"
200
+ alwaysApply: false
201
+ ---
202
+
203
+ {.codebuddy/skills/modus-biz-{domain}/SKILL.md 的完整内容}
204
+ ```
205
+
206
+ #### GitHub Copilot(`.github/copilot-instructions.md`)
207
+
208
+ 将每个业务域的 Skill 内容以带标记的段落形式追加或更新(幂等):
209
+
210
+ ```markdown
211
+ <!-- modus:biz-skill:{domain}:start -->
212
+
213
+ ### Business Skill: {domain}
214
+
215
+ {.codebuddy/skills/modus-biz-{domain}/SKILL.md 的完整内容}
216
+
217
+ <!-- modus:biz-skill:{domain}:end -->
218
+ ```
219
+
220
+ **若文件中已存在对应域的标记段落,替换其内容(不重复追加)。**
221
+
222
+ **同步完成输出:**
223
+
224
+ ```
225
+ 📡 多平台同步:
226
+ ✓ Claude .claude/agents/modus-biz-order.md
227
+ ✓ Claude .claude/agents/modus-biz-payment.md
228
+ ✓ Cursor .cursor/rules/modus-biz-order.mdc
229
+ ✓ Cursor .cursor/rules/modus-biz-payment.mdc
230
+ ✓ Copilot .github/copilot-instructions.md(已更新 2 个域段落)
231
+ ```
232
+
233
+ 若 `platforms` 只包含 `codebuddy`(或字段不存在),跳过此步骤。
234
+
235
+ ---
236
+
167
237
  ### Step 4:生成团队约定 Skill(Layer 0-T)
168
238
 
169
239
  调用「Skills Builder SubAgent」(模式 E:团队约定初始化):
@@ -274,6 +344,11 @@ constitution:
274
344
  - .codebuddy/skills/modus-biz-payment/SKILL.md [draft]
275
345
  - ...
276
346
 
347
+ 多平台同步(来自 modus/config.yaml platforms 配置):
348
+ - Claude Code → .claude/agents/modus-biz-*.md(N 个域)
349
+ - Cursor → .cursor/rules/modus-biz-*.mdc(N 个域)
350
+ - Copilot → .github/copilot-instructions.md(N 个域段落)
351
+
277
352
  初始化基础 Skill:
278
353
  - .codebuddy/skills/modus-team-conventions/SKILL.md (Layer 0-T) [draft]
279
354
  └─ 融合来源:CLAUDE.md, .cursor/rules/, CONTRIBUTING.md, 代码注解模式
@@ -393,6 +393,28 @@ design.md ────────────► design-brief.md ────
393
393
  maturity 变化: modus-biz-order draft→verified
394
394
  ```
395
395
 
396
+ ### Step 7.5:多平台 Skill 同步(后置)
397
+
398
+ 知识回写完成后,对所有本次**更新或新建**的业务 Skill 执行多平台同步。
399
+
400
+ **逻辑:**
401
+
402
+ 1. 读取 `modus/config.yaml` 的 `platforms` 字段
403
+ 2. 对受影响的每个业务域(Step 4 前置更新 / 新建的域),按以下规则同步:
404
+ - **Claude** → 写入 `.claude/agents/modus-biz-{domain}.md`(覆盖旧版本)
405
+ - **Cursor** → 写入 `.cursor/rules/modus-biz-{domain}.mdc`(带 frontmatter,覆盖旧版本)
406
+ - **Copilot** → 在 `.github/copilot-instructions.md` 中替换对应域的标记段落
407
+ 3. 若 `platforms` 只含 `codebuddy`(或字段不存在),跳过
408
+
409
+ **输出示例:**
410
+
411
+ ```
412
+ 📡 多平台 Skill 同步:
413
+ ✓ Claude .claude/agents/modus-biz-order.md(已更新)
414
+ ✓ Cursor .cursor/rules/modus-biz-order.mdc(已更新)
415
+ ✓ Copilot .github/copilot-instructions.md(order 域段落已更新)
416
+ ```
417
+
396
418
  ---
397
419
 
398
420
  ## 产出物目录结构
@@ -390,6 +390,28 @@ grep -l "### Requirement:" modus/specs/{domain}/spec.md 2>/dev/null
390
390
  - knowledge-catalog.md 已更新(order 域 maturity: draft→verified)
391
391
  ```
392
392
 
393
+ ### Step 7.5:多平台 Skill 同步(后置)
394
+
395
+ 知识提取与回写完成后,对本次涉及的业务域执行多平台同步。
396
+
397
+ **逻辑:**
398
+
399
+ 1. 读取 `modus/config.yaml` 的 `platforms` 字段
400
+ 2. 对 Step 4 前置更新 / 新建的每个业务域,按以下规则同步:
401
+ - **Claude** → 写入 `.claude/agents/modus-biz-{domain}.md`(覆盖旧版本)
402
+ - **Cursor** → 写入 `.cursor/rules/modus-biz-{domain}.mdc`(带 frontmatter,覆盖旧版本)
403
+ - **Copilot** → 在 `.github/copilot-instructions.md` 中替换对应域的标记段落
404
+ 3. 若 `platforms` 只含 `codebuddy`(或字段不存在),跳过
405
+
406
+ **输出示例:**
407
+
408
+ ```
409
+ 📡 多平台 Skill 同步:
410
+ ✓ Claude .claude/agents/modus-biz-order.md(已更新)
411
+ ✓ Cursor .cursor/rules/modus-biz-order.mdc(已更新)
412
+ ✓ Copilot .github/copilot-instructions.md(order 域段落已更新)
413
+ ```
414
+
393
415
  ---
394
416
 
395
417
  ## 主规格库结构