@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
package/README.md CHANGED
@@ -22,34 +22,30 @@
22
22
 
23
23
  **需要 Node.js 18.0.0 或以上版本。**
24
24
 
25
- 全局安装 Modus:
25
+ 全局安装并初始化:
26
26
 
27
27
  ```bash
28
28
  npm install -g @modus-ai/modus
29
- ```
30
-
31
- 进入你的项目目录并初始化:
32
-
33
- ```bash
34
29
  cd your-project
35
- modus init
30
+ modus init # CLI 初始化,生成框架文件和配置
36
31
  ```
37
32
 
38
- 然后在 CodeBuddy IDE 中运行:
33
+ 然后在 CodeBuddy IDE 对话框中运行:
39
34
 
40
35
  ```
41
- /modus:init
36
+ /modus:init # 扫描代码,生成业务知识库
42
37
  ```
43
38
 
44
- ## 5 个核心命令
39
+ ## 6 个核心命令
45
40
 
46
- | 命令 | 用途 |
47
- |------|------|
48
- | `/modus:init` | 分析项目,生成业务/团队/技术三层知识库 + 知识目录 |
49
- | `/modus:vibe` | 氛围编程,三级渐进加载业务上下文(`--quick` 快速模式)|
50
- | `/modus:plan` | 功能规划,生成 proposal/design/tasks,支持断点续跑 |
51
- | `/modus:spec` | 规范开发,生成 delta specs(场景驱动验收)+ 知识提取 |
52
- | `/modus:harness` | 全自动双 Loop 多智能体流程,含知识注入/提取闭环 |
41
+ | 命令 | 用途 | 产出物位置 |
42
+ |------|------|-----------|
43
+ | `/modus:init` | 扫描项目,生成业务/团队/技术三层知识库 + 知识目录 | `.codebuddy/skills/` + `modus/knowledge-catalog.md` |
44
+ | `/modus:vibe` | 氛围编程,渐进式加载业务上下文后直接编码 | 直接修改代码,无新增文件 |
45
+ | `/modus:plan` | 功能规划,复杂度自动分级,含 ADR 决策记录和 pitfall 风险提示 | `modus/plans/{name}/` |
46
+ | `/modus:spec` | 规范开发,delta specs + GIVEN/WHEN/THEN 验收,含可选 verify + 冲突检测 | `modus/changes/{name}/`,归档合并到 `modus/specs/` |
47
+ | `/modus:auto` | 智能模式推荐:读 TAPD Story,四维评分,推荐 vibe/plan/spec/harness | 启动所选模式后按该模式产出 |
48
+ | `/modus:harness` | 全自动双 Loop 多智能体流程,8 个 SubAgent 协作,含知识沉淀闭环 | `modus/plans/active/{story-id}/` |
53
49
 
54
50
  ## 典型工作流
55
51
 
@@ -65,8 +61,8 @@ AI: 识别到 3 个业务域:order, payment, user
65
61
  你: /modus:vibe 帮我给订单模块加一个批量审批接口
66
62
  AI: [Level 1] 读取知识目录(200 tokens)
67
63
  [Level 2] 加载 order 域业务知识(3000 tokens,仅此一个域)
64
+ [Level 3] 按需读取 OrderService.java、OrderMapper.java
68
65
  我来实现批量审批接口...
69
- 📝 Skill 更新建议:发现 OrderStatus.PENDING_REVIEW 状态,建议更新 Skill
70
66
 
71
67
  你: /modus:harness https://tapd.cn/xxx/stories/view/1234567
72
68
  AI: [INIT] 注入知识:order[verified] | payment[proven]
