@sun-asterisk/sunlint 1.3.38 → 1.3.39
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/cli.js +3 -2
- package/core/init-command.js +76 -2
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -24,8 +24,9 @@ program
|
|
|
24
24
|
.command('init [directory]')
|
|
25
25
|
.description('Initialize a project with SunLint code quality skill and AGENTS.md')
|
|
26
26
|
.option('-f, --force', 'Overwrite existing files')
|
|
27
|
-
.option('-t, --tool <tool>', `Target AI tool (default: ${DEFAULT_TOOL})
|
|
28
|
-
.option('-l, --language <language>', `Target language (default: typescript)
|
|
27
|
+
.option('-t, --tool <tool>', `Target AI tool (default: ${DEFAULT_TOOL})`)
|
|
28
|
+
.option('-l, --language <language>', `Target language (default: typescript)`)
|
|
29
|
+
.option('--non-interactive', 'Disable interactive prompts')
|
|
29
30
|
.addHelpText('after', `
|
|
30
31
|
AI Tool Options:
|
|
31
32
|
${getAvailableToolsHelp()}
|
package/core/init-command.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const chalk = require('chalk');
|
|
10
|
+
const readline = require('readline');
|
|
10
11
|
|
|
11
12
|
// Path to the bundled skill directory (relative to this file in the package)
|
|
12
13
|
const SKILL_SOURCE_DIR = path.join(__dirname, '..', 'skill-assets', 'sunlint-code-quality');
|
|
@@ -51,6 +52,52 @@ function getAvailableToolsHelp() {
|
|
|
51
52
|
.join('\n');
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Get available languages from rules directory
|
|
57
|
+
*/
|
|
58
|
+
function getAvailableLanguages() {
|
|
59
|
+
const rulesDir = path.join(SKILL_SOURCE_DIR, 'rules');
|
|
60
|
+
if (!fs.existsSync(rulesDir)) return ['typescript', 'csharp', 'python'];
|
|
61
|
+
|
|
62
|
+
return fs.readdirSync(rulesDir)
|
|
63
|
+
.filter(item => {
|
|
64
|
+
const fullPath = path.join(rulesDir, item);
|
|
65
|
+
return fs.statSync(fullPath).isDirectory();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Interactive selection helper
|
|
71
|
+
*/
|
|
72
|
+
async function promptSelection(question, options) {
|
|
73
|
+
const rl = readline.createInterface({
|
|
74
|
+
input: process.stdin,
|
|
75
|
+
output: process.stdout
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return new Promise((resolve) => {
|
|
79
|
+
console.log(chalk.cyan(`\n? ${question}`));
|
|
80
|
+
options.forEach((opt, i) => {
|
|
81
|
+
console.log(` ${chalk.white(i + 1)}) ${opt.name || opt}`);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const ask = () => {
|
|
85
|
+
rl.question(chalk.yellow(`\nSelect [1-${options.length}]: `), (answer) => {
|
|
86
|
+
const choice = parseInt(answer.trim());
|
|
87
|
+
if (choice >= 1 && choice <= options.length) {
|
|
88
|
+
rl.close();
|
|
89
|
+
const selected = options[choice - 1];
|
|
90
|
+
resolve(selected.key || selected);
|
|
91
|
+
} else {
|
|
92
|
+
console.log(chalk.red(`Invalid selection. Please enter a number between 1 and ${options.length}.`));
|
|
93
|
+
ask();
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
ask();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
54
101
|
/**
|
|
55
102
|
* Initialize a project with SunLint skill and AGENTS.md
|
|
56
103
|
* @param {string} targetDir - The target project directory
|
|
@@ -58,7 +105,33 @@ function getAvailableToolsHelp() {
|
|
|
58
105
|
*/
|
|
59
106
|
async function initProject(targetDir, options = {}) {
|
|
60
107
|
const resolvedTargetDir = path.resolve(targetDir);
|
|
61
|
-
|
|
108
|
+
|
|
109
|
+
let tool = options.tool;
|
|
110
|
+
let language = options.language;
|
|
111
|
+
|
|
112
|
+
// Interactive step-by-step setup if options are missing and in TTY
|
|
113
|
+
if (process.stdin.isTTY && process.stdout.isTTY && !options.nonInteractive) {
|
|
114
|
+
if (!tool) {
|
|
115
|
+
const toolOptions = Object.entries(AI_TOOL_CONFIG).map(([key, config]) => ({
|
|
116
|
+
key,
|
|
117
|
+
name: config.name
|
|
118
|
+
}));
|
|
119
|
+
tool = await promptSelection('Select Target AI Tool', toolOptions);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!language) {
|
|
123
|
+
const languageOptions = getAvailableLanguages();
|
|
124
|
+
language = await promptSelection('Select Target Language', languageOptions);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Apply defaults if still missing (non-interactive or failed prompt)
|
|
129
|
+
tool = tool || DEFAULT_TOOL;
|
|
130
|
+
language = language || 'typescript';
|
|
131
|
+
|
|
132
|
+
// Update options for subsequent steps
|
|
133
|
+
options.tool = tool;
|
|
134
|
+
options.language = language;
|
|
62
135
|
|
|
63
136
|
// Validate tool option
|
|
64
137
|
if (!AI_TOOL_CONFIG[tool]) {
|
|
@@ -72,6 +145,7 @@ async function initProject(targetDir, options = {}) {
|
|
|
72
145
|
|
|
73
146
|
console.log(chalk.cyan('\n☀️ SunLint Init - Setting up code quality standards...\n'));
|
|
74
147
|
console.log(chalk.blue(` 🤖 Target AI Tool: ${toolConfig.name}`));
|
|
148
|
+
console.log(chalk.blue(` 📝 Target Language: ${language}`));
|
|
75
149
|
|
|
76
150
|
// Validate target directory exists
|
|
77
151
|
if (!fs.existsSync(resolvedTargetDir)) {
|
|
@@ -91,7 +165,7 @@ async function initProject(targetDir, options = {}) {
|
|
|
91
165
|
console.log(chalk.white(' Files created/updated:'));
|
|
92
166
|
console.log(chalk.gray(` • ${path.relative(resolvedTargetDir, skillTargetDir)}/`));
|
|
93
167
|
console.log(chalk.gray(` • AGENTS.md`));
|
|
94
|
-
console.log(chalk.cyan(`\n📖 ${toolConfig.name} will now follow SunLint code quality standards.\n`));
|
|
168
|
+
console.log(chalk.cyan(`\n📖 ${toolConfig.name} will now follow SunLint code quality standards for ${language}.\n`));
|
|
95
169
|
}
|
|
96
170
|
|
|
97
171
|
/**
|
package/package.json
CHANGED