@modus-ai/modus 0.1.4 → 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.
Files changed (58) hide show
  1. package/README.md +76 -28
  2. package/dist/cli/index.js +206 -12
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/doctor.d.ts +2 -0
  5. package/dist/commands/doctor.d.ts.map +1 -0
  6. package/dist/commands/doctor.js +180 -0
  7. package/dist/commands/doctor.js.map +1 -0
  8. package/dist/commands/init.d.ts +18 -0
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +314 -201
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/commands/skill.d.ts +7 -0
  13. package/dist/commands/skill.d.ts.map +1 -0
  14. package/dist/commands/skill.js +175 -0
  15. package/dist/commands/skill.js.map +1 -0
  16. package/dist/commands/status.d.ts +2 -0
  17. package/dist/commands/status.d.ts.map +1 -0
  18. package/dist/commands/status.js +133 -0
  19. package/dist/commands/status.js.map +1 -0
  20. package/dist/commands/update.d.ts.map +1 -1
  21. package/dist/commands/update.js +15 -6
  22. package/dist/commands/update.js.map +1 -1
  23. package/dist/generators/claude.d.ts +9 -0
  24. package/dist/generators/claude.d.ts.map +1 -0
  25. package/dist/generators/claude.js +256 -0
  26. package/dist/generators/claude.js.map +1 -0
  27. package/dist/generators/codebuddy.d.ts +7 -0
  28. package/dist/generators/codebuddy.d.ts.map +1 -1
  29. package/dist/generators/codebuddy.js +35 -3
  30. package/dist/generators/codebuddy.js.map +1 -1
  31. package/dist/generators/copilot.d.ts +9 -0
  32. package/dist/generators/copilot.d.ts.map +1 -0
  33. package/dist/generators/copilot.js +154 -0
  34. package/dist/generators/copilot.js.map +1 -0
  35. package/dist/generators/cursor.d.ts +9 -0
  36. package/dist/generators/cursor.d.ts.map +1 -0
  37. package/dist/generators/cursor.js +220 -0
  38. package/dist/generators/cursor.js.map +1 -0
  39. package/dist/generators/index.d.ts +9 -0
  40. package/dist/generators/index.d.ts.map +1 -0
  41. package/dist/generators/index.js +26 -0
  42. package/dist/generators/index.js.map +1 -0
  43. package/dist/utils/analytics.d.ts +14 -0
  44. package/dist/utils/analytics.d.ts.map +1 -0
  45. package/dist/utils/analytics.js +81 -0
  46. package/dist/utils/analytics.js.map +1 -0
  47. package/dist/utils/config.d.ts +25 -0
  48. package/dist/utils/config.d.ts.map +1 -1
  49. package/dist/utils/config.js.map +1 -1
  50. package/package.json +1 -1
  51. package/templates/commands/auto.md +38 -0
  52. package/templates/commands/modus.md +14 -2
  53. package/templates/hooks/session-start.py +103 -1
  54. package/templates/hooks/stop-update-skills.py +58 -0
  55. package/templates/skills/modus-auto/SKILL.md +210 -0
  56. package/templates/skills/modus-init/SKILL.md +208 -11
  57. package/templates/skills/modus-plan/SKILL.md +154 -19
  58. package/templates/skills/modus-spec/SKILL.md +131 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,24 @@ export interface InitCliOptions {
13
13
  force?: boolean;
14
14
  /** Re-sync Skills from global/team directories (overwrite project copies) */
15
15
  syncScopes?: boolean;
16
+ /**
17
+ * Comma-separated list of platforms to generate.
18
+ * Allowed: codebuddy,claude,cursor,copilot
19
+ * Defaults to all four platforms when omitted.
20
+ */
21
+ platforms?: string;
22
+ }
23
+ /** One detected AI coding tool with its relevant artefacts */
24
+ export interface DetectedAITool {
25
+ tool: 'claudecode' | 'cursor' | 'codebuddy' | 'continue' | 'opencode';
26
+ /** Human-readable label */
27
+ label: string;
28
+ /** Files / directories that were found */
29
+ artifacts: string[];
30
+ /** Extracted context snippet (first 500 chars of a key file) */
31
+ contextSnippet?: string;
32
+ /** MCP servers block extracted from settings files */
33
+ mcpServers?: Record<string, unknown>;
16
34
  }
17
35
  export declare function runInit(projectRoot: string, cli?: InitCliOptions): Promise<void>;