@@ -88,28 +84,80 @@ Modus 的知识体系让 AI 从「冷启动」变为「越用越快」:
88
84
  ```
89
85
 
90
86
  **三层知识结构:**
91
- - **Layer 0-T** `modus-team-conventions` — 团队约定(代码规范、提交规范)
92
- - **Layer 1** `modus-tech-wiki` — 技术知识(架构决策、反模式库,跨项目积累)
93
- - **Layer 2** `modus-biz-*` — 业务知识(领域模型、业务规则、API 契约)
94
87
 
95
- **知识成熟度:** `draft` `verified` `proven`(自动提升 + 自动衰减,保持知识库健康)
88
+ | 层级 | Skill 文件 | 内容 | 生命周期 |
89
+ |------|-----------|------|---------|
90
+ | Layer 0-T | `modus-team-conventions` | 编码规范、提交规范、硬性约束 | 人工维护为主 |
91
+ | Layer 1 | `modus-tech-wiki` | 架构决策、反模式库(跨项目积累) | 工作流 ARCHIVE 自动积累 |
92
+ | Layer 2 | `modus-biz-{domain}` | 领域模型、业务规则、API 契约 | 每次 plan/spec/harness 后回写 |
93
+
94
+ **知识成熟度:** `draft` → `verified` → `proven`(在工作流中被引用后自动晋升,长期未引用自动衰减)
96
95
 
97
- **渐进加载:** Level 1(catalog,~200 tokens)→ Level 2(Skill,~3000 tokens/个)→ Level 3(代码文件,按需)节省约 59% token。
96
+ **渐进加载:** Level 1(catalog,~200 tokens)→ Level 2(Skill,~3000 tokens/个)→ Level 3(代码文件,按需),节省约 59% token。
98
97
 
99
98
  **项目宪法:** `modus/config.yaml` 的 `constitution.hard_rules` 是所有 SubAgent 的最高优先级约束,一次配置,永久生效。
100
99
 
100
+ ```yaml
101
+ constitution:
102
+ tech_stack: "Java 17 + Spring Boot 3 + MyBatis"
103
+ build_command: "mvn clean compile -q"
104
+ hard_rules:
105
+ - "Mapper 接口必须在 dao 包下"
106
+ - "金额字段使用 Long(单位:分)"
107
+ ```
108
+
109
+ ## `/modus:harness` 流程一览
110
+
111
+ ```
112
+ Loop 1(生产)
113
+ INIT → SA01 需求分析 → SA02 代码开发 → Gate A(编译)
114
+ → SA03/04/05 并行(测试/性能/安全)→ Gate B → SA06 代码评审 → Gate C
115
+
116
+ Loop 2(修复,有 P1/P2 时触发)
117
+ 精准重入受影响的 Sprint → Gate A → SA03/04/05 → SA06
118
+
119
+ 收尾
120
+ SA07 部署验证 → ARCHIVE 知识沉淀 → 人工 Final Review
121
+ ```
122
+
123
+ 每个 SubAgent 的产出物(`01-analysis.md` 至 `07-deploy-status.md` + `cr-report.md`)均存放在 `modus/plans/active/{story-id}/`,支持断点续跑。
124
+
125
+ ## 文件结构
126
+
127
+ ```
128
+ your-project/
129
+ ├── .codebuddy/
130
+ │ ├── skills/
131
+ │ │ ├── modus-team-conventions/SKILL.md ← Layer 0-T
132
+ │ │ ├── modus-tech-wiki/SKILL.md ← Layer 1
133
+ │ │ ├── modus-biz-{domain}/SKILL.md ← Layer 2(每域一个)
134
+ │ │ └── modus-harness-*/SKILL.md ← 8 个 SubAgent Skill
135
+ │ └── commands/modus/ ← 斜杠命令入口
136
+
137
+ └── modus/
138
+ ├── config.yaml ← 项目宪法
139
+ ├── knowledge-catalog.md ← 全景索引(~200 tokens)
140
+ ├── specs/{domain}/spec.md ← 主规格库(/spec 归档后)
141
+ ├── plans/{name}/ ← /plan 活跃目录
142
+ ├── plans/active/{story-id}/ ← /harness 产出物
143
+ ├── plans/archive/ ← /plan 归档
144
+ └── changes/ ← /spec 产出物及归档
145
+ ```
146
+
101
147
  ## 文档
102
148
 
103
- → **[Getting Started](docs/getting-started.md)**: 第一步
104
- → **[Commands](docs/commands.md)**: 命令详情
105
- → **[Concepts](docs/concepts.md)**: 核心概念(含知识分层架构)
106
- → **[Harness](docs/harness.md)**: 双 Loop 多智能体原理(含 HANDOFF 协议)
107
- → **[Knowledge](docs/knowledge.md)**: 知识体系详解
149
+ → **[Getting Started](docs/getting-started.md)**: 安装与第一步
150
+ → **[Commands Manual](docs/modus-commands-manual.md)**: 5 个命令完整用法(执行步骤、产出物、示例)
151
+ → **[Concepts](docs/concepts.md)**: 核心概念(知识分层、渐进加载、Project Constitution)
152
+ → **[Harness](docs/harness.md)**: 双 Loop 多智能体原理(含 HANDOFF 协议、Gate 规则)
153
+ → **[Knowledge](docs/knowledge.md)**: 知识体系生命周期与最佳实践
154
+ → **[Commands Reference](docs/commands.md)**: 命令快速参考
108
155
 
109
156
  ## CLI 命令
110
157
 
111
158
  ```bash
