@meltstudio/meltctl 4.1.0 → 4.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.
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +130 -58
- package/dist/index.js +3 -1
- package/package.json +2 -1
package/dist/commands/init.d.ts
CHANGED
package/dist/commands/init.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
+
import { checkbox, confirm } from '@inquirer/prompts';
|
|
2
3
|
import fs from 'fs-extra';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import { authenticatedFetch, isAuthenticated } from '../utils/auth.js';
|
|
@@ -37,12 +38,78 @@ async function fetchTemplates() {
|
|
|
37
38
|
const data = (await response.json());
|
|
38
39
|
return data.files;
|
|
39
40
|
}
|
|
41
|
+
function detectExistingTools(cwd) {
|
|
42
|
+
return {
|
|
43
|
+
claude: fs.pathExistsSync(path.join(cwd, '.claude/settings.json')),
|
|
44
|
+
cursor: fs.pathExistsSync(path.join(cwd, '.cursor/commands')),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function promptToolSelection(existingTools) {
|
|
48
|
+
const choices = [];
|
|
49
|
+
if (!existingTools?.claude) {
|
|
50
|
+
choices.push({ name: 'Claude Code', value: 'claude', checked: true });
|
|
51
|
+
}
|
|
52
|
+
if (!existingTools?.cursor) {
|
|
53
|
+
choices.push({ name: 'Cursor', value: 'cursor', checked: true });
|
|
54
|
+
}
|
|
55
|
+
choices.push({
|
|
56
|
+
name: 'Other — contact us in #dev on Slack to request support',
|
|
57
|
+
value: 'other',
|
|
58
|
+
});
|
|
59
|
+
const selected = await checkbox({
|
|
60
|
+
message: 'Which AI coding tools do you use?',
|
|
61
|
+
choices,
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
claude: selected.includes('claude'),
|
|
65
|
+
cursor: selected.includes('cursor'),
|
|
66
|
+
other: selected.includes('other'),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
40
69
|
export async function initCommand(options) {
|
|
41
70
|
const cwd = process.cwd();
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
71
|
+
const alreadyInitialized = await fs.pathExists(path.join(cwd, 'AGENTS.md'));
|
|
72
|
+
let isReInit = false;
|
|
73
|
+
let tools;
|
|
74
|
+
if (alreadyInitialized && !options.force) {
|
|
75
|
+
// Re-init scenario: project already set up, developer wants to add another tool
|
|
76
|
+
const existing = detectExistingTools(cwd);
|
|
77
|
+
const existingNames = [existing.claude ? 'Claude Code' : '', existing.cursor ? 'Cursor' : '']
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
.join(' and ');
|
|
80
|
+
if (existing.claude && existing.cursor) {
|
|
81
|
+
console.log(chalk.yellow('Project already initialized with Claude Code and Cursor. Use --force to overwrite.'));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
console.log(chalk.dim(`Project already initialized${existingNames ? ` with ${existingNames}` : ''}.`));
|
|
85
|
+
isReInit = true;
|
|
86
|
+
if (options.claude || options.cursor) {
|
|
87
|
+
// Non-interactive: use flags directly, skip confirm prompt
|
|
88
|
+
tools = { claude: !!options.claude, cursor: !!options.cursor, other: false };
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const addMore = await confirm({
|
|
92
|
+
message: 'Add configuration for another tool?',
|
|
93
|
+
default: true,
|
|
94
|
+
});
|
|
95
|
+
if (!addMore) {
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
tools = await promptToolSelection(existing);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Fresh init or --force
|
|
103
|
+
if (options.claude || options.cursor) {
|
|
104
|
+
tools = { claude: !!options.claude, cursor: !!options.cursor, other: false };
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
tools = await promptToolSelection();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (!tools.claude && !tools.cursor && !tools.other) {
|
|
111
|
+
console.log(chalk.yellow('No tools selected. Nothing to do.'));
|
|
112
|
+
process.exit(0);
|
|
46
113
|
}
|
|
47
114
|
// Require authentication
|
|
48
115
|
if (!(await isAuthenticated())) {
|
|
@@ -67,69 +134,74 @@ export async function initCommand(options) {
|
|
|
67
134
|
}
|
|
68
135
|
console.log(chalk.bold('Initializing Melt development tools...'));
|
|
69
136
|
console.log();
|
|
70
|
-
|
|
71
|
-
const agentsMd = templates['agents-md.md'];
|
|
72
|
-
if (agentsMd) {
|
|
73
|
-
await fs.writeFile(path.join(cwd, 'AGENTS.md'), agentsMd, 'utf-8');
|
|
74
|
-
}
|
|
75
|
-
// Copy .claude/settings.json
|
|
76
|
-
const claudeSettings = templates['claude-settings.json'];
|
|
77
|
-
if (claudeSettings) {
|
|
78
|
-
await fs.ensureDir(path.join(cwd, '.claude'));
|
|
79
|
-
await fs.writeFile(path.join(cwd, '.claude/settings.json'), claudeSettings, 'utf-8');
|
|
80
|
-
}
|
|
81
|
-
// Create Claude skills from workflow templates
|
|
137
|
+
const createdFiles = [];
|
|
82
138
|
const workflows = ['plan', 'review', 'pr', 'debug'];
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
await fs.
|
|
88
|
-
|
|
89
|
-
await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
|
|
139
|
+
// Shared files (skip on re-init)
|
|
140
|
+
if (!isReInit) {
|
|
141
|
+
const agentsMd = templates['agents-md.md'];
|
|
142
|
+
if (agentsMd) {
|
|
143
|
+
await fs.writeFile(path.join(cwd, 'AGENTS.md'), agentsMd, 'utf-8');
|
|
144
|
+
createdFiles.push('AGENTS.md');
|
|
90
145
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
await fs.ensureDir(path.join(cwd, '.cursor/rules'));
|
|
96
|
-
await fs.writeFile(path.join(cwd, '.cursor/rules/standards.mdc'), cursorRules, 'utf-8');
|
|
97
|
-
}
|
|
98
|
-
// Copy Cursor commands from workflow templates
|
|
99
|
-
await fs.ensureDir(path.join(cwd, '.cursor/commands'));
|
|
100
|
-
for (const name of workflows) {
|
|
101
|
-
const workflowContent = templates[`workflows/${name}.md`];
|
|
102
|
-
if (workflowContent) {
|
|
103
|
-
await fs.writeFile(path.join(cwd, `.cursor/commands/melt-${name}.md`), workflowContent, 'utf-8');
|
|
146
|
+
const mcpConfig = templates['mcp-configs/base.json'];
|
|
147
|
+
if (mcpConfig) {
|
|
148
|
+
await fs.writeFile(path.join(cwd, '.mcp.json'), mcpConfig, 'utf-8');
|
|
149
|
+
createdFiles.push('.mcp.json');
|
|
104
150
|
}
|
|
151
|
+
const envExample = templates['env-melt-example'];
|
|
152
|
+
if (envExample) {
|
|
153
|
+
await fs.writeFile(path.join(cwd, '.env.melt.example'), envExample, 'utf-8');
|
|
154
|
+
createdFiles.push('.env.melt.example');
|
|
155
|
+
}
|
|
156
|
+
await updateGitignore(cwd);
|
|
105
157
|
}
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
158
|
+
// Claude Code files
|
|
159
|
+
if (tools.claude) {
|
|
160
|
+
const claudeSettings = templates['claude-settings.json'];
|
|
161
|
+
if (claudeSettings) {
|
|
162
|
+
await fs.ensureDir(path.join(cwd, '.claude'));
|
|
163
|
+
await fs.writeFile(path.join(cwd, '.claude/settings.json'), claudeSettings, 'utf-8');
|
|
164
|
+
createdFiles.push('.claude/settings.json');
|
|
165
|
+
}
|
|
166
|
+
for (const name of workflows) {
|
|
167
|
+
const workflowContent = templates[`workflows/${name}.md`];
|
|
168
|
+
if (workflowContent) {
|
|
169
|
+
const skillDir = path.join(cwd, `.claude/skills/melt-${name}`);
|
|
170
|
+
await fs.ensureDir(skillDir);
|
|
171
|
+
const skillContent = SKILL_FRONTMATTER[name] + workflowContent;
|
|
172
|
+
await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
createdFiles.push('.claude/skills/melt-{plan,review,pr,debug}/SKILL.md');
|
|
110
176
|
}
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
177
|
+
// Cursor files
|
|
178
|
+
if (tools.cursor) {
|
|
179
|
+
await fs.ensureDir(path.join(cwd, '.cursor/commands'));
|
|
180
|
+
for (const name of workflows) {
|
|
181
|
+
const workflowContent = templates[`workflows/${name}.md`];
|
|
182
|
+
if (workflowContent) {
|
|
183
|
+
await fs.writeFile(path.join(cwd, `.cursor/commands/melt-${name}.md`), workflowContent, 'utf-8');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
createdFiles.push('.cursor/commands/melt-{plan,review,pr,debug}.md');
|
|
115
187
|
}
|
|
116
|
-
// Update .gitignore
|
|
117
|
-
await updateGitignore(cwd);
|
|
118
188
|
// Print summary
|
|
119
189
|
console.log(chalk.green('Created files:'));
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
console.log(chalk.dim(' .cursor/rules/standards.mdc'));
|
|
124
|
-
console.log(chalk.dim(' .cursor/commands/melt-{plan,review,pr,debug}.md'));
|
|
125
|
-
console.log(chalk.dim(' .mcp.json'));
|
|
126
|
-
console.log(chalk.dim(' .env.melt.example'));
|
|
127
|
-
console.log();
|
|
128
|
-
console.log(chalk.yellow('Next steps:'));
|
|
129
|
-
console.log(chalk.dim(' 1. Edit AGENTS.md to describe your project and add team-specific standards'));
|
|
130
|
-
console.log(chalk.dim(' 2. Copy .env.melt.example to .env.local and fill in credentials'));
|
|
131
|
-
console.log(chalk.dim(' 3. Commit the generated files'));
|
|
190
|
+
for (const file of createdFiles) {
|
|
191
|
+
console.log(chalk.dim(` ${file}`));
|
|
192
|
+
}
|
|
132
193
|
console.log();
|
|
194
|
+
if (tools.other) {
|
|
195
|
+
console.log(chalk.cyan('Want support for your tool? Let us know in #dev on Slack'));
|
|
196
|
+
console.log();
|
|
197
|
+
}
|
|
198
|
+
if (!isReInit) {
|
|
199
|
+
console.log(chalk.yellow('Next steps:'));
|
|
200
|
+
console.log(chalk.dim(' 1. Run your AI agent — it will automatically fill in project details in AGENTS.md'));
|
|
201
|
+
console.log(chalk.dim(' 2. Copy .env.melt.example to .env.local and fill in credentials'));
|
|
202
|
+
console.log(chalk.dim(' 3. Commit the generated files'));
|
|
203
|
+
console.log();
|
|
204
|
+
}
|
|
133
205
|
console.log(chalk.green('Done!'));
|
|
134
206
|
}
|
|
135
207
|
async function updateGitignore(cwd) {
|
package/dist/index.js
CHANGED
|
@@ -42,8 +42,10 @@ project
|
|
|
42
42
|
.command('init')
|
|
43
43
|
.description('scaffold Melt development tools into the current directory (AGENTS.md, .claude/, .cursor/, .mcp.json)')
|
|
44
44
|
.option('--force', 'overwrite existing files if already initialized')
|
|
45
|
+
.option('--claude', 'generate Claude Code configuration')
|
|
46
|
+
.option('--cursor', 'generate Cursor configuration')
|
|
45
47
|
.action(options => {
|
|
46
|
-
return initCommand({ force: options.force });
|
|
48
|
+
return initCommand({ force: options.force, claude: options.claude, cursor: options.cursor });
|
|
47
49
|
});
|
|
48
50
|
program
|
|
49
51
|
.command('version')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meltstudio/meltctl",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "AI-first development tools for teams - set up AGENTS.md, Claude Code, Cursor, and Copilot standards",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"license": "MIT",
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@commander-js/extra-typings": "^12.1.0",
|
|
51
|
+
"@inquirer/prompts": "^8.2.1",
|
|
51
52
|
"chalk": "^5.4.1",
|
|
52
53
|
"commander": "^12.1.0",
|
|
53
54
|
"fs-extra": "^11.2.0",
|