@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.
- package/README.md +76 -28
- package/dist/cli/index.js +206 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +180 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +18 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +314 -201
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/skill.d.ts +7 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +175 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +133 -0
- package/dist/commands/status.js.map +1 -0
- 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/codebuddy.d.ts +7 -0
- package/dist/generators/codebuddy.d.ts.map +1 -1
- package/dist/generators/codebuddy.js +35 -3
- package/dist/generators/codebuddy.js.map +1 -1
- 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/analytics.d.ts +14 -0
- package/dist/utils/analytics.d.ts.map +1 -0
- package/dist/utils/analytics.js +81 -0
- package/dist/utils/analytics.js.map +1 -0
- package/dist/utils/config.d.ts +25 -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/commands/auto.md +38 -0
- package/templates/commands/modus.md +14 -2
- package/templates/hooks/session-start.py +103 -1
- package/templates/hooks/stop-update-skills.py +58 -0
- package/templates/skills/modus-auto/SKILL.md +210 -0
- package/templates/skills/modus-init/SKILL.md +208 -11
- package/templates/skills/modus-plan/SKILL.md +154 -19
- package/templates/skills/modus-spec/SKILL.md +131 -6
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { writeFile, readTemplate, fileExists, readFile } from '../utils/file-system.js';
|
|
3
|
+
const RULES_BASE = path.join('.cursor', 'rules');
|
|
4
|
+
const MCP_PATH = path.join('.cursor', 'mcp.json');
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Framework Skills → individual .mdc rules
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
const SKILL_RULES = [
|
|
9
|
+
{
|
|
10
|
+
id: 'modus-init',
|
|
11
|
+
templatePath: 'skills/modus-init/SKILL.md',
|
|
12
|
+
description: 'Run /modus:init to scan the codebase and build Business Skills for each domain',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'modus-vibe',
|
|
16
|
+
templatePath: 'skills/modus-vibe/SKILL.md',
|
|
17
|
+
description: 'Run /modus:vibe to start context-aware vibe coding with business Skill preloading',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'modus-plan',
|
|
21
|
+
templatePath: 'skills/modus-plan/SKILL.md',
|
|
22
|
+
description: 'Run /modus:plan to create structured feature proposals with complexity grading',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'modus-spec',
|
|
26
|
+
templatePath: 'skills/modus-spec/SKILL.md',
|
|
27
|
+
description: 'Run /modus:spec for OpenSpec-driven development with delta specs and GIVEN/WHEN/THEN scenarios',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'modus-auto',
|
|
31
|
+
templatePath: 'skills/modus-auto/SKILL.md',
|
|
32
|
+
description: 'Run /modus:auto with a TAPD story URL to get AI-recommended mode (vibe/plan/spec/harness)',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'modus-harness',
|
|
36
|
+
templatePath: 'skills/modus-harness/SKILL.md',
|
|
37
|
+
description: 'Run /modus:harness to execute the full dual-loop multi-agent development pipeline',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
// Harness sub-agent templates to merge into the single harness rule
|
|
41
|
+
const HARNESS_SUB_AGENT_TEMPLATES = [
|
|
42
|
+
{ id: '00-skills-builder', templatePath: 'skills/modus-harness-agents/00-skills-builder/SKILL.md' },
|
|
43
|
+
{ id: '01-analysis', templatePath: 'skills/modus-harness-agents/01-analysis/SKILL.md' },
|
|
44
|
+
{ id: '02-dev', templatePath: 'skills/modus-harness-agents/02-dev/SKILL.md' },
|
|
45
|
+
{ id: '03-test', templatePath: 'skills/modus-harness-agents/03-test/SKILL.md' },
|
|
46
|
+
{ id: '04-perf', templatePath: 'skills/modus-harness-agents/04-perf/SKILL.md' },
|
|
47
|
+
{ id: '05-security', templatePath: 'skills/modus-harness-agents/05-security/SKILL.md' },
|
|
48
|
+
{ id: '06-review', templatePath: 'skills/modus-harness-agents/06-review/SKILL.md' },
|
|
49
|
+
{ id: '07-deploy', templatePath: 'skills/modus-harness-agents/07-deploy/SKILL.md' },
|
|
50
|
+
];
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Main entry
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
export function generateCursorFiles(projectRoot, config, _opts = {}) {
|
|
55
|
+
generateCursorSkillRules(projectRoot, config);
|
|
56
|
+
generateCursorHarnessRule(projectRoot);
|
|
57
|
+
generateCursorConstitution(projectRoot, config);
|
|
58
|
+
generateCursorAutoVibe(projectRoot);
|
|
59
|
+
generateCursorMcp(projectRoot, config);
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Individual skill rules
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
function generateCursorSkillRules(projectRoot, config) {
|
|
65
|
+
const enabled = new Set(config.commands.enabled);
|
|
66
|
+
for (const skill of SKILL_RULES) {
|
|
67
|
+
// Only generate command-backed skills if the command is enabled
|
|
68
|
+
const cmdId = skill.id.replace('modus-', '');
|
|
69
|
+
if (['init', 'vibe', 'plan', 'spec', 'auto', 'harness'].includes(cmdId) && !enabled.has(cmdId)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
let body;
|
|
73
|
+
try {
|
|
74
|
+
body = readTemplate(skill.templatePath);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const content = buildMdcFile(skill.description, false, body);
|
|
80
|
+
writeFile(path.join(projectRoot, RULES_BASE, `${skill.id}.mdc`), content);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// Harness rule — single-agent degradation
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
function generateCursorHarnessRule(projectRoot) {
|
|
87
|
+
const sections = [
|
|
88
|
+
'# Modus Harness — Single-Agent Mode',
|
|
89
|
+
'',
|
|
90
|
+
'> **Note:** Cursor does not support native Sub-Agents. The Harness pipeline runs in',
|
|
91
|
+
'> single-agent mode: the orchestrator executes each step sequentially within one context.',
|
|
92
|
+
'> For full parallel Sub-Agent support, use CodeBuddy or Claude Code.',
|
|
93
|
+
'',
|
|
94
|
+
'## Pipeline Steps (sequential)',
|
|
95
|
+
'',
|
|
96
|
+
];
|
|
97
|
+
for (const agent of HARNESS_SUB_AGENT_TEMPLATES) {
|
|
98
|
+
let body;
|
|
99
|
+
try {
|
|
100
|
+
body = readTemplate(agent.templatePath);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
sections.push(`### Step ${agent.id}`, '', body, '', '---', '');
|
|
106
|
+
}
|
|
107
|
+
const content = buildMdcFile('Modus Harness orchestration steps (single-agent mode for Cursor)', false, sections.join('\n'));
|
|
108
|
+
writeFile(path.join(projectRoot, RULES_BASE, 'modus-harness-agents.mdc'), content);
|
|
109
|
+
}
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
// Constitution rule
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
function generateCursorConstitution(projectRoot, config) {
|
|
114
|
+
const any = config;
|
|
115
|
+
const constitution = any['constitution'] ?? {};
|
|
116
|
+
const techStack = String(constitution['tech_stack'] ?? config.techStack ?? '');
|
|
117
|
+
const buildCmd = String(constitution['build_command'] ?? '');
|
|
118
|
+
const testCmd = String(constitution['test_command'] ?? '');
|
|
119
|
+
const context = config.context ?? '';
|
|
120
|
+
const hardRules = Array.isArray(constitution['hard_rules'])
|
|
121
|
+
? constitution['hard_rules'].map((r) => `- ${r}`).join('\n')
|
|
122
|
+
: '';
|
|
123
|
+
const keyPatterns = Array.isArray(constitution['key_patterns'])
|
|
124
|
+
? constitution['key_patterns'].map((p) => `- ${p}`).join('\n')
|
|
125
|
+
: '';
|
|
126
|
+
const lines = ['# Modus Project Constitution', ''];
|
|
127
|
+
if (context) {
|
|
128
|
+
lines.push(`> ${context}`, '');
|
|
129
|
+
}
|
|
130
|
+
if (techStack) {
|
|
131
|
+
lines.push(`**Tech Stack:** ${techStack}`, '');
|
|
132
|
+
}
|
|
133
|
+
if (buildCmd) {
|
|
134
|
+
lines.push(`**Build Command:** \`${buildCmd}\``, '');
|
|
135
|
+
}
|
|
136
|
+
if (testCmd) {
|
|
137
|
+
lines.push(`**Test Command:** \`${testCmd}\``, '');
|
|
138
|
+
}
|
|
139
|
+
if (hardRules) {
|
|
140
|
+
lines.push('**Hard Rules (must never violate):**', hardRules, '');
|
|
141
|
+
}
|
|
142
|
+
if (keyPatterns) {
|
|
143
|
+
lines.push('**Key Patterns:**', keyPatterns, '');
|
|
144
|
+
}
|
|
145
|
+
lines.push('**Modus Commands:** `/modus:init` · `/modus:vibe` · `/modus:plan` · `/modus:spec` · `/modus:auto` · `/modus:harness`');
|
|
146
|
+
const content = buildMdcFile('Modus project constitution — tech stack, hard rules, and key patterns', true, lines.join('\n'));
|
|
147
|
+
writeFile(path.join(projectRoot, RULES_BASE, 'modus-constitution.mdc'), content);
|
|
148
|
+
}
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Auto-vibe — always-on rule that activates vibe behavior automatically
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
function generateCursorAutoVibe(projectRoot) {
|
|
153
|
+
const body = [
|
|
154
|
+
'# Modus Auto-Vibe Mode',
|
|
155
|
+
'',
|
|
156
|
+
'This project has Modus initialized. **For every conversation, automatically apply',
|
|
157
|
+
'vibe-mode behavior** — do not wait for the user to type `/modus:vibe`.',
|
|
158
|
+
'',
|
|
159
|
+
'## Auto-Vibe Instructions',
|
|
160
|
+
'',
|
|
161
|
+
'1. At the start of each conversation, read `modus/knowledge-catalog.md` to understand',
|
|
162
|
+
' available Business Skills and their domains.',
|
|
163
|
+
'2. Based on the user\'s request, identify the relevant business domain(s).',
|
|
164
|
+
'3. Load the corresponding `.cursor/rules/modus-biz-{domain}.mdc` rule(s) to get',
|
|
165
|
+
' business context (entities, rules, pitfalls, key files).',
|
|
166
|
+
'4. Respond as a developer who deeply understands this project — apply the',
|
|
167
|
+
' business rules, naming conventions, and known pitfalls from the loaded Skills.',
|
|
168
|
+
'5. If the user explicitly triggers `/modus:plan`, `/modus:spec`, or `/modus:harness`,',
|
|
169
|
+
' switch to that mode\'s workflow.',
|
|
170
|
+
'',
|
|
171
|
+
'## Token Efficiency',
|
|
172
|
+
'',
|
|
173
|
+
'- Load Skills **on demand** (only for domains relevant to the current request).',
|
|
174
|
+
'- Skip loading if the request is clearly out of project scope (e.g. general questions).',
|
|
175
|
+
'- Re-use already-loaded Skill context within the same conversation.',
|
|
176
|
+
].join('\n');
|
|
177
|
+
const content = buildMdcFile('Auto-apply Modus vibe mode for every conversation — load Business Skills based on user request', true, body);
|
|
178
|
+
writeFile(path.join(projectRoot, RULES_BASE, 'modus-auto-vibe.mdc'), content);
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// MCP config — .cursor/mcp.json
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
function generateCursorMcp(projectRoot, config) {
|
|
184
|
+
if (!config.mcpServers || Object.keys(config.mcpServers).length === 0)
|
|
185
|
+
return;
|
|
186
|
+
const mcpPath = path.join(projectRoot, MCP_PATH);
|
|
187
|
+
let existing = {};
|
|
188
|
+
if (fileExists(mcpPath)) {
|
|
189
|
+
try {
|
|
190
|
+
existing = JSON.parse(readFile(mcpPath));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
existing = {};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const existingServers = existing['mcpServers'] ?? {};
|
|
197
|
+
existing['mcpServers'] = { ...config.mcpServers, ...existingServers };
|
|
198
|
+
writeFile(mcpPath, JSON.stringify(existing, null, 2) + '\n');
|
|
199
|
+
}
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Helpers
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
/**
|
|
204
|
+
* Wrap markdown body in a Cursor .mdc frontmatter header.
|
|
205
|
+
*/
|
|
206
|
+
function buildMdcFile(description, alwaysApply, body) {
|
|
207
|
+
return `---\ndescription: "${description.replace(/"/g, '\\"')}"\nalwaysApply: ${alwaysApply}\n---\n\n${body}\n`;
|
|
208
|
+
}
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// Business Skill sync
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
/**
|
|
213
|
+
* Sync a single business Skill to Cursor format.
|
|
214
|
+
* Creates a rule at .cursor/rules/modus-biz-{domain}.mdc
|
|
215
|
+
*/
|
|
216
|
+
export function syncBizSkillToCursor(projectRoot, domain, skillContent) {
|
|
217
|
+
const content = buildMdcFile(`Business rules and conventions for the ${domain} domain`, false, skillContent);
|
|
218
|
+
writeFile(path.join(projectRoot, RULES_BASE, `modus-biz-${domain}.mdc`), content);
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=cursor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/generators/cursor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type GenerateOptions } from './codebuddy.js';
|
|
2
|
+
import type { ModusConfig } from '../utils/config.js';
|
|
3
|
+
export type { GenerateOptions };
|
|
4
|
+
/**
|
|
5
|
+
* Generate configuration files for every platform listed in `config.platforms`.
|
|
6
|
+
* Defaults to ['codebuddy'] when the field is absent to preserve backward compat.
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateAllPlatformFiles(projectRoot: string, config: ModusConfig, opts?: GenerateOptions): void;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAI9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,WAAW,EACnB,IAAI,GAAE,eAAoB,GACzB,IAAI,CAeN"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Platform dispatcher — generates configuration files for all selected AI platforms.
|
|
2
|
+
// Called by `modus init` and `modus update`; replaces direct calls to generateCodeBuddyFiles.
|
|
3
|
+
import { generateCodeBuddyFiles } from './codebuddy.js';
|
|
4
|
+
import { generateClaudeFiles } from './claude.js';
|
|
5
|
+
import { generateCursorFiles } from './cursor.js';
|
|
6
|
+
import { generateCopilotFiles } from './copilot.js';
|
|
7
|
+
/**
|
|
8
|
+
* Generate configuration files for every platform listed in `config.platforms`.
|
|
9
|
+
* Defaults to ['codebuddy'] when the field is absent to preserve backward compat.
|
|
10
|
+
*/
|
|
11
|
+
export function generateAllPlatformFiles(projectRoot, config, opts = {}) {
|
|
12
|
+
const platforms = config.platforms ?? ['codebuddy'];
|
|
13
|
+
if (platforms.includes('codebuddy')) {
|
|
14
|
+
generateCodeBuddyFiles(projectRoot, config, opts);
|
|
15
|
+
}
|
|
16
|
+
if (platforms.includes('claude')) {
|
|
17
|
+
generateClaudeFiles(projectRoot, config, opts);
|
|
18
|
+
}
|
|
19
|
+
if (platforms.includes('cursor')) {
|
|
20
|
+
generateCursorFiles(projectRoot, config, opts);
|
|
21
|
+
}
|
|
22
|
+
if (platforms.includes('copilot')) {
|
|
23
|
+
generateCopilotFiles(projectRoot, config, opts);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,8FAA8F;AAC9F,OAAO,EAAE,sBAAsB,EAAwB,MAAM,gBAAgB,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAKpD;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,MAAmB,EACnB,OAAwB,EAAE;IAE1B,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,CAAC,WAAW,CAAC,CAAC;IAEpD,IAAI,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpC,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface TrackEvent {
|
|
2
|
+
event_type: string;
|
|
3
|
+
command?: string;
|
|
4
|
+
sub_agent?: string;
|
|
5
|
+
result?: string;
|
|
6
|
+
payload?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Send a usage event to the Modus Collector API.
|
|
10
|
+
* Fire-and-forget: errors are silently swallowed so they never block the CLI.
|
|
11
|
+
* Respects MODUS_ANALYTICS_DISABLED=1 env var.
|
|
12
|
+
*/
|
|
13
|
+
export declare function track(projectRoot: string, event: TrackEvent): void;
|
|
14
|
+
//# sourceMappingURL=analytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/utils/analytics.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AA2BD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CA+ClE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
/**
|
|
6
|
+
* Derive an anonymized user ID from git email or hostname (MD5, not reversible).
|
|
7
|
+
* Never sends the raw email.
|
|
8
|
+
*/
|
|
9
|
+
function resolveUserId() {
|
|
10
|
+
try {
|
|
11
|
+
const email = execSync('git config --global user.email', {
|
|
12
|
+
timeout: 2000,
|
|
13
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
14
|
+
})
|
|
15
|
+
.toString()
|
|
16
|
+
.trim();
|
|
17
|
+
if (email)
|
|
18
|
+
return createHash('md5').update(email).digest('hex').slice(0, 16);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// git not available or no config
|
|
22
|
+
}
|
|
23
|
+
return createHash('md5').update(os.hostname()).digest('hex').slice(0, 16);
|
|
24
|
+
}
|
|
25
|
+
let _userId = null;
|
|
26
|
+
function getUserId() {
|
|
27
|
+
if (!_userId)
|
|
28
|
+
_userId = resolveUserId();
|
|
29
|
+
return _userId;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Send a usage event to the Modus Collector API.
|
|
33
|
+
* Fire-and-forget: errors are silently swallowed so they never block the CLI.
|
|
34
|
+
* Respects MODUS_ANALYTICS_DISABLED=1 env var.
|
|
35
|
+
*/
|
|
36
|
+
export function track(projectRoot, event) {
|
|
37
|
+
// Env-level opt-out
|
|
38
|
+
if (process.env['MODUS_ANALYTICS_DISABLED'] === '1')
|
|
39
|
+
return;
|
|
40
|
+
// Read config lazily; if it fails, just skip
|
|
41
|
+
let collectorUrl;
|
|
42
|
+
let token;
|
|
43
|
+
let projectId;
|
|
44
|
+
let teamName;
|
|
45
|
+
try {
|
|
46
|
+
const config = loadConfig(projectRoot);
|
|
47
|
+
const analytics = config.analytics;
|
|
48
|
+
if (analytics?.enabled === false)
|
|
49
|
+
return;
|
|
50
|
+
collectorUrl = analytics?.collectorUrl?.trim();
|
|
51
|
+
token = analytics?.token?.trim();
|
|
52
|
+
projectId = config.tapdProjectId ?? undefined;
|
|
53
|
+
teamName = config.teamName ?? undefined;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!collectorUrl)
|
|
59
|
+
return;
|
|
60
|
+
const body = JSON.stringify({
|
|
61
|
+
event_type: event.event_type,
|
|
62
|
+
command: event.command,
|
|
63
|
+
sub_agent: event.sub_agent,
|
|
64
|
+
user_id: getUserId(),
|
|
65
|
+
project_id: projectId,
|
|
66
|
+
team_name: teamName,
|
|
67
|
+
result: event.result,
|
|
68
|
+
payload: event.payload,
|
|
69
|
+
});
|
|
70
|
+
// Defer so the main CLI flow is never blocked
|
|
71
|
+
setImmediate(() => {
|
|
72
|
+
const url = `${collectorUrl}/track`;
|
|
73
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
74
|
+
if (token)
|
|
75
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
76
|
+
fetch(url, { method: 'POST', headers, body, signal: AbortSignal.timeout(3000) }).catch(() => {
|
|
77
|
+
// Intentionally silent
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=analytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/utils/analytics.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/** Supported AI platform targets for file generation. */
|
|
2
|
+
export type PlatformId = 'codebuddy' | 'claude' | 'cursor' | 'copilot';
|
|
3
|
+
export interface ModusAnalyticsConfig {
|
|
4
|
+
/** Whether to send usage events. Defaults to true. */
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
/** URL of the Modus Collector API, e.g. http://43.139.34.70:3456 */
|
|
7
|
+
collectorUrl?: string;
|
|
8
|
+
/** Bearer token for the collector API (optional). */
|
|
9
|
+
token?: string;
|
|
10
|
+
}
|
|
1
11
|
export interface ModusConfig {
|
|
2
12
|
version: string;
|
|
3
13
|
commands: {
|
|
@@ -13,6 +23,21 @@ export interface ModusConfig {
|
|
|
13
23
|
teamName?: string;
|
|
14
24
|
/** MCP server configs collected during `modus init`. Written to .codebuddy/settings.json. */
|
|
15
25
|
mcpServers?: Record<string, unknown>;
|
|
26
|
+
/** Usage analytics — sends command/subagent events to the Collector API. */
|
|
27
|
+
analytics?: ModusAnalyticsConfig;
|
|
28
|
+
/**
|
|
29
|
+
* AI platforms to generate configuration files for.
|
|
30
|
+
* Set during `modus init`; refreshed by `modus update`.
|
|
31
|
+
* Defaults to ['codebuddy'] when omitted.
|
|
32
|
+
*/
|
|
33
|
+
platforms?: PlatformId[];
|
|
34
|
+
/**
|
|
35
|
+
* The modus CLI version that last wrote the platform files.
|
|
36
|
+
* Written by `modus init` and `modus update`.
|
|
37
|
+
* The session-start hook compares this against the currently installed version
|
|
38
|
+
* and auto-runs `modus update` when they differ (silent auto-update).
|
|
39
|
+
*/
|
|
40
|
+
modusBuildVersion?: string;
|
|
16
41
|
}
|
|
17
42
|
export declare function getConfigPath(projectRoot: string): string;
|
|
18
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAKA,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,4EAA4E;IAC5E,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,UAAU,EAAE,CAAC;IACzB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AASD,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAK3D;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAIzE"}
|
package/dist/utils/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA8CnE,MAAM,cAAc,GAAgB;IAClC,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE;QACR,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;KACrD;CACF,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,WAAmB;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB;IAC5C,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC1D,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAgB,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,WAAmB,EAAE,MAAmB;IACjE,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACtD,SAAS,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# /modus:auto
|
|
2
|
+
|
|
3
|
+
Smart mode recommendation. Reads a TAPD Story, scores it across 4 dimensions, recommends the best Modus mode, then launches it after human confirmation.
|
|
4
|
+
|
|
5
|
+
## Instructions
|
|
6
|
+
|
|
7
|
+
Read and follow the skill at `.codebuddy/skills/modus-auto/SKILL.md` to execute this command.
|
|
8
|
+
|
|
9
|
+
## Quick Summary
|
|
10
|
+
|
|
11
|
+
1. Accept a TAPD Story URL (or prompt for manual input if omitted)
|
|
12
|
+
2. Read Story content via TAPD MCP
|
|
13
|
+
3. Score the story across 4 dimensions: Complexity / Risk / Clarity / Contract Impact
|
|
14
|
+
4. Apply the decision tree → recommend one of: vibe / plan / spec / harness
|
|
15
|
+
5. Show recommendation with reasoning + comparison table of other options
|
|
16
|
+
6. Wait for human mode selection
|
|
17
|
+
7. Show parameter confirmation window (second confirmation step)
|
|
18
|
+
8. Auto-launch the selected mode with TAPD context pre-filled
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
/modus:auto https://tapd.cn/company/stories/view/1234567890
|
|
24
|
+
/modus:auto (without URL — will prompt for manual Story content)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Decision Tree (summary)
|
|
28
|
+
|
|
29
|
+
| Score | Recommended Mode |
|
|
30
|
+
|-------|-----------------|
|
|
31
|
+
| Low complexity + Low risk + No contract change | vibe |
|
|
32
|
+
| Medium complexity + High clarity + No contract change | plan |
|
|
33
|
+
| Any contract change OR High risk OR needs testable acceptance criteria | spec |
|
|
34
|
+
| Low clarity OR High complexity + High risk OR full automation needed | harness |
|
|
35
|
+
|
|
36
|
+
## When to Use
|
|
37
|
+
|
|
38
|
+
Use `/modus:auto` when you have a TAPD Story but are unsure which Modus mode fits best. The AI analyzes the story and presents a reasoned recommendation — you still make the final call.
|
|
@@ -10,13 +10,25 @@ Modus — Business-grounded AI coding accelerator.
|
|
|
10
10
|
| `/modus:vibe` | Context-aware vibe coding with business Skill backing |
|
|
11
11
|
| `/modus:plan` | Plan mode with Skill-backed business context |
|
|
12
12
|
| `/modus:spec` | OpenSpec-style spec-driven development |
|
|
13
|
+
| `/modus:auto` | Smart mode recommendation — reads TAPD Story, scores 4 dimensions, recommends vibe/plan/spec/harness |
|
|
13
14
|
| `/modus:harness` | Full dual-loop multi-agent Harness (analyze → dev → test → review → deploy) |
|
|
14
15
|
|
|
15
16
|
## Quick Start
|
|
16
17
|
|
|
17
18
|
1. Run `/modus:init` once to scan your project and build business Skills
|
|
18
|
-
2. Use `/modus:
|
|
19
|
-
3. Use `/modus:
|
|
19
|
+
2. Use `/modus:auto [tapd-url]` when unsure which mode fits — AI recommends based on story analysis
|
|
20
|
+
3. Use `/modus:vibe` for day-to-day coding with project context
|
|
21
|
+
4. Use `/modus:harness` for full-cycle feature delivery from a TAPD Story URL
|
|
22
|
+
|
|
23
|
+
## Mode Selection Guide
|
|
24
|
+
|
|
25
|
+
| Situation | Recommended Command |
|
|
26
|
+
|-----------|-------------------|
|
|
27
|
+
| Not sure which mode to use | `/modus:auto [tapd-url]` |
|
|
28
|
+
| Quick bug fix / small change | `/modus:vibe` |
|
|
29
|
+
| Feature with design docs, no spec needed | `/modus:plan` |
|
|
30
|
+
| Interface contract changes / testable acceptance criteria | `/modus:spec` |
|
|
31
|
+
| Full automation from TAPD story to deployment | `/modus:harness` |
|
|
20
32
|
|
|
21
33
|
## Tips
|
|
22
34
|
|