112
159
  modus init # 初始化项目(生成 .codebuddy/ 文件 + 知识目录)
160
+ modus rehook # 修复 hook 路径(git clone 到新机器/路径后执行)
113
161
  modus update # 升级后刷新文件
114
162
  modus config show # 查看当前配置
115
163
  modus config profile # 选择启用哪些命令
package/dist/cli/index.js CHANGED
@@ -5,24 +5,53 @@ import { runInit } from '../commands/init.js';
5
5
  import { runUpdate } from '../commands/update.js';
6
6
  import { runConfig } from '../commands/config.js';
7
7
  import { runGlobalInit, runGlobalList } from '../commands/global.js';
8
+ import { runStatus } from '../commands/status.js';
9
+ import { runDoctor } from '../commands/doctor.js';
10
+ import chalk from 'chalk';
11
+ import { runSkillList, runSkillShow, runSkillRefresh } from '../commands/skill.js';
12
+ import { rehookProject } from '../generators/codebuddy.js';
13
+ import { track } from '../utils/analytics.js';
14
+ import { loadConfig } from '../utils/config.js';
8
15
  const require = createRequire(import.meta.url);
9
16
  const pkg = require('../../package.json');
10
17
  const program = new Command();
11
18
  program
12
19
  .name('modus')
13
- .description('Modus — Business-grounded AI coding accelerator for CodeBuddy IDE')
20
+ .description('Modus — Business-grounded AI coding accelerator\n\n' +
21
+ ' Quick start:\n' +
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' +
33
+ ' After git clone to a new machine:\n' +
34
+ ' modus rehook Fix hook script paths in .codebuddy/settings.json')
14
35
  .version(pkg.version);
15
36
  program
16
37
  .command('init')
17
- .description('Initialize Modus in the current project (generates .codebuddy/ files)')
38
+ .description('Initialize Modus in the current project\n' +
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')
18
46
  .option('--root <path>', 'Project root directory', process.cwd())
19
47
  .option('-y, --yes', 'Skip all prompts; use flags + defaults (non-interactive)')
20
- .option('--tech-stack <stack>', 'Tech stack description, written to modus/config.yaml')
21
- .option('--context <text>', 'One-line project description used as AI context')
22
- .option('--tapd-project-id <id>', 'TAPD project ID (optional, for /harness command)')
48
+ .option('--tech-stack <stack>', 'Tech stack, e.g. "Java Spring Boot, MySQL, Redis"')
49
+ .option('--context <text>', 'One-line project description used as AI background context')
50
+ .option('--tapd-project-id <id>', 'TAPD project ID (optional, enables /modus:harness Bug creation)')
23
51
  .option('--team-name <name>', 'Team name — copies Skills from ~/.codebuddy/team/<name>/')
24
- .option('--commands <csv>', 'Comma-separated list of commands to enable (default: all)')
25
- .option('--force', 'Re-generate files even if already initialized (use with --yes)')
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)')
54
+ .option('--force', 'Re-generate all files even if already initialized (use with --yes)')
26
55
  .option('--sync-scopes', 'Re-sync Skills from global/team directories (overwrites project copies)')
27
56
  .action(async (opts) => {
28
57
  const projectRoot = path.resolve(opts.root);
@@ -33,26 +62,38 @@ program
33
62
  tapdProjectId: opts.tapdProjectId,
34
63
  teamName: opts.teamName,
35
64
  commands: opts.commands,
65
+ platforms: opts.platforms,
36
66
  force: opts.force,
37
67
  syncScopes: opts.syncScopes,
38
68
  });
