@modus-ai/modus 0.1.5 → 0.1.7
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.
- package/dist/cli/index.js +28 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +183 -216
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +15 -6
- package/dist/commands/update.js.map +1 -1
- package/dist/generators/claude.d.ts +9 -0
- package/dist/generators/claude.d.ts.map +1 -0
- package/dist/generators/claude.js +256 -0
- package/dist/generators/claude.js.map +1 -0
- package/dist/generators/copilot.d.ts +9 -0
- package/dist/generators/copilot.d.ts.map +1 -0
- package/dist/generators/copilot.js +154 -0
- package/dist/generators/copilot.js.map +1 -0
- package/dist/generators/cursor.d.ts +9 -0
- package/dist/generators/cursor.d.ts.map +1 -0
- package/dist/generators/cursor.js +220 -0
- package/dist/generators/cursor.js.map +1 -0
- package/dist/generators/index.d.ts +9 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +26 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/utils/config.d.ts +15 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js.map +1 -1
- package/package.json +1 -1
- package/templates/hooks/session-start.py +51 -1
- package/templates/skills/modus-init/SKILL.md +75 -0
- package/templates/skills/modus-plan/SKILL.md +22 -0
- package/templates/skills/modus-spec/SKILL.md +22 -0
package/dist/cli/index.js
CHANGED
|
@@ -17,19 +17,32 @@ const pkg = require('../../package.json');
|
|
|
17
17
|
const program = new Command();
|
|
18
18
|
program
|
|
19
19
|
.name('modus')
|
|
20
|
-
.description('Modus — Business-grounded AI coding accelerator
|
|
20
|
+
.description('Modus — Business-grounded AI coding accelerator\n\n' +
|
|
21
21
|
' Quick start:\n' +
|
|
22
|
-
' modus init
|
|
23
|
-
' /modus:init
|
|
24
|
-
' /modus:auto [tapd-url]
|
|
22
|
+
' modus init Initialize project — generates files for all selected AI platforms\n' +
|
|
23
|
+
' /modus:init (in your AI tool) Scan codebase, build business Skills\n' +
|
|
24
|
+
' /modus:auto [tapd-url] Smart mode recommendation — reads TAPD, picks best command\n\n' +
|
|
25
|
+
' Platforms supported:\n' +
|
|
26
|
+
' CodeBuddy .codebuddy/ Skills / Agents / Hooks — full support\n' +
|
|
27
|
+
' Claude .claude/ + CLAUDE.md Sub-Agents — full support\n' +
|
|
28
|
+
' Cursor .cursor/rules/ Rules + MCP — Harness degrades to single-agent\n' +
|
|
29
|
+
' Copilot .github/copilot-instructions.md Single file, single-agent\n\n' +
|
|
30
|
+
' Upgrading (after npm install -g @modus-ai/modus):\n' +
|
|
31
|
+
' modus update Regenerate all platform files from latest templates\n' +
|
|
32
|
+
' (or just start a conversation — session hook auto-detects version change)\n\n' +
|
|
25
33
|
' After git clone to a new machine:\n' +
|
|
26
|
-
' modus rehook
|
|
34
|
+
' modus rehook Fix hook script paths in .codebuddy/settings.json')
|
|
27
35
|
.version(pkg.version);
|
|
28
36
|
program
|
|
29
37
|
.command('init')
|
|
30
38
|
.description('Initialize Modus in the current project\n' +
|
|
31
|
-
' Generates
|
|
32
|
-
' After CLI init, run /modus:init in
|
|
39
|
+
' Generates configuration files for all selected AI platforms.\n' +
|
|
40
|
+
' After CLI init, run /modus:init in your AI tool to scan codebase and build business Skills.\n\n' +
|
|
41
|
+
' Platform files generated by default (all four):\n' +
|
|
42
|
+
' CodeBuddy → .codebuddy/ (Skills, Agents, Hooks, Rules)\n' +
|
|
43
|
+
' Claude → .claude/ + CLAUDE.md\n' +
|
|
44
|
+
' Cursor → .cursor/rules/ + mcp.json\n' +
|
|
45
|
+
' Copilot → .github/copilot-instructions.md')
|
|
33
46
|
.option('--root <path>', 'Project root directory', process.cwd())
|
|
34
47
|
.option('-y, --yes', 'Skip all prompts; use flags + defaults (non-interactive)')
|
|
35
48
|
.option('--tech-stack <stack>', 'Tech stack, e.g. "Java Spring Boot, MySQL, Redis"')
|
|
@@ -37,6 +50,7 @@ program
|
|
|
37
50
|
.option('--tapd-project-id <id>', 'TAPD project ID (optional, enables /modus:harness Bug creation)')
|
|
38
51
|
.option('--team-name <name>', 'Team name — copies Skills from ~/.codebuddy/team/<name>/')
|
|
39
52
|
.option('--commands <csv>', 'Commands to enable, e.g. "init,vibe,plan,spec,auto,harness" (default: all)')
|
|
53
|
+
.option('--platforms <csv>', 'AI platforms to generate, e.g. "codebuddy,claude" (default: all four)')
|
|
40
54
|
.option('--force', 'Re-generate all files even if already initialized (use with --yes)')
|
|
41
55
|
.option('--sync-scopes', 'Re-sync Skills from global/team directories (overwrites project copies)')
|
|
42
56
|
.action(async (opts) => {
|
|
@@ -48,15 +62,19 @@ program
|
|
|
48
62
|
tapdProjectId: opts.tapdProjectId,
|
|
49
63
|
teamName: opts.teamName,
|
|
50
64
|
commands: opts.commands,
|
|
65
|
+
platforms: opts.platforms,
|
|
51
66
|
force: opts.force,
|
|
52
67
|
syncScopes: opts.syncScopes,
|
|
53
68
|
});
|
|
54
69
|
});
|
|
55
70
|
program
|
|
56
71
|
.command('update')
|
|
57
|
-
.description('Re-generate
|
|
58
|
-
'
|
|
59
|
-
'
|
|
72
|
+
.description('Re-generate platform files from latest Modus templates\n' +
|
|
73
|
+
' Regenerates files for all platforms listed in modus/config.yaml (platforms field).\n' +
|
|
74
|
+
' Also stamps modusBuildVersion so the session hook knows files are up to date.\n' +
|
|
75
|
+
' Business Skills (modus-biz-*) and custom rules are never overwritten.\n\n' +
|
|
76
|
+
' Tip: The session-start hook auto-detects a version mismatch and runs this\n' +
|
|
77
|
+
' command silently — manual run is only needed if you want to force a refresh.')
|
|
60
78
|
.option('--root <path>', 'Project root directory', process.cwd())
|
|
61
79
|
.option('--sync-scopes', 'Also re-sync Skills/Rules from global/team directories')
|
|
62
80
|
.action(async (opts) => {
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAyB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAE1C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CACV,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -13,6 +13,12 @@ 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;
|
|
16
22
|
}
|
|
17
23
|
/** One detected AI coding tool with its relevant artefacts */
|
|
18
24
|
export interface DetectedAITool {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAiBA,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;AAyTD,wBAAsB,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoL1F"}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,36 +1,16 @@
|
|
|
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
6
|
import inquirer from 'inquirer';
|
|
6
7
|
import { loadConfig, saveConfig } from '../utils/config.js';
|
|
7
|
-
import {
|
|
8
|
+
import { generateAllPlatformFiles } from '../generators/index.js';
|
|
8
9
|
import { fileExists, ensureDir } from '../utils/file-system.js';
|
|
9
10
|
import { track } from '../utils/analytics.js';
|
|
11
|
+
const _require = createRequire(import.meta.url);
|
|
12
|
+
const MODUS_VERSION = _require('../../package.json').version;
|
|
10
13
|
const DEFAULT_COMMANDS = ['init', 'vibe', 'plan', 'spec', 'auto', 'harness'];
|
|
11
|
-
function isInteractiveTerminal() {
|
|
12
|
-
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
13
|
-
}
|
|
14
|
-
function printNonInteractiveHelp(projectRoot) {
|
|
15
|
-
console.log(chalk.yellow('\n 当前环境无法交互输入(例如:在 AI 助手里跑命令、或 CI 管道)。\n'));
|
|
16
|
-
console.log(chalk.bold(' 请任选其一:\n'));
|
|
17
|
-
console.log(chalk.cyan(' 方式 A — 在本机「真实终端」里执行(有逐步提问):'));
|
|
18
|
-
console.log(chalk.white(` cd ${projectRoot}`));
|
|
19
|
-
console.log(chalk.white(' modus init\n'));
|
|
20
|
-
console.log(chalk.cyan(' 方式 B — 一条命令非交互完成(适合脚本 / AI 代跑):'));
|
|
21
|
-
console.log(chalk.white(' modus init --yes \\'));
|
|
22
|
-
console.log(chalk.white(' --tech-stack "Java Spring Boot, MySQL, Redis" \\'));
|
|
23
|
-
console.log(chalk.white(' --context "后端多租户 SaaS 服务" \\'));
|
|
24
|
-
console.log(chalk.gray(' [--tapd-project-id "12345678"] \\'));
|
|
25
|
-
console.log(chalk.gray(' [--commands "init,vibe,plan,spec,harness"]'));
|
|
26
|
-
console.log(chalk.gray('\n 各参数含义:'));
|
|
27
|
-
console.log(chalk.gray(' --tech-stack 技术栈,写入 modus/config.yaml'));
|
|
28
|
-
console.log(chalk.gray(' --context 项目一句话描述,给 AI 当背景'));
|
|
29
|
-
console.log(chalk.gray(' --tapd-project-id 可选,TAPD 项目 ID'));
|
|
30
|
-
console.log(chalk.gray(' --team-name 可选,团队名称,复用 ~/.codebuddy/team/<name>/ 的 Skills'));
|
|
31
|
-
console.log(chalk.gray(' --commands 可选,逗号分隔,默认五个全开'));
|
|
32
|
-
console.log(chalk.gray(' --force 已初始化过时仍覆盖(配合 --yes)\n'));
|
|
33
|
-
}
|
|
34
14
|
/**
|
|
35
15
|
* Scan the project root for well-known build/config files and infer the tech stack.
|
|
36
16
|
* For package.json, also reads dependencies to detect common frameworks.
|
|
@@ -299,6 +279,82 @@ function mergeMcpServers(existing, detected) {
|
|
|
299
279
|
}
|
|
300
280
|
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
301
281
|
}
|
|
282
|
+
const ALL_PLATFORMS = ['codebuddy', 'claude', 'cursor', 'copilot'];
|
|
283
|
+
function parsePlatformsCsv(csv) {
|
|
284
|
+
if (!csv?.trim())
|
|
285
|
+
return [...ALL_PLATFORMS];
|
|
286
|
+
const parts = csv.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
287
|
+
const allowed = new Set(ALL_PLATFORMS);
|
|
288
|
+
const filtered = parts.filter((p) => allowed.has(p));
|
|
289
|
+
return filtered.length > 0 ? filtered : [...ALL_PLATFORMS];
|
|
290
|
+
}
|
|
291
|
+
function isInteractiveTerminal() {
|
|
292
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Remove modus-managed files for a platform that the user chose not to keep.
|
|
296
|
+
* Only deletes files/dirs that modus owns — never touches user files.
|
|
297
|
+
*/
|
|
298
|
+
function removePlatformFiles(projectRoot, platform) {
|
|
299
|
+
const rm = (p) => {
|
|
300
|
+
const full = path.join(projectRoot, p);
|
|
301
|
+
try {
|
|
302
|
+
if (fs.existsSync(full)) {
|
|
303
|
+
fs.rmSync(full, { recursive: true, force: true });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
catch { /* non-fatal */ }
|
|
307
|
+
};
|
|
308
|
+
// Remove modus-generated files matching a glob-like prefix in a directory
|
|
309
|
+
const rmGlob = (dir, prefix) => {
|
|
310
|
+
const fullDir = path.join(projectRoot, dir);
|
|
311
|
+
if (!fs.existsSync(fullDir))
|
|
312
|
+
return;
|
|
313
|
+
try {
|
|
314
|
+
for (const entry of fs.readdirSync(fullDir)) {
|
|
315
|
+
if (entry.startsWith(prefix)) {
|
|
316
|
+
fs.rmSync(path.join(fullDir, entry), { recursive: true, force: true });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch { /* non-fatal */ }
|
|
321
|
+
};
|
|
322
|
+
// Remove modus section markers from a file (between start/end comment markers)
|
|
323
|
+
const removeSection = (filePath, startMarker, endMarker) => {
|
|
324
|
+
const full = path.join(projectRoot, filePath);
|
|
325
|
+
if (!fs.existsSync(full))
|
|
326
|
+
return;
|
|
327
|
+
try {
|
|
328
|
+
let content = fs.readFileSync(full, 'utf-8');
|
|
329
|
+
const startIdx = content.indexOf(startMarker);
|
|
330
|
+
const endIdx = content.indexOf(endMarker);
|
|
331
|
+
if (startIdx !== -1 && endIdx !== -1) {
|
|
332
|
+
content = content.slice(0, startIdx) + content.slice(endIdx + endMarker.length);
|
|
333
|
+
fs.writeFileSync(full, content.trimEnd() + '\n', 'utf-8');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
catch { /* non-fatal */ }
|
|
337
|
+
};
|
|
338
|
+
if (platform === 'codebuddy') {
|
|
339
|
+
rmGlob('.codebuddy/skills', 'modus-');
|
|
340
|
+
rm('.codebuddy/commands/modus');
|
|
341
|
+
rmGlob('.codebuddy/agents', 'modus-');
|
|
342
|
+
rm('.codebuddy/hooks');
|
|
343
|
+
rmGlob('.codebuddy/rules', 'modus-');
|
|
344
|
+
}
|
|
345
|
+
if (platform === 'claude') {
|
|
346
|
+
rm('.claude/commands/modus');
|
|
347
|
+
rmGlob('.claude/agents', 'modus-');
|
|
348
|
+
rmGlob('.claude/rules', 'modus-');
|
|
349
|
+
removeSection('CLAUDE.md', '<!-- modus:constitution:start -->', '<!-- modus:constitution:end -->');
|
|
350
|
+
}
|
|
351
|
+
if (platform === 'cursor') {
|
|
352
|
+
rmGlob('.cursor/rules', 'modus-');
|
|
353
|
+
}
|
|
354
|
+
if (platform === 'copilot') {
|
|
355
|
+
rm('.github/copilot-instructions.md');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
302
358
|
function parseCommandsCsv(csv) {
|
|
303
359
|
if (!csv?.trim())
|
|
304
360
|
return [...DEFAULT_COMMANDS];
|
|
@@ -326,169 +382,34 @@ export async function runInit(projectRoot, cli = {}) {
|
|
|
326
382
|
}
|
|
327
383
|
const configPath = path.join(projectRoot, 'modus', 'config.yaml');
|
|
328
384
|
const isFirstRun = !fileExists(configPath);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
printNonInteractiveHelp(projectRoot);
|
|
385
|
+
if (!isFirstRun && !cli.force) {
|
|
386
|
+
console.error(chalk.red(' 项目已存在 modus/config.yaml。请加 --force 以覆盖重新生成 .codebuddy/ 文件。'));
|
|
332
387
|
process.exitCode = 1;
|
|
333
388
|
return;
|
|
334
389
|
}
|
|
335
|
-
if (!isFirstRun) {
|
|
336
|
-
if (nonInteractive) {
|
|
337
|
-
if (!cli.force) {
|
|
338
|
-
console.error(chalk.red(' 项目已存在 modus/config.yaml。非交互模式下请加 --force 以覆盖生成 .codebuddy/ 文件。'));
|
|
339
|
-
process.exitCode = 1;
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
console.log(chalk.cyan(' --force:将重新生成 .codebuddy/ 与配置(保留已有 YAML 中未在 CLI 传入的字段逻辑见下方)'));
|
|
343
|
-
}
|
|
344
|
-
else {
|
|
345
|
-
const { overwrite } = await inquirer.prompt([
|
|
346
|
-
{
|
|
347
|
-
type: 'confirm',
|
|
348
|
-
name: 'overwrite',
|
|
349
|
-
message: 'Modus is already initialized. Re-generate all files?',
|
|
350
|
-
default: true,
|
|
351
|
-
},
|
|
352
|
-
]);
|
|
353
|
-
if (!overwrite) {
|
|
354
|
-
console.log(chalk.gray(' Aborted.'));
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
390
|
let config = loadConfig(projectRoot);
|
|
360
391
|
if (isFirstRun) {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
console.log(chalk.dim(` 已自动检测到技术栈:${chalk.cyan(autoStack)}`));
|
|
365
|
-
}
|
|
366
|
-
config = {
|
|
367
|
-
...config,
|
|
368
|
-
techStack: autoStack,
|
|
369
|
-
context: cli.context || undefined,
|
|
370
|
-
tapdProjectId: cli.tapdProjectId || undefined,
|
|
371
|
-
teamName: cli.teamName || undefined,
|
|
372
|
-
};
|
|
392
|
+
const autoStack = cli.techStack || detectTechStack(projectRoot) || undefined;
|
|
393
|
+
if (autoStack) {
|
|
394
|
+
console.log(chalk.dim(` 已自动检测到技术栈:${chalk.cyan(autoStack)}`));
|
|
373
395
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
console.log(chalk.dim(' 接下来会问你 3 个问题(可直接回车用默认空值),再勾选要启用的命令。\n'));
|
|
382
|
-
}
|
|
383
|
-
const answers = await inquirer.prompt([
|
|
384
|
-
{
|
|
385
|
-
type: 'input',
|
|
386
|
-
name: 'techStack',
|
|
387
|
-
message: '技术栈(例如 "Java Spring Boot, MySQL, Redis"):',
|
|
388
|
-
default: detectedStack || '',
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
type: 'input',
|
|
392
|
-
name: 'context',
|
|
393
|
-
message: '项目一句话描述(作为 AI 背景):',
|
|
394
|
-
default: '',
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
type: 'input',
|
|
398
|
-
name: 'tapdProjectId',
|
|
399
|
-
message: 'TAPD 项目 ID(可选,用于 /harness 命令):',
|
|
400
|
-
default: '',
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
type: 'input',
|
|
404
|
-
name: 'teamName',
|
|
405
|
-
message: '团队名称(可选,复用 ~/.codebuddy/team/<name>/ 的 Skills,留空跳过):',
|
|
406
|
-
default: config.teamName || '',
|
|
407
|
-
},
|
|
408
|
-
{
|
|
409
|
-
type: 'input',
|
|
410
|
-
name: 'collectorUrl',
|
|
411
|
-
message: 'Modus 埋点上报地址(可选,留空跳过,例如 http://43.139.34.70:3456):',
|
|
412
|
-
default: (config.analytics?.collectorUrl) ?? '',
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
type: 'confirm',
|
|
416
|
-
name: 'configureMcp',
|
|
417
|
-
message: '是否配置 MCP 服务器?(可在 .codebuddy/settings.json 中手动编辑)',
|
|
418
|
-
default: false,
|
|
419
|
-
},
|
|
420
|
-
]);
|
|
421
|
-
let mcpServers;
|
|
422
|
-
if (answers.configureMcp) {
|
|
423
|
-
console.log(chalk.dim('\n MCP 服务器配置(直接回车跳过某项)'));
|
|
424
|
-
const mcpAnswers = await inquirer.prompt([
|
|
425
|
-
{
|
|
426
|
-
type: 'input',
|
|
427
|
-
name: 'tapdMcpCommand',
|
|
428
|
-
message: ' TAPD MCP 启动命令(例如 "npx @your-org/tapd-mcp-server",留空跳过):',
|
|
429
|
-
default: '',
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
type: 'input',
|
|
433
|
-
name: 'extraMcpName',
|
|
434
|
-
message: ' 其他 MCP 服务名称(留空跳过):',
|
|
435
|
-
default: '',
|
|
436
|
-
},
|
|
437
|
-
{
|
|
438
|
-
type: 'input',
|
|
439
|
-
name: 'extraMcpCommand',
|
|
440
|
-
message: ' 其他 MCP 启动命令(留空跳过):',
|
|
441
|
-
default: '',
|
|
442
|
-
},
|
|
443
|
-
]);
|
|
444
|
-
mcpServers = {};
|
|
445
|
-
if (mcpAnswers.tapdMcpCommand) {
|
|
446
|
-
const [cmd, ...args] = mcpAnswers.tapdMcpCommand.trim().split(/\s+/);
|
|
447
|
-
mcpServers['tapd'] = {
|
|
448
|
-
type: 'stdio',
|
|
449
|
-
command: cmd,
|
|
450
|
-
args,
|
|
451
|
-
description: 'TAPD story / bug management',
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
if (mcpAnswers.extraMcpName && mcpAnswers.extraMcpCommand) {
|
|
455
|
-
const [cmd, ...args] = mcpAnswers.extraMcpCommand.trim().split(/\s+/);
|
|
456
|
-
mcpServers[mcpAnswers.extraMcpName] = {
|
|
457
|
-
type: 'stdio',
|
|
458
|
-
command: cmd,
|
|
459
|
-
args,
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
if (Object.keys(mcpServers).length === 0)
|
|
463
|
-
mcpServers = undefined;
|
|
464
|
-
}
|
|
465
|
-
const collectorUrl = answers.collectorUrl?.trim() || undefined;
|
|
466
|
-
config = {
|
|
467
|
-
...config,
|
|
468
|
-
techStack: answers.techStack || undefined,
|
|
469
|
-
context: answers.context || undefined,
|
|
470
|
-
tapdProjectId: answers.tapdProjectId || undefined,
|
|
471
|
-
teamName: answers.teamName || undefined,
|
|
472
|
-
...(mcpServers ? { mcpServers } : {}),
|
|
473
|
-
analytics: {
|
|
474
|
-
enabled: true,
|
|
475
|
-
collectorUrl,
|
|
476
|
-
...(config.analytics?.token ? { token: config.analytics.token } : {}),
|
|
477
|
-
},
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
else if (nonInteractive && cli.techStack) {
|
|
482
|
-
config = { ...config, techStack: cli.techStack };
|
|
483
|
-
}
|
|
484
|
-
if (!isFirstRun && nonInteractive && cli.context) {
|
|
485
|
-
config = { ...config, context: cli.context };
|
|
486
|
-
}
|
|
487
|
-
if (!isFirstRun && nonInteractive && cli.tapdProjectId) {
|
|
488
|
-
config = { ...config, tapdProjectId: cli.tapdProjectId };
|
|
396
|
+
config = {
|
|
397
|
+
...config,
|
|
398
|
+
techStack: autoStack,
|
|
399
|
+
context: cli.context || undefined,
|
|
400
|
+
tapdProjectId: cli.tapdProjectId || undefined,
|
|
401
|
+
teamName: cli.teamName || undefined,
|
|
402
|
+
};
|
|
489
403
|
}
|
|
490
|
-
|
|
491
|
-
|
|
404
|
+
else {
|
|
405
|
+
if (cli.techStack)
|
|
406
|
+
config = { ...config, techStack: cli.techStack };
|
|
407
|
+
if (cli.context)
|
|
408
|
+
config = { ...config, context: cli.context };
|
|
409
|
+
if (cli.tapdProjectId)
|
|
410
|
+
config = { ...config, tapdProjectId: cli.tapdProjectId };
|
|
411
|
+
if (cli.teamName)
|
|
412
|
+
config = { ...config, teamName: cli.teamName };
|
|
492
413
|
}
|
|
493
414
|
// Merge MCP servers from detected tools (existing/CLI-provided entries win)
|
|
494
415
|
if (detectedTools.some((t) => t.mcpServers)) {
|
|
@@ -502,28 +423,7 @@ export async function runInit(projectRoot, cli = {}) {
|
|
|
502
423
|
}
|
|
503
424
|
}
|
|
504
425
|
}
|
|
505
|
-
|
|
506
|
-
if (nonInteractive) {
|
|
507
|
-
enabledCommands = parseCommandsCsv(cli.commands);
|
|
508
|
-
}
|
|
509
|
-
else {
|
|
510
|
-
const { enabledCommands: ec } = await inquirer.prompt([
|
|
511
|
-
{
|
|
512
|
-
type: 'checkbox',
|
|
513
|
-
name: 'enabledCommands',
|
|
514
|
-
message: 'Enable commands:',
|
|
515
|
-
choices: [
|
|
516
|
-
{ name: '/modus:init — Analyze project and build business Skills', value: 'init', checked: true },
|
|
517
|
-
{ name: '/modus:vibe — Context-aware vibe coding', value: 'vibe', checked: true },
|
|
518
|
-
{ name: '/modus:plan — Plan mode with Skill-backed context', value: 'plan', checked: true },
|
|
519
|
-
{ name: '/modus:spec — OpenSpec-style spec-driven development', value: 'spec', checked: true },
|
|
520
|
-
{ name: '/modus:auto — Smart mode recommendation (reads TAPD, recommends vibe/plan/spec/harness)', value: 'auto', checked: true },
|
|
521
|
-
{ name: '/modus:harness — Full dual-loop multi-agent Harness', value: 'harness', checked: true },
|
|
522
|
-
],
|
|
523
|
-
},
|
|
524
|
-
]);
|
|
525
|
-
enabledCommands = ec;
|
|
526
|
-
}
|
|
426
|
+
const enabledCommands = parseCommandsCsv(cli.commands);
|
|
527
427
|
config.commands = { enabled: enabledCommands };
|
|
528
428
|
config.version = '1';
|
|
529
429
|
ensureDir(path.join(projectRoot, 'modus', 'specs'));
|
|
@@ -533,31 +433,98 @@ export async function runInit(projectRoot, cli = {}) {
|
|
|
533
433
|
ensureDir(path.join(projectRoot, 'modus', 'plans', 'archive'));
|
|
534
434
|
ensureDir(path.join(projectRoot, 'modus', 'changes', 'archive'));
|
|
535
435
|
ensureDir(path.join(projectRoot, 'modus', 'sessions'));
|
|
436
|
+
// ── Step 1: Generate ALL four platforms ──────────────────────────────────
|
|
437
|
+
// Always generate all so the user can see what each platform produces.
|
|
438
|
+
const allPlatforms = ['codebuddy', 'claude', 'cursor', 'copilot'];
|
|
439
|
+
config.platforms = allPlatforms;
|
|
440
|
+
config.modusBuildVersion = MODUS_VERSION;
|
|
536
441
|
saveConfig(projectRoot, config);
|
|
537
|
-
console.log(chalk.green(' ✓ modus/config.yaml written'));
|
|
538
|
-
console.log(chalk.cyan('\n Generating CodeBuddy files...'));
|
|
539
442
|
if (config.teamName) {
|
|
540
443
|
console.log(chalk.dim(` 将从团队目录复制 Skills:~/.codebuddy/team/${config.teamName}/`));
|
|
541
444
|
}
|
|
542
|
-
|
|
543
|
-
|
|
445
|
+
console.log(chalk.cyan('\n Generating platform files (all four)...'));
|
|
446
|
+
generateAllPlatformFiles(projectRoot, { ...config, platforms: allPlatforms }, {
|
|
447
|
+
syncScopes: Boolean(cli.syncScopes),
|
|
448
|
+
});
|
|
544
449
|
const cmdCount = enabledCommands.length;
|
|
545
|
-
console.log(chalk.green(` ✓
|
|
546
|
-
console.log(chalk.green(` ✓ ${cmdCount} commands
|
|
547
|
-
console.log(chalk.green(' ✓ 8 agents
|
|
548
|
-
console.log(chalk.green(' ✓ 5 hooks
|
|
549
|
-
console.log(chalk.green(
|
|
550
|
-
console.log(chalk.green(' ✓
|
|
551
|
-
console.log(chalk.
|
|
450
|
+
console.log(chalk.green(` ✓ [CodeBuddy] 14 skills → .codebuddy/skills/modus-*/SKILL.md`));
|
|
451
|
+
console.log(chalk.green(` ✓ [CodeBuddy] ${cmdCount} commands → .codebuddy/commands/modus/*.md`));
|
|
452
|
+
console.log(chalk.green(' ✓ [CodeBuddy] 8 agents → .codebuddy/agents/modus-harness-0*.md'));
|
|
453
|
+
console.log(chalk.green(' ✓ [CodeBuddy] 5 hooks → .codebuddy/hooks/*.py'));
|
|
454
|
+
console.log(chalk.green(` ✓ [Claude] ${cmdCount} commands → .claude/commands/modus/*.md`));
|
|
455
|
+
console.log(chalk.green(' ✓ [Claude] 8 agents → .claude/agents/modus-harness-*.md'));
|
|
456
|
+
console.log(chalk.green(' ✓ [Claude] constitution → CLAUDE.md'));
|
|
457
|
+
console.log(chalk.green(` ✓ [Cursor] ${cmdCount + 2} rules → .cursor/rules/modus-*.mdc`));
|
|
458
|
+
console.log(chalk.green(' ✓ [Copilot] instructions → .github/copilot-instructions.md'));
|
|
459
|
+
// ── Step 2: Ask user which platforms to keep ─────────────────────────────
|
|
460
|
+
// Non-interactive: --yes or --platforms flag or non-TTY → skip prompt
|
|
461
|
+
const platformsExplicitlySet = Boolean(cli.platforms?.trim());
|
|
462
|
+
const interactive = !cli.yes && !platformsExplicitlySet && isInteractiveTerminal();
|
|
463
|
+
let keptPlatforms = allPlatforms;
|
|
464
|
+
if (!interactive) {
|
|
465
|
+
// --platforms explicitly set → use that; otherwise keep all four
|
|
466
|
+
keptPlatforms = platformsExplicitlySet
|
|
467
|
+
? parsePlatformsCsv(cli.platforms)
|
|
468
|
+
: allPlatforms;
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
console.log(chalk.cyan('\n 以上四个平台的文件已全部生成,请选择你实际使用的平台(将移除其他平台的文件):'));
|
|
472
|
+
const { kept } = await inquirer.prompt({
|
|
473
|
+
type: 'checkbox',
|
|
474
|
+
name: 'kept',
|
|
475
|
+
message: '保留哪些平台?(空格选中/取消,回车确认)',
|
|
476
|
+
choices: [
|
|
477
|
+
{
|
|
478
|
+
name: 'CodeBuddy (.codebuddy/) — 框架首选,Skills/Agents/Hooks 完整支持',
|
|
479
|
+
value: 'codebuddy',
|
|
480
|
+
checked: true,
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
name: 'Claude Code (.claude/ + CLAUDE.md) — Sub-Agent 完整支持',
|
|
484
|
+
value: 'claude',
|
|
485
|
+
checked: true,
|
|
486
|
+
},
|
|
487
|
+
{
|
|
488
|
+
name: 'Cursor (.cursor/rules/ + mcp.json) — Rules/MCP,Harness 降级单 Agent',
|
|
489
|
+
value: 'cursor',
|
|
490
|
+
checked: true,
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
name: 'GitHub Copilot (.github/copilot-instructions.md) — 单文件,单 Agent',
|
|
494
|
+
value: 'copilot',
|
|
495
|
+
checked: true,
|
|
496
|
+
},
|
|
497
|
+
],
|
|
498
|
+
});
|
|
499
|
+
keptPlatforms = kept.filter((p) => ['codebuddy', 'claude', 'cursor', 'copilot'].includes(p));
|
|
500
|
+
if (keptPlatforms.length === 0)
|
|
501
|
+
keptPlatforms = allPlatforms; // 兜底
|
|
502
|
+
keptPlatforms = kept;
|
|
503
|
+
}
|
|
504
|
+
// ── Step 3: Remove files for discarded platforms ─────────────────────────
|
|
505
|
+
const discarded = allPlatforms.filter((p) => !keptPlatforms.includes(p));
|
|
506
|
+
if (discarded.length > 0) {
|
|
507
|
+
console.log(chalk.yellow(`\n 移除未选择的平台文件:${discarded.join(', ')}`));
|
|
508
|
+
for (const p of discarded) {
|
|
509
|
+
removePlatformFiles(projectRoot, p);
|
|
510
|
+
console.log(chalk.dim(` ✗ [${p}] 已移除`));
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
// ── Step 4: Persist selected platforms ───────────────────────────────────
|
|
514
|
+
config.platforms = keptPlatforms;
|
|
515
|
+
config.modusBuildVersion = MODUS_VERSION;
|
|
516
|
+
saveConfig(projectRoot, config);
|
|
517
|
+
console.log(chalk.green(`\n ✓ modus/config.yaml written (platforms: ${keptPlatforms.join(', ')})`));
|
|
518
|
+
console.log(chalk.bold('\n Ready! Open your AI tool and run:'));
|
|
552
519
|
console.log(chalk.yellow(' /modus:init') + ' — scan your codebase and build business Skills');
|
|
553
520
|
console.log(chalk.yellow(' /modus:vibe') + ' — start context-aware coding');
|
|
554
|
-
console.log(chalk.dim('\n Tip: Edit modus/config.yaml (constitution.*) then run `modus update` to refresh
|
|
555
|
-
console.log(chalk.dim(' Note: After git clone to a different path, run `modus rehook` to fix hook script paths.\n'));
|
|
521
|
+
console.log(chalk.dim('\n Tip: Edit modus/config.yaml (constitution.* and platforms) then run `modus update` to refresh all platform files.'));
|
|
522
|
+
console.log(chalk.dim(' Note: After git clone to a different path, run `modus rehook` to fix CodeBuddy hook script paths.\n'));
|
|
556
523
|
// Report init event after all files are written (config is now saved so collectorUrl is readable)
|
|
557
524
|
track(projectRoot, {
|
|
558
525
|
event_type: 'init.registered',
|
|
559
526
|
command: 'init',
|
|
560
|
-
payload: { isFirstRun, enabledCommandCount: enabledCommands.length },
|
|
527
|
+
payload: { isFirstRun, enabledCommandCount: enabledCommands.length, platformCount: keptPlatforms.length },
|
|
561
528
|
});
|
|
562
529
|
}
|
|
563
530
|
//# sourceMappingURL=init.js.map
|