mad-pro-cli 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+
5
+ export default async function listCommand() {
6
+ const rootDir = process.cwd();
7
+ const targetRefDir = path.join(rootDir, 'references');
8
+
9
+ console.log(chalk.bold.magenta('\nšŸ“‹ MAD Pro Installed Skills'));
10
+
11
+ if (!fs.existsSync(targetRefDir)) {
12
+ console.log(chalk.yellow('\nNo skills initialized in this project. Run `mad-pro init` first.'));
13
+ return;
14
+ }
15
+
16
+ const getFiles = (dir) => {
17
+ let results = [];
18
+ const list = fs.readdirSync(dir);
19
+ list.forEach(file => {
20
+ const fullPath = path.join(dir, file);
21
+ const stat = fs.statSync(fullPath);
22
+ if (stat && stat.isDirectory()) {
23
+ results = results.concat(getFiles(fullPath));
24
+ } else if (file.endsWith('.md')) {
25
+ results.push(path.relative(targetRefDir, fullPath));
26
+ }
27
+ });
28
+ return results;
29
+ };
30
+
31
+ const installed = getFiles(targetRefDir);
32
+
33
+ if (installed.length === 0) {
34
+ console.log(chalk.gray('Zero skills found in /references directory.'));
35
+ } else {
36
+ installed.sort().forEach(file => {
37
+ console.log(`${chalk.green('āœ“')} ${file.replace('.md', '').toUpperCase().replace(/_/g, ' ')}`);
38
+ });
39
+ console.log(chalk.cyan(`\nTotal: ${installed.length} skills active.`));
40
+ }
41
+ console.log("");
42
+ }
@@ -0,0 +1,128 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import inquirer from 'inquirer';
5
+ import { loadConfig } from '../utils/config.js';
6
+
7
+ export default async function promptCommand(cmdObj) {
8
+ const rootDir = process.cwd();
9
+ const targetRefDir = path.join(rootDir, 'references');
10
+ const config = loadConfig(rootDir) || { architecture: 'mvvm', di: 'hilt' };
11
+
12
+ console.log(chalk.bold.magenta('\nšŸ¤– MAD Pro - Contextual Agent Instruction Generator'));
13
+
14
+ if (!fs.existsSync(targetRefDir)) {
15
+ console.log(chalk.yellow('\nNo skills found. Run `mad-pro init` first to generate a tailored prompt.'));
16
+ return;
17
+ }
18
+
19
+ // Identify installed skills
20
+ const getFiles = (dir) => {
21
+ let results = [];
22
+ if (!fs.existsSync(dir)) return results;
23
+ const list = fs.readdirSync(dir);
24
+ list.forEach(file => {
25
+ const fullPath = path.join(dir, file);
26
+ if (fs.statSync(fullPath).isDirectory()) {
27
+ if (file !== 'design-tokens') {
28
+ results = results.concat(getFiles(fullPath));
29
+ }
30
+ } else if (file.endsWith('.md')) {
31
+ if (!fullPath.includes('design-tokens')) {
32
+ results.push(path.basename(file, '.md').replace(/_/g, ' ').toUpperCase());
33
+ }
34
+ }
35
+ });
36
+ return results;
37
+ };
38
+
39
+ const skills = getFiles(targetRefDir);
40
+ const industryDir = path.join(targetRefDir, 'industry');
41
+ const industrySkills = getFiles(industryDir);
42
+
43
+ const archRules = {
44
+ 'mvvm': 'Follow MVVM architecture: UI -> ViewModel -> (UseCase) -> Repository -> Data Source.',
45
+ 'mvi': 'Follow MVI architecture: UI -> Intent -> ViewModel -> StateFlow -> UI.',
46
+ 'mvp': 'Follow MVP architecture: View <-> Presenter -> Repository.',
47
+ 'clean+mvi': 'Follow Clean + MVI: UI -> Intent -> ViewModel -> UseCase -> Repository.',
48
+ 'viper': 'Follow VIPER architecture: View, Interactor, Presenter, Entity, Router.',
49
+ 'custom': 'Follow the custom architecture patterns established in the project.'
50
+ };
51
+
52
+ const diRules = {
53
+ 'hilt': 'Use Hilt for Dependency Injection (@HiltViewModel, @Inject).',
54
+ 'koin': 'Use Koin for Dependency Injection (constructor injection, get()).',
55
+ 'none': 'Use manual Dependency Injection.'
56
+ };
57
+
58
+ const hasTokens = fs.existsSync(path.join(targetRefDir, 'design-tokens'));
59
+
60
+ const formatRes = await inquirer.prompt([{
61
+ type: 'list',
62
+ name: 'format',
63
+ message: 'Select target format:',
64
+ choices: [
65
+ { name: '.cursorrules (Cursor)', value: 'cursor' },
66
+ { name: '.windsurfrules (Windsurf)', value: 'windsurf' },
67
+ { name: 'System Prompt (Clipboard / Generic)', value: 'generic' }
68
+ ]
69
+ }]);
70
+
71
+ const promptBuilder = [];
72
+
73
+ if (formatRes.format !== 'generic') {
74
+ promptBuilder.push(`You are an expert Android Developer using the MAD Pro v1.3.0 framework.`);
75
+ promptBuilder.push(`Your goal is to build highly scalable, testable, and maintainable Android apps.\n`);
76
+ } else {
77
+ promptBuilder.push(`# AI AGENT INSTRUCTIONS (MAD PRO)`);
78
+ promptBuilder.push(`System Role: Expert Android Developer\n`);
79
+ }
80
+
81
+ promptBuilder.push(`## PROJECT CONTEXT`);
82
+ promptBuilder.push(`This project uses the following architecture: **${config.architecture.toUpperCase()}** with **${config.di.toUpperCase()}**.`);
83
+ if (skills.length > 0) {
84
+ promptBuilder.push(`Installed architectural patterns in /references:`);
85
+ skills.slice(0, 15).forEach(s => promptBuilder.push(`- ${s}`));
86
+ if (skills.length > 15) promptBuilder.push(`- ...and ${skills.length - 15} more.`);
87
+ }
88
+ promptBuilder.push('');
89
+
90
+ promptBuilder.push(`## CORE RULES`);
91
+ promptBuilder.push(`1. ALWAYS check the matching file in /references before implementing a new feature.`);
92
+ promptBuilder.push(`2. ${archRules[config.architecture] || archRules['mvvm']}`);
93
+ promptBuilder.push(`3. ${diRules[config.di] || diRules['hilt']}`);
94
+ promptBuilder.push(`4. Use Jetpack Compose with Unidirectional Data Flow (UDF).`);
95
+
96
+ if (industrySkills.length > 0) {
97
+ promptBuilder.push(`5. Adhere strictly to the industry best practices found in /references/industry/ for: ${industrySkills.join(', ')}.`);
98
+ }
99
+
100
+ promptBuilder.push(`\n## OUTPUT STYLE`);
101
+ promptBuilder.push(`- Provide production-ready Kotlin code.`);
102
+ if (hasTokens) {
103
+ promptBuilder.push(`- STYLING: You MUST use the design tokens defined in /references/design-tokens/ (colors, typography, spacing). Do not hardcode dimensions or generic colors.`);
104
+ }
105
+ promptBuilder.push(`- Ensure all UI components follow the defined Material 3 theme. Avoid outdated XML layouts unless required.`);
106
+
107
+ const finalPrompt = promptBuilder.join('\n');
108
+
109
+ console.log(chalk.white(`\n--- COPY THIS TO YOUR ${formatRes.format === 'generic' ? 'SYSTEM PROMPT' : formatRes.format === 'cursor' ? '.cursorrules' : '.windsurfrules'} ---\n`));
110
+ console.log(chalk.cyan(finalPrompt));
111
+ console.log(chalk.white('------------------------------------------------------------------\n'));
112
+
113
+ // Optionally auto-write to file if it's cursor or windsurf
114
+ if (formatRes.format === 'cursor' || formatRes.format === 'windsurf') {
115
+ const fileName = formatRes.format === 'cursor' ? '.cursorrules' : '.windsurfrules';
116
+ const fileRes = await inquirer.prompt([{
117
+ type: 'confirm',
118
+ name: 'write',
119
+ message: `Do you want to write this to ${fileName} in the current directory?`,
120
+ default: true
121
+ }]);
122
+
123
+ if (fileRes.write) {
124
+ fs.writeFileSync(path.join(rootDir, fileName), finalPrompt);
125
+ console.log(chalk.green(`āœ“ Saved to ${fileName}`));
126
+ }
127
+ }
128
+ }
@@ -0,0 +1,32 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+
4
+ const CONFIG_FILE = '.mad-pro.json';
5
+
6
+ export function getConfigPath(rootDir = process.cwd()) {
7
+ return path.join(rootDir, CONFIG_FILE);
8
+ }
9
+
10
+ export function loadConfig(rootDir = process.cwd()) {
11
+ const configPath = getConfigPath(rootDir);
12
+ if (fs.existsSync(configPath)) {
13
+ try {
14
+ return fs.readJsonSync(configPath);
15
+ } catch (e) {
16
+ return null;
17
+ }
18
+ }
19
+ return null;
20
+ }
21
+
22
+ export function saveConfig(config, rootDir = process.cwd()) {
23
+ const configPath = getConfigPath(rootDir);
24
+ fs.writeJsonSync(configPath, config, { spaces: 2 });
25
+ }
26
+
27
+ export function updateConfig(updates, rootDir = process.cwd()) {
28
+ const currentConfig = loadConfig(rootDir) || {};
29
+ const newConfig = { ...currentConfig, ...updates };
30
+ saveConfig(newConfig, rootDir);
31
+ return newConfig;
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mad-pro-cli",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -25,6 +25,10 @@
25
25
  "dependencies": {
26
26
  "chalk": "^5.6.2",
27
27
  "commander": "^14.0.3",
28
- "fs-extra": "^11.3.4"
28
+ "fs-extra": "^11.3.4",
29
+ "inquirer": "^12.4.2"
30
+ },
31
+ "publishConfig": {
32
+ "access": "public"
29
33
  }
30
34
  }