39
69
  });
40
70
  program
41
71
  .command('update')
42
- .description('Re-generate .codebuddy/ skill and command files from latest templates')
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.')
43
78
  .option('--root <path>', 'Project root directory', process.cwd())
44
- .option('--sync-scopes', 'Re-sync Skills/Rules from global/team directories (overwrites project copies)')
79
+ .option('--sync-scopes', 'Also re-sync Skills/Rules from global/team directories')
45
80
  .action(async (opts) => {
46
81
  const projectRoot = path.resolve(opts.root);
82
+ track(projectRoot, { event_type: 'command.executed', command: 'update' });
47
83
  const updateOpts = { syncScopes: Boolean(opts.syncScopes) };
48
84
  await runUpdate(projectRoot, updateOpts);
49
85
  });
50
86
  program
51
87
  .command('config [subcommand]')
52
- .description('View or update Modus config. Subcommands: show | profile | set')
88
+ .description('View or edit modus/config.yaml\n' +
89
+ ' Subcommands:\n' +
90
+ ' show Print current config\n' +
91
+ ' profile Select which /modus:* commands to enable\n' +
92
+ ' set Update a single config key, e.g. modus config set tapdProjectId 12345')
53
93
  .option('--root <path>', 'Project root directory', process.cwd())
54
94
  .action(async (subcommand, opts) => {
55
95
  const projectRoot = path.resolve(opts.root);
96
+ track(projectRoot, { event_type: 'command.executed', command: 'config' });
56
97
  await runConfig(projectRoot, subcommand);
57
98
  });
58
99
  // ---------------------------------------------------------------------------
@@ -60,11 +101,14 @@ program
60
101
  // ---------------------------------------------------------------------------
61
102
  const globalCmd = program
62
103
  .command('global')
63
- .description('Manage global (~/.codebuddy/global/) and team-level (~/.codebuddy/team/) Skills');
104
+ .description('Manage shared Skills across projects via global/team scopes\n' +
105
+ ' Global scope ~/.codebuddy/global/ shared by all your projects\n' +
106
+ ' Team scope ~/.codebuddy/team/<name>/ shared by team members\n' +
107
+ ' Subcommands: init | list');
64
108
  globalCmd
65
109
  .command('init')
66
110
  .description('Initialize global or team-level Modus directory with starter Skills')
67
- .option('--team <name>', 'Target a team-level directory (~/.codebuddy/team/<name>/)')
111
+ .option('--team <name>', 'Target a team scope, e.g. --team backend-squad')
68
112
  .action(async (opts) => {
69
113
  await runGlobalInit({ team: opts.team });
70
114
  });
@@ -74,5 +118,155 @@ globalCmd
74
118
  .action(async () => {
75
119
  await runGlobalList();
76
120
  });