18
36
  //# sourceMappingURL=init.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAWA,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAqGD,wBAAsB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0N1F"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAgBA,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuED,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;IACtE,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AA+OD,wBAAsB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyI1F"}
@@ -1,35 +1,15 @@
1
1
  import path from 'node:path';
2
2
  import process from 'node:process';
3
3
  import fs from 'node:fs';
4
+ import { createRequire } from 'node:module';
4
5
  import chalk from 'chalk';
5
- import inquirer from 'inquirer';
6
6
  import { loadConfig, saveConfig } from '../utils/config.js';
7
- import { generateCodeBuddyFiles } from '../generators/codebuddy.js';
7
+ import { generateAllPlatformFiles } from '../generators/index.js';
8
8
  import { fileExists, ensureDir } from '../utils/file-system.js';
9
- const DEFAULT_COMMANDS = ['init', 'vibe', 'plan', 'spec', 'harness'];
10
- function isInteractiveTerminal() {
11
- return Boolean(process.stdin.isTTY && process.stdout.isTTY);
12
- }
13
- function printNonInteractiveHelp(projectRoot) {
14
- console.log(chalk.yellow('\n 当前环境无法交互输入(例如:在 AI 助手里跑命令、或 CI 管道)。\n'));
15
- console.log(chalk.bold(' 请任选其一:\n'));
16
- console.log(chalk.cyan(' 方式 A — 在本机「真实终端」里执行(有逐步提问):'));
17
- console.log(chalk.white(` cd ${projectRoot}`));
18
- console.log(chalk.white(' modus init\n'));
19
- console.log(chalk.cyan(' 方式 B — 一条命令非交互完成(适合脚本 / AI 代跑):'));
20
- console.log(chalk.white(' modus init --yes \\'));
21
- console.log(chalk.white(' --tech-stack "Java Spring Boot, MySQL, Redis" \\'));
22
- console.log(chalk.white(' --context "后端多租户 SaaS 服务" \\'));
23
- console.log(chalk.gray(' [--tapd-project-id "12345678"] \\'));
24
- console.log(chalk.gray(' [--commands "init,vibe,plan,spec,harness"]'));
25
- console.log(chalk.gray('\n 各参数含义:'));
26
- console.log(chalk.gray(' --tech-stack 技术栈,写入 modus/config.yaml'));
27
- console.log(chalk.gray(' --context 项目一句话描述,给 AI 当背景'));
28
- console.log(chalk.gray(' --tapd-project-id 可选,TAPD 项目 ID'));
29
- console.log(chalk.gray(' --team-name 可选,团队名称,复用 ~/.codebuddy/team/<name>/ 的 Skills'));
30
- console.log(chalk.gray(' --commands 可选,逗号分隔,默认五个全开'));
31
- console.log(chalk.gray(' --force 已初始化过时仍覆盖(配合 --yes)\n'));
32
- }
9
+ import { track } from '../utils/analytics.js';
10
+ const _require = createRequire(import.meta.url);
11
+ const MODUS_VERSION = _require('../../package.json').version;
12
+ const DEFAULT_COMMANDS = ['init', 'vibe', 'plan', 'spec', 'auto', 'harness'];
33
13
  /**
34
14
  * Scan the project root for well-known build/config files and infer the tech stack.
35
15
  * For package.json, also reads dependencies to detect common frameworks.
@@ -92,193 +72,296 @@ function detectTechStack(projectRoot) {
92
72
  }
93
73
  return [...new Set(labels)].join(', ');
94
74
  }
95
- function parseCommandsCsv(csv) {
96
- if (!csv?.trim())
97
- return [...DEFAULT_COMMANDS];
98
- const parts = csv.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
99
- const allowed = new Set(DEFAULT_COMMANDS);
100
- const filtered = parts.filter((c) => allowed.has(c));
101
- return filtered.length > 0 ? filtered : [...DEFAULT_COMMANDS];
102
- }
103
- export async function runInit(projectRoot, cli = {}) {
104
- console.log(chalk.bold('\n Modus init\n'));
105
- const configPath = path.join(projectRoot, 'modus', 'config.yaml');
106
- const isFirstRun = !fileExists(configPath);
107
- const nonInteractive = Boolean(cli.yes) || !isInteractiveTerminal();
108
- if (!isInteractiveTerminal() && !cli.yes) {
109
- printNonInteractiveHelp(projectRoot);
110
- process.exitCode = 1;
111
- return;
112
- }
113
- if (!isFirstRun) {
114
- if (nonInteractive) {
115
- if (!cli.force) {
116
- console.error(chalk.red(' 项目已存在 modus/config.yaml。非交互模式下请加 --force 以覆盖生成 .codebuddy/ 文件。'));
117
- process.exitCode = 1;
118
- return;
75
+ /**
76
+ * Scan the project root for existing AI tool configuration directories and
77
+ * files (`.claude/`, `.cursor/rules/`, `CLAUDE.md`, `AGENTS.md`, …).
78
+ * Returns a list of detected tools with the artefacts found.
79
+ */
80
+ function detectExistingAITools(projectRoot) {
81
+ const results = [];
82
+ // ── ClaudeCode ──────────────────────────────────────────────────────────────
83
+ {
84
+ const artifacts = [];
85
+ let contextSnippet;
86
+ let mcpServers;
87
+ const claudeMdPaths = ['CLAUDE.md', '.claude/CLAUDE.md', 'CLAUDE.local.md'];
88
+ for (const p of claudeMdPaths) {
89
+ const full = path.join(projectRoot, p);
90
+ if (fileExists(full)) {
91
+ artifacts.push(p);
92
+ if (!contextSnippet) {
93
+ try {
94
+ contextSnippet = fs.readFileSync(full, 'utf-8').slice(0, 500);
95
+ }
96
+ catch { /* ignore */ }
97
+ }
119
98
  }
120
- console.log(chalk.cyan(' --force:将重新生成 .codebuddy/ 与配置(保留已有 YAML 中未在 CLI 传入的字段逻辑见下方)'));
121
99
  }
122
- else {
123
- const { overwrite } = await inquirer.prompt([
124
- {
125
- type: 'confirm',
126
- name: 'overwrite',
127
- message: 'Modus is already initialized. Re-generate all files?',
128
- default: true,
129
- },
130
- ]);
131
- if (!overwrite) {
132
- console.log(chalk.gray(' Aborted.'));
133
- return;
100
+ const claudeRulesDir = path.join(projectRoot, '.claude', 'rules');
101
+ if (fs.existsSync(claudeRulesDir)) {
102
+ try {
103
+ const ruleFiles = fs.readdirSync(claudeRulesDir)
104
+ .filter((f) => f.endsWith('.md') || f.endsWith('.mdc'))
105
+ .map((f) => `.claude/rules/${f}`);
106
+ artifacts.push(...ruleFiles);
134
107
  }
108
+ catch { /* ignore */ }
109
+ }
110
+ const claudeSettingsPath = path.join(projectRoot, '.claude', 'settings.json');
111
+ if (fileExists(claudeSettingsPath)) {
112
+ artifacts.push('.claude/settings.json');
113
+ try {
114
+ const raw = JSON.parse(fs.readFileSync(claudeSettingsPath, 'utf-8'));
115
+ if (raw.mcpServers && typeof raw.mcpServers === 'object') {
116
+ mcpServers = raw.mcpServers;
117
+ }
118
+ }
119
+ catch { /* ignore */ }
120
+ }
121
+ const claudeCommandsDir = path.join(projectRoot, '.claude', 'commands');
122
+ if (fs.existsSync(claudeCommandsDir)) {
123
+ try {
124
+ const cmds = fs.readdirSync(claudeCommandsDir)
125
+ .filter((f) => f.endsWith('.md'))
126
+ .map((f) => `.claude/commands/${f}`);
127
+ artifacts.push(...cmds);
128
+ }
129
+ catch { /* ignore */ }
130
+ }
131
+ if (artifacts.length > 0) {
132
+ results.push({ tool: 'claudecode', label: 'Claude Code', artifacts, contextSnippet, mcpServers });
135
133
  }
136
134
  }
137
- let config = loadConfig(projectRoot);
138
- if (isFirstRun) {
139
- if (nonInteractive) {
140
- const autoStack = cli.techStack || detectTechStack(projectRoot) || undefined;
141
- if (autoStack && !cli.techStack) {
142
- console.log(chalk.dim(` 已自动检测到技术栈:${chalk.cyan(autoStack)}`));
135
+ // ── Cursor ──────────────────────────────────────────────────────────────────
136
+ {
137
+ const artifacts = [];
138
+ let contextSnippet;
139
+ let mcpServers;
140
+ const cursorRulesDir = path.join(projectRoot, '.cursor', 'rules');
141
+ if (fs.existsSync(cursorRulesDir)) {
142
+ try {
143
+ const ruleFiles = fs.readdirSync(cursorRulesDir)
144
+ .filter((f) => f.endsWith('.md') || f.endsWith('.mdc'))
145
+ .map((f) => `.cursor/rules/${f}`);
146
+ artifacts.push(...ruleFiles);
147
+ if (!contextSnippet && ruleFiles.length > 0) {
148
+ const firstRule = path.join(cursorRulesDir, path.basename(ruleFiles[0]));
149
+ try {
150
+ contextSnippet = fs.readFileSync(firstRule, 'utf-8').slice(0, 500);
151
+ }
152
+ catch { /* ignore */ }
153
+ }
143
154
  }
144
- config = {
145
- ...config,
146
- techStack: autoStack,
147
- context: cli.context || undefined,
148
- tapdProjectId: cli.tapdProjectId || undefined,
149
- teamName: cli.teamName || undefined,
150
- };
155
+ catch { /* ignore */ }
151
156
  }
152
- else {
153
- const detectedStack = detectTechStack(projectRoot);
154
- if (detectedStack) {
155
- console.log(chalk.dim(` 已自动检测到技术栈:${chalk.cyan(detectedStack)}`));
156
- console.log(chalk.dim(' 接下来会问你 3 个问题(可直接回车确认检测值),再勾选要启用的命令。\n'));
157
+ const cursorMcpPath = path.join(projectRoot, '.cursor', 'mcp.json');
158
+ if (fileExists(cursorMcpPath)) {
159
+ artifacts.push('.cursor/mcp.json');
160
+ try {
161
+ const raw = JSON.parse(fs.readFileSync(cursorMcpPath, 'utf-8'));
162
+ if (raw.mcpServers && typeof raw.mcpServers === 'object') {
163
+ mcpServers = raw.mcpServers;
164
+ }
157
165
  }
158
- else {
159
- console.log(chalk.dim(' 接下来会问你 3 个问题(可直接回车用默认空值),再勾选要启用的命令。\n'));
166
+ catch { /* ignore */ }
167
+ }
168
+ // AGENTS.md (Cursor project-level agent instructions)
169
+ for (const p of ['AGENTS.md', '.cursor/AGENTS.md']) {
170
+ const full = path.join(projectRoot, p);
171
+ if (fileExists(full)) {
172
+ artifacts.push(p);
173
+ if (!contextSnippet) {
174
+ try {
175
+ contextSnippet = fs.readFileSync(full, 'utf-8').slice(0, 500);
176
+ }
177
+ catch { /* ignore */ }
178
+ }
160
179
  }
161
- const answers = await inquirer.prompt([
162
- {
163
- type: 'input',
164
- name: 'techStack',
165
- message: '技术栈(例如 "Java Spring Boot, MySQL, Redis"):',
166
- default: detectedStack || '',
167
- },
168
- {
169
- type: 'input',
170
- name: 'context',
171
- message: '项目一句话描述(作为 AI 背景):',
172
- default: '',
173
- },
174
- {
175
- type: 'input',
176
- name: 'tapdProjectId',
177
- message: 'TAPD 项目 ID(可选,用于 /harness 命令):',
178
- default: '',
179
- },
180
- {
181
- type: 'input',
182
- name: 'teamName',
183
- message: '团队名称(可选,复用 ~/.codebuddy/team/<name>/ 的 Skills,留空跳过):',
184
- default: config.teamName || '',
185
- },
186
- {
187
- type: 'confirm',
188
- name: 'configureMcp',
189
- message: '是否配置 MCP 服务器?(可在 .codebuddy/settings.json 中手动编辑)',
190
- default: false,
191
- },
192
- ]);
193
- let mcpServers;
194
- if (answers.configureMcp) {
195
- console.log(chalk.dim('\n MCP 服务器配置(直接回车跳过某项)'));
196
- const mcpAnswers = await inquirer.prompt([
197
- {
198
- type: 'input',
199
- name: 'tapdMcpCommand',
200
- message: ' TAPD MCP 启动命令(例如 "npx @your-org/tapd-mcp-server",留空跳过):',
201
- default: '',
202
- },
203
- {
204
- type: 'input',
205
- name: 'extraMcpName',
206
- message: ' 其他 MCP 服务名称(留空跳过):',
207
- default: '',
208
- },
209
- {
210
- type: 'input',
211
- name: 'extraMcpCommand',
212
- message: ' 其他 MCP 启动命令(留空跳过):',
213
- default: '',
214
- },
215
- ]);
216
- mcpServers = {};
217
- if (mcpAnswers.tapdMcpCommand) {
218
- const [cmd, ...args] = mcpAnswers.tapdMcpCommand.trim().split(/\s+/);
219
- mcpServers['tapd'] = {
220
- type: 'stdio',
221
- command: cmd,
222
- args,
223
- description: 'TAPD story / bug management',
224
- };
180
+ }
181
+ if (artifacts.length > 0) {
182
+ results.push({ tool: 'cursor', label: 'Cursor', artifacts, contextSnippet, mcpServers });
183
+ }
184
+ }
185
+ // ── CodeBuddy (non-modus) ───────────────────────────────────────────────────
186
+ {
187
+ const artifacts = [];
188
+ let contextSnippet;
189
+ let mcpServers;
190
+ const cbSettingsPath = path.join(projectRoot, '.codebuddy', 'settings.json');
191
+ if (fileExists(cbSettingsPath)) {
192
+ artifacts.push('.codebuddy/settings.json');
193
+ try {
194
+ const raw = JSON.parse(fs.readFileSync(cbSettingsPath, 'utf-8'));
195
+ if (raw.mcpServers && typeof raw.mcpServers === 'object') {
196
+ mcpServers = raw.mcpServers;
225
197
  }
226
- if (mcpAnswers.extraMcpName && mcpAnswers.extraMcpCommand) {
227
- const [cmd, ...args] = mcpAnswers.extraMcpCommand.trim().split(/\s+/);
228
- mcpServers[mcpAnswers.extraMcpName] = {
229
- type: 'stdio',
230
- command: cmd,
231
- args,
232
- };
198
+ }
199
+ catch { /* ignore */ }
200
+ }
201
+ const cbRulesDir = path.join(projectRoot, '.codebuddy', 'rules');
202
+ if (fs.existsSync(cbRulesDir)) {
203
+ try {
204
+ const ruleFiles = fs.readdirSync(cbRulesDir)
205
+ .filter((f) => f.endsWith('.md') || f.endsWith('.mdc'))
206
+ .map((f) => `.codebuddy/rules/${f}`);
207
+ artifacts.push(...ruleFiles);
208
+ if (!contextSnippet && ruleFiles.length > 0) {
209
+ const firstRule = path.join(cbRulesDir, path.basename(ruleFiles[0]));
210
+ try {
211
+ contextSnippet = fs.readFileSync(firstRule, 'utf-8').slice(0, 500);
212
+ }
213
+ catch { /* ignore */ }
233
214
  }
234
- if (Object.keys(mcpServers).length === 0)
235
- mcpServers = undefined;
236
215
  }
237
- config = {
238
- ...config,
239
- techStack: answers.techStack || undefined,
240
- context: answers.context || undefined,
241
- tapdProjectId: answers.tapdProjectId || undefined,
242
- teamName: answers.teamName || undefined,
243
- ...(mcpServers ? { mcpServers } : {}),
244
- };
216
+ catch { /* ignore */ }
217
+ }
218
+ if (artifacts.length > 0) {
219
+ results.push({ tool: 'codebuddy', label: 'CodeBuddy', artifacts, contextSnippet, mcpServers });
245
220
  }
246
221
  }
247
- else if (nonInteractive && cli.techStack) {
248
- config = { ...config, techStack: cli.techStack };
222
+ // ── Continue.dev ────────────────────────────────────────────────────────────
223
+ {
224
+ const artifacts = [];
225
+ let contextSnippet;
226
+ for (const p of ['.continue/config.json', '.continue/config.yaml', '.continue/config.yml']) {
227
+ const full = path.join(projectRoot, p);
228
+ if (fileExists(full)) {
229
+ artifacts.push(p);
230
+ if (!contextSnippet) {
231
+ try {
232
+ contextSnippet = fs.readFileSync(full, 'utf-8').slice(0, 500);
233
+ }
234
+ catch { /* ignore */ }
235
+ }
236
+ }
237
+ }
238
+ if (artifacts.length > 0) {
239
+ results.push({ tool: 'continue', label: 'Continue.dev', artifacts, contextSnippet });
240
+ }
249
241
  }
250
- if (!isFirstRun && nonInteractive && cli.context) {
251
- config = { ...config, context: cli.context };
242
+ // ── OpenCode / Generic AGENT.md ─────────────────────────────────────────────
243
+ {
244
+ const artifacts = [];
245
+ let contextSnippet;
246
+ for (const p of ['AGENT.md', '.agent/AGENT.md', '.claude-internal/AGENT.md']) {
247
+ const full = path.join(projectRoot, p);
248
+ if (fileExists(full)) {
249
+ artifacts.push(p);
250
+ if (!contextSnippet) {
251
+ try {
252
+ contextSnippet = fs.readFileSync(full, 'utf-8').slice(0, 500);
253
+ }
254
+ catch { /* ignore */ }
255
+ }
256
+ }
257
+ }
258
+ if (artifacts.length > 0) {
259
+ results.push({ tool: 'opencode', label: 'OpenCode / Generic', artifacts, contextSnippet });
260
+ }
252
261
  }
253
- if (!isFirstRun && nonInteractive && cli.tapdProjectId) {
254
- config = { ...config, tapdProjectId: cli.tapdProjectId };
262
+ return results;
263
+ }
264
+ /**
265
+ * Merge MCP servers from detected AI tools into the existing mcpServers map.
266
+ * Existing entries (already in modus config) take precedence.
267
+ */
268
+ function mergeMcpServers(existing, detected) {
269
+ const merged = { ...(existing ?? {}) };
270
+ for (const tool of detected) {
271
+ if (!tool.mcpServers)
272
+ continue;
273
+ for (const [key, val] of Object.entries(tool.mcpServers)) {
274
+ if (!(key in merged)) {
275
+ merged[key] = val;
276
+ }
277
+ }
278
+ }
279
+ return Object.keys(merged).length > 0 ? merged : undefined;
280
+ }
281
+ const ALL_PLATFORMS = ['codebuddy', 'claude', 'cursor', 'copilot'];
282
+ function parsePlatformsCsv(csv) {
283
+ if (!csv?.trim())
284
+ return [...ALL_PLATFORMS];
285
+ const parts = csv.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
286
+ const allowed = new Set(ALL_PLATFORMS);
287
+ const filtered = parts.filter((p) => allowed.has(p));
288
+ return filtered.length > 0 ? filtered : [...ALL_PLATFORMS];
289
+ }
290
+ function parseCommandsCsv(csv) {
291
+ if (!csv?.trim())
292
+ return [...DEFAULT_COMMANDS];
293
+ const parts = csv.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
294
+ const allowed = new Set(DEFAULT_COMMANDS);
295
+ const filtered = parts.filter((c) => allowed.has(c));
296
+ return filtered.length > 0 ? filtered : [...DEFAULT_COMMANDS];
297
+ }
298
+ export async function runInit(projectRoot, cli = {}) {
299
+ console.log(chalk.bold('\n Modus — init\n'));
300
+ // ── Scan existing AI tool configurations ──────────────────────────────────
301
+ const detectedTools = detectExistingAITools(projectRoot);
302
+ if (detectedTools.length > 0) {
303
+ console.log(chalk.cyan(' 检测到已有 AI 工具配置:'));
304
+ for (const t of detectedTools) {
305
+ console.log(chalk.green(` ✓ ${t.label}`) + chalk.dim(` — ${t.artifacts.length} 个文件`));
306
+ for (const a of t.artifacts.slice(0, 4)) {
307
+ console.log(chalk.dim(` ${a}`));
308
+ }
309
+ if (t.artifacts.length > 4) {
310
+ console.log(chalk.dim(` ... 共 ${t.artifacts.length} 个`));
311
+ }
312
+ }
313
+ console.log(chalk.dim(' 这些配置将在 /modus:init 时被读取并融入业务 Skills 与团队约定 Skill。\n'));
255
314
  }
256
- if (!isFirstRun && nonInteractive && cli.teamName) {
257
- config = { ...config, teamName: cli.teamName };
315
+ const configPath = path.join(projectRoot, 'modus', 'config.yaml');
316
+ const isFirstRun = !fileExists(configPath);
317
+ if (!isFirstRun && !cli.force) {
318
+ console.error(chalk.red(' 项目已存在 modus/config.yaml。请加 --force 以覆盖重新生成 .codebuddy/ 文件。'));
319
+ process.exitCode = 1;
320
+ return;
258
321
  }
259
- let enabledCommands;
260
- if (nonInteractive) {
261
- enabledCommands = parseCommandsCsv(cli.commands);
322
+ let config = loadConfig(projectRoot);
323
+ if (isFirstRun) {
324
+ const autoStack = cli.techStack || detectTechStack(projectRoot) || undefined;
325
+ if (autoStack) {
326
+ console.log(chalk.dim(` 已自动检测到技术栈:${chalk.cyan(autoStack)}`));
327
+ }
328
+ config = {
329
+ ...config,
330
+ techStack: autoStack,
331
+ context: cli.context || undefined,
332
+ tapdProjectId: cli.tapdProjectId || undefined,
333
+ teamName: cli.teamName || undefined,
334
+ };
262
335
  }
263
336
  else {
264
- const { enabledCommands: ec } = await inquirer.prompt([
265
- {
266
- type: 'checkbox',
267
- name: 'enabledCommands',
268
- message: 'Enable commands:',
269
- choices: [
270
- { name: '/modus:init — Analyze project and build business Skills', value: 'init', checked: true },
271
- { name: '/modus:vibe — Context-aware vibe coding', value: 'vibe', checked: true },
272
- { name: '/modus:plan — Plan mode with Skill-backed context', value: 'plan', checked: true },
273
- { name: '/modus:spec — OpenSpec-style spec-driven development', value: 'spec', checked: true },
274
- { name: '/modus:harness Full dual-loop multi-agent Harness', value: 'harness', checked: true },
275
- ],
276
- },
277
- ]);
278
- enabledCommands = ec;
337
+ if (cli.techStack)
338
+ config = { ...config, techStack: cli.techStack };
339
+ if (cli.context)
340
+ config = { ...config, context: cli.context };
341
+ if (cli.tapdProjectId)
342
+ config = { ...config, tapdProjectId: cli.tapdProjectId };
343
+ if (cli.teamName)
344
+ config = { ...config, teamName: cli.teamName };
345
+ }
346
+ // Merge MCP servers from detected tools (existing/CLI-provided entries win)
347
+ if (detectedTools.some((t) => t.mcpServers)) {
348
+ const existingMcpCount = Object.keys(config.mcpServers ?? {}).length;
349
+ const merged = mergeMcpServers(config.mcpServers, detectedTools);
350
+ if (merged) {
351
+ config = { ...config, mcpServers: merged };
352
+ const importedCount = Object.keys(merged).length - existingMcpCount;
353
+ if (importedCount > 0) {
354
+ console.log(chalk.dim(` 已从已有 AI 工具配置中导入 ${importedCount} 个 MCP 服务器配置。`));
355
+ }
356
+ }
279
357
  }
358
+ const enabledCommands = parseCommandsCsv(cli.commands);
359
+ // Platform selection: default to all four — user deletes the dirs they don't need
360
+ const selectedPlatforms = parsePlatformsCsv(cli.platforms ?? undefined);
280
361
  config.commands = { enabled: enabledCommands };
362
+ config.platforms = selectedPlatforms;
281
363
  config.version = '1';
364
+ config.modusBuildVersion = MODUS_VERSION;
282
365
  ensureDir(path.join(projectRoot, 'modus', 'specs'));
283
366
  ensureDir(path.join(projectRoot, 'modus', 'changes'));
284
367
  ensureDir(path.join(projectRoot, 'modus', 'plans'));
@@ -288,22 +371,52 @@ export async function runInit(projectRoot, cli = {}) {
288
371
  ensureDir(path.join(projectRoot, 'modus', 'sessions'));
289
372
  saveConfig(projectRoot, config);
290
373
  console.log(chalk.green(' ✓ modus/config.yaml written'));
291
- console.log(chalk.cyan('\n Generating CodeBuddy files...'));
374
+ const platformLabels = {
375
+ codebuddy: 'CodeBuddy (.codebuddy/)',
376
+ claude: 'Claude Code (.claude/ + CLAUDE.md)',
377
+ cursor: 'Cursor (.cursor/rules/ + mcp.json)',
378
+ copilot: 'Copilot (.github/copilot-instructions.md)',
379
+ };
380
+ console.log(chalk.cyan('\n Generating platform files...'));
381
+ for (const p of selectedPlatforms) {
382
+ console.log(chalk.dim(` → ${platformLabels[p] ?? p}`));
383
+ }
292
384
  if (config.teamName) {
293
385
  console.log(chalk.dim(` 将从团队目录复制 Skills:~/.codebuddy/team/${config.teamName}/`));
294
386
  }
295
- generateCodeBuddyFiles(projectRoot, config, { syncScopes: Boolean(cli.syncScopes) });
296
- const skillCount = 13;
387
+ generateAllPlatformFiles(projectRoot, config, { syncScopes: Boolean(cli.syncScopes) });
297
388
  const cmdCount = enabledCommands.length;
298
- console.log(chalk.green(` ✓ ${skillCount} skills → .codebuddy/skills/modus-*/SKILL.md`));
299
- console.log(chalk.green(` ✓ ${cmdCount} commands → .codebuddy/commands/modus/*.md`));
300
- console.log(chalk.green('8 agents → .codebuddy/agents/modus-harness-0*.md'));
301
- console.log(chalk.green('5 hooks → .codebuddy/hooks/*.py'));
302
- console.log(chalk.green(' ✓ 2 rules → .codebuddy/rules/modus-*/RULE.mdc'));
303
- console.log(chalk.green(' ✓ settings → .codebuddy/settings.json (hooks + MCP)'));
304
- console.log(chalk.bold('\n Ready! Open CodeBuddy and run:'));
389
+ if (selectedPlatforms.includes('codebuddy')) {
390
+ const skillCount = 14;
391
+ console.log(chalk.green(`[CodeBuddy] ${skillCount} skills → .codebuddy/skills/modus-*/SKILL.md`));
392
+ console.log(chalk.green(`[CodeBuddy] ${cmdCount} commands → .codebuddy/commands/modus/*.md`));
393
+ console.log(chalk.green(' ✓ [CodeBuddy] 8 agents → .codebuddy/agents/modus-harness-0*.md'));
394
+ console.log(chalk.green(' ✓ [CodeBuddy] 5 hooks → .codebuddy/hooks/*.py'));
395
+ console.log(chalk.green(' [CodeBuddy] 2 rules → .codebuddy/rules/modus-*/RULE.mdc'));
396
+ }
397
+ if (selectedPlatforms.includes('claude')) {
398
+ console.log(chalk.green(` ✓ [Claude] ${cmdCount} commands → .claude/commands/modus/*.md`));
399
+ console.log(chalk.green(' ✓ [Claude] 8 agents → .claude/agents/modus-harness-*.md'));
400
+ console.log(chalk.green(' ✓ [Claude] 2 rules → .claude/rules/modus-*.md'));
401
+ console.log(chalk.green(' ✓ [Claude] constitution → CLAUDE.md'));
402
+ }
403
+ if (selectedPlatforms.includes('cursor')) {
404
+ console.log(chalk.green(` ✓ [Cursor] ${cmdCount + 1} rules → .cursor/rules/modus-*.mdc`));
405
+ console.log(chalk.green(' ✓ [Cursor] harness agents merged → .cursor/rules/modus-harness-agents.mdc'));
406
+ }
407
+ if (selectedPlatforms.includes('copilot')) {
408
+ console.log(chalk.green(' ✓ [Copilot] instructions → .github/copilot-instructions.md'));
409
+ }
410
+ console.log(chalk.bold('\n Ready! Open your AI tool and run:'));
305
411
  console.log(chalk.yellow(' /modus:init') + ' — scan your codebase and build business Skills');
306
412
  console.log(chalk.yellow(' /modus:vibe') + ' — start context-aware coding');
307
- console.log(chalk.dim('\n Tip: Edit modus/config.yaml (constitution.*) then run `modus update` to refresh rules.\n'));
413
+ console.log(chalk.dim('\n Tip: Edit modus/config.yaml (constitution.* and platforms) then run `modus update` to refresh all platform files.'));
414
+ console.log(chalk.dim(' Note: After git clone to a different path, run `modus rehook` to fix CodeBuddy hook script paths.\n'));
415
+ // Report init event after all files are written (config is now saved so collectorUrl is readable)
416
+ track(projectRoot, {
417
+ event_type: 'init.registered',
418
+ command: 'init',
419
+ payload: { isFirstRun, enabledCommandCount: enabledCommands.length, platformCount: selectedPlatforms.length },
420
+ });
308
421
  }
309
422
  //# sourceMappingURL=init.js.map