121
+ // ---------------------------------------------------------------------------
122
+ // modus status — show project state at a glance
123
+ // ---------------------------------------------------------------------------
124
+ program
125
+ .command('status')
126
+ .description('Show Modus project state at a glance\n' +
127
+ ' Reports: initialized Skills, active plans/changes, knowledge freshness, stale Skills')
128
+ .option('--root <path>', 'Project root directory', process.cwd())
129
+ .action(async (opts) => {
130
+ const projectRoot = path.resolve(opts.root);
131
+ track(projectRoot, { event_type: 'command.executed', command: 'status' });
132
+ await runStatus(projectRoot);
133
+ });
134
+ // ---------------------------------------------------------------------------
135
+ // modus doctor — diagnose environment and project setup
136
+ // ---------------------------------------------------------------------------
137
+ program
138
+ .command('doctor')
139
+ .description('Diagnose Modus installation, config, and Skills integrity\n' +
140
+ ' Checks: Node version, templates, config.yaml, hook scripts, Skill file health')
141
+ .option('--root <path>', 'Project root directory', process.cwd())
142
+ .action(async (opts) => {
143
+ const projectRoot = path.resolve(opts.root);
144
+ track(projectRoot, { event_type: 'command.executed', command: 'doctor' });
145
+ await runDoctor(projectRoot);
146
+ });
147
+ // ---------------------------------------------------------------------------
148
+ // modus skill — project-level Skill management
149
+ // ---------------------------------------------------------------------------
150
+ const skillCmd = program
151
+ .command('skill')
152
+ .description('Manage project-level Business Skills (modus-biz-*)\n' +
153
+ ' Subcommands: list | show <name> | refresh [name]');
154
+ skillCmd
155
+ .command('list')
156
+ .description('List all Modus Skills (framework + business) with maturity and last-referenced date')
157
+ .option('--root <path>', 'Project root directory', process.cwd())
158
+ .option('--filter <keyword>', 'Filter Skills by name keyword')
159
+ .option('--json', 'Output as JSON')
160
+ .action(async (opts) => {
161
+ const projectRoot = path.resolve(opts.root);
162
+ track(projectRoot, { event_type: 'command.executed', command: 'skill.list' });
163
+ await runSkillList(projectRoot, { filter: opts.filter, json: opts.json });
164
+ });
165
+ skillCmd
166
+ .command('show <name>')
167
+ .description('Print the full content of a Skill (accepts partial name, e.g. "order" → modus-biz-order)')
168
+ .option('--root <path>', 'Project root directory', process.cwd())
169
+ .action(async (name, opts) => {
170
+ const projectRoot = path.resolve(opts.root);
171
+ track(projectRoot, { event_type: 'command.executed', command: 'skill.show' });
172
+ await runSkillShow(projectRoot, name);
173
+ });
174
+ skillCmd
175
+ .command('refresh [name]')
176
+ .description('Clear last_hash to force re-scan on next AI command\n' +
177
+ ' Omit name to refresh all business Skills at once')
178
+ .option('--root <path>', 'Project root directory', process.cwd())
179
+ .action(async (name, opts) => {
180
+ const projectRoot = path.resolve(opts.root);
181
+ track(projectRoot, { event_type: 'command.executed', command: 'skill.refresh' });
182
+ await runSkillRefresh(projectRoot, name);
183
+ });
184
+ // ---------------------------------------------------------------------------
185
+ // modus rehook — update hook paths after git clone / path change
186
+ // ---------------------------------------------------------------------------
187
+ program
188
+ .command('rehook')
189
+ .description('Fix hook script paths in .codebuddy/settings.json\n' +
190
+ ' Run this after git clone to a different machine or directory path')
191
+ .option('--root <path>', 'Project root directory', process.cwd())
192
+ .action((opts) => {
193
+ const projectRoot = path.resolve(opts.root);
194
+ track(projectRoot, { event_type: 'command.executed', command: 'rehook' });
195
+ rehookProject(projectRoot);
196
+ });
197
+ // ---------------------------------------------------------------------------
198
+ // modus commands — list available CodeBuddy slash commands
199
+ // ---------------------------------------------------------------------------
200
+ program
201
+ .command('commands')
202
+ .description('List the /modus:* slash commands available inside CodeBuddy IDE\n' +
203
+ ' These are AI commands triggered in the chat window, not terminal commands')
204
+ .option('--root <path>', 'Project root directory', process.cwd())
205
+ .action((opts) => {
206
+ const projectRoot = path.resolve(opts.root);
207
+ track(projectRoot, { event_type: 'command.executed', command: 'commands' });
208
+ printSlashCommands(projectRoot);
209
+ });
210
+ // ---------------------------------------------------------------------------
211
+ // helpers
212
+ // ---------------------------------------------------------------------------
213
+ /** Print available /modus:* slash commands with descriptions. */
214
+ function printSlashCommands(projectRoot) {
215
+ let enabled = [];
216
+ try {
217
+ const config = loadConfig(projectRoot);
218
+ enabled = config.commands?.enabled ?? [];
219
+ }
220
+ catch {
221
+ // not initialized — show all
222
+ }
223
+ const all = [
224
+ {
225
+ cmd: '/modus:init',
226
+ description: 'Scan codebase, classify business domains, generate Business Skills + knowledge catalog',
227
+ note: 'Run once per project (or after major code changes)',
228
+ },
229
+ {
230
+ cmd: '/modus:vibe',
231
+ description: 'Context-aware coding — loads relevant business Skills before editing code',
232
+ note: 'Best for daily bug fixes and small feature tasks',
233
+ },
234
+ {
235
+ cmd: '/modus:plan',
236
+ description: 'Feature planning with complexity grading → proposal + design (ADR) + tasks',
237
+ note: 'Use when you need design docs but not formal specs',
238
+ },
239
+ {
240
+ cmd: '/modus:spec',
241
+ description: 'Spec-driven development — generates delta specs (ADDED/MODIFIED/REMOVED) with GIVEN/WHEN/THEN scenarios',
242
+ note: 'Use when changing interface contracts or needing testable acceptance criteria',
243
+ },
244
+ {
245
+ cmd: '/modus:auto',
246
+ description: 'Smart mode selector — reads TAPD Story, scores 4 dimensions, recommends vibe/plan/spec/harness',
247
+ note: 'Use when unsure which mode fits the TAPD story',
248
+ },
249
+ {
250
+ cmd: '/modus:harness',
251
+ description: 'Full dual-loop multi-agent pipeline: requirements → code → tests → security → review → deploy',
252
+ note: 'Use for full-cycle delivery from a TAPD Story URL',
253
+ },
254
+ ];
255
+ console.log(chalk.bold('\n /modus:* Slash Commands (run inside CodeBuddy IDE chat)\n'));
256
+ for (const item of all) {
257
+ const isEnabled = enabled.length === 0 || enabled.includes(item.cmd.replace('/modus:', ''));
258
+ const status = isEnabled ? chalk.green('✓') : chalk.dim('○');
259
+ console.log(` ${status} ${chalk.yellow(item.cmd.padEnd(18))} ${item.description}`);
260
+ if (item.note) {
261
+ console.log(` ${' '.repeat(18)} ${chalk.dim(item.note)}`);
262
+ }
263
+ }
264
+ if (enabled.length > 0) {
265
+ console.log(chalk.dim('\n ✓ = enabled in this project ○ = disabled (modus config profile to change)\n'));
266
+ }
267
+ else {
268
+ console.log(chalk.dim('\n Run `modus init` first to configure which commands are enabled.\n'));
269
+ }
270
+ }
77
271
  program.parse(process.argv);
78
272
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runDoctor(projectRoot: string): Promise<void>;
2
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AA6LA,wBAAsB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuDlE"}
@@ -0,0 +1,180 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs';
3
+ import { execSync } from 'node:child_process';
4
+ import chalk from 'chalk';
5
+ import { loadConfig, getConfigPath } from '../utils/config.js';
6
+ import { fileExists, listDirs, readFile } from '../utils/file-system.js';
7
+ function check(label, pass, detail, fix) {
8
+ return { label, pass, detail, fix };
9
+ }
10
+ function printCheck(result) {
11
+ const icon = result.pass ? chalk.green(' ✓') : chalk.red(' ✗');
12
+ const labelStr = result.pass ? chalk.white(result.label) : chalk.red(result.label);
13
+ console.log(`${icon} ${labelStr}${result.detail ? chalk.gray(` — ${result.detail}`) : ''}`);
14
+ if (!result.pass && result.fix) {
15
+ console.log(chalk.dim(` Fix: ${result.fix}`));
16
+ }
17
+ }
18
+ function printSection(title) {
19
+ console.log(chalk.bold(`\n ${title}`));
20
+ }
21
+ // ── Environment Checks ────────────────────────────────────────────────────────
22
+ function checkNodeVersion() {
23
+ const ver = process.version;
24
+ const major = parseInt(ver.replace('v', '').split('.')[0] ?? '0', 10);
25
+ return check(`Node.js ${ver}`, major >= 18, major >= 18 ? 'supported' : 'requires ≥18', 'Upgrade Node.js: https://nodejs.org');
26
+ }
27
+ function checkNpmAvailable() {
28
+ try {
29
+ const version = execSync('npm --version', { stdio: 'pipe' }).toString().trim();
30
+ return check(`npm ${version}`, true);
31
+ }
32
+ catch {
33
+ return check('npm', false, 'not found in PATH', 'Install Node.js (npm is bundled)');
34
+ }
35
+ }
36
+ // ── Project Checks ────────────────────────────────────────────────────────────
37
+ function checkInitialized(projectRoot) {
38
+ const configPath = getConfigPath(projectRoot);
39
+ return check('Modus initialized', fileExists(configPath), fileExists(configPath) ? configPath.replace(projectRoot, '.') : undefined, 'Run `modus init` to initialize the project');
40
+ }
41
+ function checkConfigValid(projectRoot) {
42
+ const configPath = getConfigPath(projectRoot);
43
+ if (!fileExists(configPath)) {
44
+ return check('Config valid', false, 'config.yaml missing', 'Run `modus init`');
45
+ }
46
+ try {
47
+ const cfg = loadConfig(projectRoot);
48
+ if (!cfg.version)
49
+ return check('Config valid', false, 'missing "version" field', 'Check modus/config.yaml');
50
+ if (!Array.isArray(cfg.commands?.enabled)) {
51
+ return check('Config valid', false, 'commands.enabled must be an array', 'Check modus/config.yaml');
52
+ }
53
+ return check('Config valid', true, `version=${cfg.version}, commands=${cfg.commands.enabled.length}`);
54
+ }
55
+ catch (err) {
56
+ return check('Config valid', false, String(err), 'Fix YAML syntax in modus/config.yaml');
57
+ }
58
+ }
59
+ function checkKnowledgeCatalog(projectRoot) {
60
+ const catalogPath = path.join(projectRoot, 'modus', 'knowledge-catalog.md');
61
+ if (!fileExists(catalogPath)) {
62
+ return check('Knowledge catalog', false, 'not generated', 'Run `modus init` or `/modus:init`');
63
+ }
64
+ const stat = fs.statSync(catalogPath);
65
+ const ageDays = Math.floor((Date.now() - stat.mtimeMs) / (1000 * 60 * 60 * 24));
66
+ const stale = ageDays > 30;
67
+ return check('Knowledge catalog', !stale, stale ? `stale (${ageDays}d old)` : `up to date (${ageDays}d old)`, stale ? 'Run `modus update` or `/modus:init` to refresh' : undefined);
68
+ }
69
+ function checkCodeBuddyDir(projectRoot) {
70
+ const codeBuddyDir = path.join(projectRoot, '.codebuddy');
71
+ const skillsDir = path.join(codeBuddyDir, 'skills');
72
+ const commandsDir = path.join(codeBuddyDir, 'commands', 'modus');
73
+ const hasSkills = fs.existsSync(skillsDir);
74
+ const hasCommands = fs.existsSync(commandsDir);
75
+ const ok = hasSkills && hasCommands;
76
+ return check('.codebuddy/ directory', ok, ok ? 'skills/ and commands/ present' : `missing: ${!hasSkills ? 'skills/' : ''}${!hasCommands ? ' commands/modus/' : ''}`.trim(), 'Run `modus init` or `modus update`');
77
+ }
78
+ function checkSkillsIntegrity(projectRoot) {
79
+ const skillsDir = path.join(projectRoot, '.codebuddy', 'skills');
80
+ if (!fs.existsSync(skillsDir)) {
81
+ return check('Skills integrity', false, 'skills directory missing', 'Run `modus init`');
82
+ }
83
+ const modusSkillDirs = listDirs(skillsDir).filter(d => d.startsWith('modus-'));
84
+ if (modusSkillDirs.length === 0) {
85
+ return check('Skills integrity', false, 'no modus Skills found', 'Run `modus init` to generate Skills');
86
+ }
87
+ const broken = [];
88
+ for (const skillDir of modusSkillDirs) {
89
+ const skillPath = path.join(skillsDir, skillDir, 'SKILL.md');
90
+ if (!fileExists(skillPath)) {
91
+ broken.push(skillDir);
92
+ continue;
93
+ }
94
+ // Check frontmatter exists
95
+ const content = readFile(skillPath);
96
+ if (!content.startsWith('---')) {
97
+ broken.push(skillDir);
98
+ }
99
+ }
100
+ return check('Skills integrity', broken.length === 0, broken.length === 0
101
+ ? `${modusSkillDirs.length} Skills OK`
102
+ : `${broken.length} broken: ${broken.slice(0, 3).join(', ')}${broken.length > 3 ? '...' : ''}`, broken.length > 0 ? 'Run `modus update` to regenerate broken Skills' : undefined);
103
+ }
104
+ function checkCommandFiles(projectRoot) {
105
+ const commandsDir = path.join(projectRoot, '.codebuddy', 'commands', 'modus');
106
+ if (!fs.existsSync(commandsDir)) {
107
+ return check('Command files', false, 'commands/modus/ missing', 'Run `modus init` or `modus update`');
108
+ }
109
+ const config = loadConfig(projectRoot);
110
+ const enabled = config.commands?.enabled ?? [];
111
+ const missing = enabled.filter(cmd => {
112
+ const cmdFile = path.join(commandsDir, `${cmd}.md`);
113
+ return !fileExists(cmdFile);
114
+ });
115
+ return check('Command files', missing.length === 0, missing.length === 0
116
+ ? `all ${enabled.length} command files present`
117
+ : `missing: ${missing.join(', ')}`, missing.length > 0 ? 'Run `modus update` to regenerate command files' : undefined);
118
+ }
119
+ // ── Analytics Config ──────────────────────────────────────────────────────────
120
+ function checkAnalyticsConfig(projectRoot) {
121
+ if (!fileExists(getConfigPath(projectRoot))) {
122
+ return check('Analytics config', false, 'config.yaml missing', 'Run `modus init`');
123
+ }
124
+ const config = loadConfig(projectRoot);
125
+ if (config.analytics?.enabled === false) {
126
+ return check('Analytics config', true, 'disabled (opt-out)');
127
+ }
128
+ if (config.analytics?.collectorUrl) {
129
+ return check('Analytics config', true, `collector: ${config.analytics.collectorUrl}`);
130
+ }
131
+ return check('Analytics config', true, 'default (no collector configured)');
132
+ }
133
+ // ── Entry Point ───────────────────────────────────────────────────────────────
134
+ export async function runDoctor(projectRoot) {
135
+ console.log(chalk.bold('\n modus doctor\n'));
136
+ console.log(chalk.gray(` Diagnosing project at: ${projectRoot}\n`));
137
+ const allResults = [];
138
+ printSection('Environment');
139
+ const nodeCheck = checkNodeVersion();
140
+ printCheck(nodeCheck);
141
+ allResults.push(nodeCheck);
142
+ const npmCheck = checkNpmAvailable();
143
+ printCheck(npmCheck);
144
+ allResults.push(npmCheck);
145
+ printSection('Project Setup');
146
+ const initCheck = checkInitialized(projectRoot);
147
+ printCheck(initCheck);
148
+ allResults.push(initCheck);
149
+ const configCheck = checkConfigValid(projectRoot);
150
+ printCheck(configCheck);
151
+ allResults.push(configCheck);
152
+ const codeBuddyCheck = checkCodeBuddyDir(projectRoot);
153
+ printCheck(codeBuddyCheck);
154
+ allResults.push(codeBuddyCheck);
155
+ const commandsCheck = checkCommandFiles(projectRoot);
156
+ printCheck(commandsCheck);
157
+ allResults.push(commandsCheck);
158
+ printSection('Knowledge Base');
159
+ const catalogCheck = checkKnowledgeCatalog(projectRoot);
160
+ printCheck(catalogCheck);
161
+ allResults.push(catalogCheck);
162
+ const skillsCheck = checkSkillsIntegrity(projectRoot);
163
+ printCheck(skillsCheck);
164
+ allResults.push(skillsCheck);
165
+ printSection('Analytics');
166
+ const analyticsCheck = checkAnalyticsConfig(projectRoot);
167
+ printCheck(analyticsCheck);
168
+ allResults.push(analyticsCheck);
169
+ // ── Summary ────────────────────────────────────────────────────────────────
170
+ const failed = allResults.filter(r => !r.pass);
171
+ console.log('');
172
+ if (failed.length === 0) {
173
+ console.log(chalk.green(` ✓ All checks passed. Modus is healthy.\n`));
174
+ }
175
+ else {
176
+ console.log(chalk.red(` ✗ ${failed.length} check${failed.length > 1 ? 's' : ''} failed.\n`));
177
+ process.exitCode = 1;
178
+ }
179
+ }
180
+ //# sourceMappingURL=doctor.js.map