@meltstudio/meltctl 4.38.0 → 4.38.1
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/index.js +2178 -210
- package/package.json +4 -3
- package/dist/commands/audit.d.ts +0 -10
- package/dist/commands/audit.js +0 -191
- package/dist/commands/audit.test.d.ts +0 -1
- package/dist/commands/audit.test.js +0 -324
- package/dist/commands/coins.d.ts +0 -5
- package/dist/commands/coins.js +0 -51
- package/dist/commands/coins.test.d.ts +0 -1
- package/dist/commands/coins.test.js +0 -113
- package/dist/commands/feedback.d.ts +0 -7
- package/dist/commands/feedback.js +0 -90
- package/dist/commands/feedback.test.d.ts +0 -1
- package/dist/commands/feedback.test.js +0 -177
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.js +0 -520
- package/dist/commands/init.test.d.ts +0 -1
- package/dist/commands/init.test.js +0 -478
- package/dist/commands/login.d.ts +0 -1
- package/dist/commands/login.js +0 -90
- package/dist/commands/login.test.d.ts +0 -1
- package/dist/commands/login.test.js +0 -194
- package/dist/commands/logout.d.ts +0 -1
- package/dist/commands/logout.js +0 -12
- package/dist/commands/logout.test.d.ts +0 -1
- package/dist/commands/logout.test.js +0 -59
- package/dist/commands/plan.d.ts +0 -6
- package/dist/commands/plan.js +0 -123
- package/dist/commands/plan.test.d.ts +0 -1
- package/dist/commands/plan.test.js +0 -246
- package/dist/commands/standup.d.ts +0 -7
- package/dist/commands/standup.js +0 -74
- package/dist/commands/standup.test.d.ts +0 -1
- package/dist/commands/standup.test.js +0 -218
- package/dist/commands/templates.d.ts +0 -1
- package/dist/commands/templates.js +0 -37
- package/dist/commands/templates.test.d.ts +0 -1
- package/dist/commands/templates.test.js +0 -89
- package/dist/commands/update.d.ts +0 -2
- package/dist/commands/update.js +0 -74
- package/dist/commands/update.test.d.ts +0 -1
- package/dist/commands/update.test.js +0 -93
- package/dist/commands/version.d.ts +0 -1
- package/dist/commands/version.js +0 -43
- package/dist/commands/version.test.d.ts +0 -1
- package/dist/commands/version.test.js +0 -86
- package/dist/index.d.ts +0 -2
- package/dist/utils/analytics.d.ts +0 -1
- package/dist/utils/analytics.js +0 -54
- package/dist/utils/analytics.test.d.ts +0 -1
- package/dist/utils/analytics.test.js +0 -91
- package/dist/utils/api.d.ts +0 -3
- package/dist/utils/api.js +0 -23
- package/dist/utils/api.test.d.ts +0 -1
- package/dist/utils/api.test.js +0 -76
- package/dist/utils/auth.d.ts +0 -12
- package/dist/utils/auth.js +0 -54
- package/dist/utils/auth.test.d.ts +0 -1
- package/dist/utils/auth.test.js +0 -165
- package/dist/utils/banner.d.ts +0 -1
- package/dist/utils/banner.js +0 -22
- package/dist/utils/banner.test.d.ts +0 -1
- package/dist/utils/banner.test.js +0 -34
- package/dist/utils/debug.d.ts +0 -1
- package/dist/utils/debug.js +0 -6
- package/dist/utils/git.d.ts +0 -9
- package/dist/utils/git.js +0 -76
- package/dist/utils/git.test.d.ts +0 -1
- package/dist/utils/git.test.js +0 -184
- package/dist/utils/package-manager.d.ts +0 -7
- package/dist/utils/package-manager.js +0 -55
- package/dist/utils/package-manager.test.d.ts +0 -1
- package/dist/utils/package-manager.test.js +0 -76
- package/dist/utils/templates.d.ts +0 -2
- package/dist/utils/templates.js +0 -5
- package/dist/utils/templates.test.d.ts +0 -1
- package/dist/utils/templates.test.js +0 -38
- package/dist/utils/version-check.d.ts +0 -7
- package/dist/utils/version-check.js +0 -139
- package/dist/utils/version-check.test.d.ts +0 -1
- package/dist/utils/version-check.test.js +0 -189
package/dist/commands/init.js
DELETED
|
@@ -1,520 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { checkbox, confirm } from '@inquirer/prompts';
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { isAuthenticated } from '../utils/auth.js';
|
|
6
|
-
import { fetchTemplates } from '../utils/templates.js';
|
|
7
|
-
const SKILL_FRONTMATTER = {
|
|
8
|
-
setup: `---
|
|
9
|
-
user-invocable: true
|
|
10
|
-
description: >-
|
|
11
|
-
Analyze the project and customize AGENTS.md for this codebase.
|
|
12
|
-
Use when setting up a new project, after running meltctl init,
|
|
13
|
-
or when AGENTS.md has placeholder markers. Detects tech stack,
|
|
14
|
-
fills in project-specific sections, and merges existing standards.
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
`,
|
|
18
|
-
plan: `---
|
|
19
|
-
user-invocable: true
|
|
20
|
-
description: >-
|
|
21
|
-
Design an implementation approach before writing code. Use when
|
|
22
|
-
starting a feature, tackling a complex task, or when the developer
|
|
23
|
-
says "plan this" or "how should we approach this". Gathers requirements,
|
|
24
|
-
explores codebase, and presents a step-by-step plan for approval.
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
`,
|
|
28
|
-
review: `---
|
|
29
|
-
user-invocable: true
|
|
30
|
-
description: >-
|
|
31
|
-
Review code changes against project standards and address PR feedback.
|
|
32
|
-
Use when the developer asks to review changes, check code quality,
|
|
33
|
-
or respond to PR reviewer comments. Categorizes findings as must-fix,
|
|
34
|
-
should-fix, or suggestions.
|
|
35
|
-
---
|
|
36
|
-
|
|
37
|
-
`,
|
|
38
|
-
pr: `---
|
|
39
|
-
user-invocable: true
|
|
40
|
-
description: >-
|
|
41
|
-
Create a well-structured pull request from current changes. Use when
|
|
42
|
-
the developer is ready to submit work, says "create a PR", or "open
|
|
43
|
-
a pull request". Analyzes changes, runs pre-flight checks, drafts
|
|
44
|
-
description, and creates the PR via gh CLI.
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
`,
|
|
48
|
-
debug: `---
|
|
49
|
-
user-invocable: true
|
|
50
|
-
description: >-
|
|
51
|
-
Systematically investigate and fix bugs. Use when the developer
|
|
52
|
-
reports a bug, encounters an error, or says "debug this" or "why
|
|
53
|
-
is this failing". Reproduces the issue, isolates root cause, writes
|
|
54
|
-
regression test, and implements minimal fix.
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
`,
|
|
58
|
-
audit: `---
|
|
59
|
-
user-invocable: true
|
|
60
|
-
description: >-
|
|
61
|
-
Run a comprehensive project compliance audit against team standards.
|
|
62
|
-
Use when the developer wants to assess project health, check compliance,
|
|
63
|
-
or says "audit this project". Checks 15 categories including documentation,
|
|
64
|
-
testing, CI/CD, security, and AI tool setup. Produces a structured
|
|
65
|
-
report with scores and actionable fixes.
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
`,
|
|
69
|
-
'ux-audit': `---
|
|
70
|
-
user-invocable: true
|
|
71
|
-
description: >-
|
|
72
|
-
Review the project's UI against usability heuristics using Chrome DevTools
|
|
73
|
-
MCP. Use when the developer wants to check UX quality, says "review the UI",
|
|
74
|
-
or "UX audit". In full audit mode, crawls the entire app. During an active
|
|
75
|
-
plan, scopes to the current feature and appends results to the plan file.
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
`,
|
|
79
|
-
'security-audit': `---
|
|
80
|
-
user-invocable: true
|
|
81
|
-
description: >-
|
|
82
|
-
Run a comprehensive security posture audit across the entire platform.
|
|
83
|
-
Use when the developer wants to assess security, says "security audit",
|
|
84
|
-
or "check our security posture". Covers infrastructure, encryption, auth,
|
|
85
|
-
application security, data protection, CI/CD, and compliance readiness.
|
|
86
|
-
Investigates all platform repositories for a holistic view.
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
`,
|
|
90
|
-
validate: `---
|
|
91
|
-
user-invocable: true
|
|
92
|
-
description: >-
|
|
93
|
-
Run the validation plan from the plan document after implementation.
|
|
94
|
-
Use when the developer says "validate this", "test the feature", or
|
|
95
|
-
after finishing implementation. Validates end-to-end using browser,
|
|
96
|
-
API, or CLI testing, suggests test coverage improvements, then prompts
|
|
97
|
-
the developer for mandatory manual sign-off.
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
`,
|
|
101
|
-
update: `---
|
|
102
|
-
user-invocable: true
|
|
103
|
-
description: >-
|
|
104
|
-
Update Melt skills and standards to the latest version. Use when the
|
|
105
|
-
developer wants the latest skill templates, says "update melt", or
|
|
106
|
-
after a new meltctl version is released. Fetches latest templates,
|
|
107
|
-
preserves project customizations in AGENTS.md, and merges changes.
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
`,
|
|
111
|
-
help: `---
|
|
112
|
-
user-invocable: true
|
|
113
|
-
description: >-
|
|
114
|
-
Answer questions about the AI-First Development Playbook and team
|
|
115
|
-
workflow. Use when the developer asks about the development process,
|
|
116
|
-
what step they're on, how validation works, or any workflow question.
|
|
117
|
-
This is a reference skill — it explains the process, not executes it.
|
|
118
|
-
---
|
|
119
|
-
|
|
120
|
-
`,
|
|
121
|
-
link: `---
|
|
122
|
-
user-invocable: true
|
|
123
|
-
description: >-
|
|
124
|
-
Connect and verify required integrations (ticket tracker, browser
|
|
125
|
-
testing). Use after melt-setup, when tools aren't working, or when
|
|
126
|
-
a skill reports missing MCP connections. Guides setup, verifies
|
|
127
|
-
each tool works, and updates AGENTS.md connection status.
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
`,
|
|
131
|
-
};
|
|
132
|
-
const OPENCODE_COMMAND_FRONTMATTER = {
|
|
133
|
-
setup: `---
|
|
134
|
-
description: Analyze the project and customize AGENTS.md for this codebase.
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
`,
|
|
138
|
-
plan: `---
|
|
139
|
-
description: Design an implementation approach before writing code.
|
|
140
|
-
---
|
|
141
|
-
|
|
142
|
-
`,
|
|
143
|
-
review: `---
|
|
144
|
-
description: Review code changes against project standards and address PR feedback.
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
`,
|
|
148
|
-
pr: `---
|
|
149
|
-
description: Create a well-structured pull request from current changes.
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
`,
|
|
153
|
-
debug: `---
|
|
154
|
-
description: Systematically investigate and fix bugs.
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
`,
|
|
158
|
-
audit: `---
|
|
159
|
-
description: Run a comprehensive project compliance audit against team standards.
|
|
160
|
-
---
|
|
161
|
-
|
|
162
|
-
`,
|
|
163
|
-
'ux-audit': `---
|
|
164
|
-
description: Review the project's UI against usability heuristics using Chrome DevTools MCP.
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
`,
|
|
168
|
-
'security-audit': `---
|
|
169
|
-
description: Run a comprehensive security posture audit across the entire platform.
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
`,
|
|
173
|
-
validate: `---
|
|
174
|
-
description: Run the validation plan from the plan document after implementation.
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
`,
|
|
178
|
-
update: `---
|
|
179
|
-
description: Update Melt skills and standards to the latest version.
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
`,
|
|
183
|
-
help: `---
|
|
184
|
-
description: Answer questions about the AI-First Development Playbook and team workflow.
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
`,
|
|
188
|
-
link: `---
|
|
189
|
-
description: Connect and verify required integrations (ticket tracker, browser testing).
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
`,
|
|
193
|
-
};
|
|
194
|
-
const GITIGNORE_ENTRIES = ['.env.local', '.claude/settings.local.json'];
|
|
195
|
-
function detectExistingTools(cwd) {
|
|
196
|
-
return {
|
|
197
|
-
claude: fs.pathExistsSync(path.join(cwd, '.claude/settings.json')),
|
|
198
|
-
cursor: fs.pathExistsSync(path.join(cwd, '.cursor/commands')),
|
|
199
|
-
opencode: fs.pathExistsSync(path.join(cwd, '.opencode/commands')),
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
async function promptToolSelection(existingTools) {
|
|
203
|
-
const choices = [];
|
|
204
|
-
if (!existingTools?.claude) {
|
|
205
|
-
choices.push({ name: 'Claude Code', value: 'claude', checked: true });
|
|
206
|
-
}
|
|
207
|
-
if (!existingTools?.cursor) {
|
|
208
|
-
choices.push({ name: 'Cursor', value: 'cursor', checked: true });
|
|
209
|
-
}
|
|
210
|
-
if (!existingTools?.opencode) {
|
|
211
|
-
choices.push({ name: 'OpenCode', value: 'opencode', checked: true });
|
|
212
|
-
}
|
|
213
|
-
choices.push({
|
|
214
|
-
name: 'Other — contact us in #dev on Slack to request support',
|
|
215
|
-
value: 'other',
|
|
216
|
-
});
|
|
217
|
-
const selected = await checkbox({
|
|
218
|
-
message: 'Which AI coding tools do you use?',
|
|
219
|
-
choices,
|
|
220
|
-
});
|
|
221
|
-
return {
|
|
222
|
-
claude: selected.includes('claude'),
|
|
223
|
-
cursor: selected.includes('cursor'),
|
|
224
|
-
opencode: selected.includes('opencode'),
|
|
225
|
-
other: selected.includes('other'),
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
export async function initCommand(options) {
|
|
229
|
-
// Check authentication before anything else to avoid wasted prompts
|
|
230
|
-
if (!(await isAuthenticated())) {
|
|
231
|
-
console.error(chalk.red('Not authenticated. Run `npx @meltstudio/meltctl@latest login` first.'));
|
|
232
|
-
process.exit(1);
|
|
233
|
-
}
|
|
234
|
-
const cwd = process.cwd();
|
|
235
|
-
// Warn if not in a git repository — likely the wrong directory
|
|
236
|
-
const isGitRepo = await fs.pathExists(path.join(cwd, '.git'));
|
|
237
|
-
if (!isGitRepo) {
|
|
238
|
-
console.log(chalk.yellow(`Warning: ${cwd} is not a git repository.`));
|
|
239
|
-
console.log(chalk.dim('meltctl init should be run from the root of your project.'));
|
|
240
|
-
console.log();
|
|
241
|
-
const proceed = await confirm({
|
|
242
|
-
message: 'Continue initializing here anyway?',
|
|
243
|
-
default: false,
|
|
244
|
-
});
|
|
245
|
-
if (!proceed) {
|
|
246
|
-
console.log(chalk.dim('Aborted. cd into your project root and try again.'));
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
console.log();
|
|
250
|
-
}
|
|
251
|
-
const alreadyInitialized = await fs.pathExists(path.join(cwd, 'AGENTS.md'));
|
|
252
|
-
let isReInit = false;
|
|
253
|
-
let tools;
|
|
254
|
-
if (alreadyInitialized && !options.force) {
|
|
255
|
-
// Re-init scenario: project already set up, developer wants to add another tool
|
|
256
|
-
const existing = detectExistingTools(cwd);
|
|
257
|
-
const existingNames = [
|
|
258
|
-
existing.claude ? 'Claude Code' : '',
|
|
259
|
-
existing.cursor ? 'Cursor' : '',
|
|
260
|
-
existing.opencode ? 'OpenCode' : '',
|
|
261
|
-
]
|
|
262
|
-
.filter(Boolean)
|
|
263
|
-
.join(', ');
|
|
264
|
-
if (existing.claude && existing.cursor && existing.opencode) {
|
|
265
|
-
console.log(chalk.yellow('Project already initialized with all tools. Use --force to overwrite.'));
|
|
266
|
-
process.exit(1);
|
|
267
|
-
}
|
|
268
|
-
console.log(chalk.dim(`Project already initialized${existingNames ? ` with ${existingNames}` : ''}.`));
|
|
269
|
-
isReInit = true;
|
|
270
|
-
if (options.claude || options.cursor || options.opencode) {
|
|
271
|
-
// Non-interactive: use flags directly, skip confirm prompt
|
|
272
|
-
tools = {
|
|
273
|
-
claude: !!options.claude,
|
|
274
|
-
cursor: !!options.cursor,
|
|
275
|
-
opencode: !!options.opencode,
|
|
276
|
-
other: false,
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
const addMore = await confirm({
|
|
281
|
-
message: 'Add configuration for another tool?',
|
|
282
|
-
default: true,
|
|
283
|
-
});
|
|
284
|
-
if (!addMore) {
|
|
285
|
-
process.exit(0);
|
|
286
|
-
}
|
|
287
|
-
tools = await promptToolSelection(existing);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
else {
|
|
291
|
-
// Fresh init or --force
|
|
292
|
-
if (options.claude || options.cursor || options.opencode) {
|
|
293
|
-
tools = {
|
|
294
|
-
claude: !!options.claude,
|
|
295
|
-
cursor: !!options.cursor,
|
|
296
|
-
opencode: !!options.opencode,
|
|
297
|
-
other: false,
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
tools = await promptToolSelection();
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
if (!tools.claude && !tools.cursor && !tools.opencode && !tools.other) {
|
|
305
|
-
console.log(chalk.yellow('No tools selected. Nothing to do.'));
|
|
306
|
-
process.exit(0);
|
|
307
|
-
}
|
|
308
|
-
let templates;
|
|
309
|
-
try {
|
|
310
|
-
templates = await fetchTemplates();
|
|
311
|
-
}
|
|
312
|
-
catch (error) {
|
|
313
|
-
if (error instanceof Error && error.message.includes('expired')) {
|
|
314
|
-
console.error(chalk.red('Session expired. Run `npx @meltstudio/meltctl@latest login` to re-authenticate.'));
|
|
315
|
-
}
|
|
316
|
-
else if (error instanceof Error && error.message.includes('fetch')) {
|
|
317
|
-
console.error(chalk.red('Could not reach Melt API. Check your connection.'));
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
console.error(chalk.red(`Failed to fetch templates: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
321
|
-
}
|
|
322
|
-
process.exit(1);
|
|
323
|
-
}
|
|
324
|
-
console.log(chalk.bold('Initializing Melt development tools...'));
|
|
325
|
-
console.log();
|
|
326
|
-
const createdFiles = [];
|
|
327
|
-
const workflows = [
|
|
328
|
-
'setup',
|
|
329
|
-
'plan',
|
|
330
|
-
'validate',
|
|
331
|
-
'review',
|
|
332
|
-
'pr',
|
|
333
|
-
'debug',
|
|
334
|
-
'audit',
|
|
335
|
-
'ux-audit',
|
|
336
|
-
'security-audit',
|
|
337
|
-
'update',
|
|
338
|
-
'help',
|
|
339
|
-
'link',
|
|
340
|
-
];
|
|
341
|
-
// Shared files (skip on re-init)
|
|
342
|
-
if (!isReInit) {
|
|
343
|
-
const agentsMd = templates['agents-md.md'];
|
|
344
|
-
if (agentsMd) {
|
|
345
|
-
await fs.writeFile(path.join(cwd, 'AGENTS.md'), agentsMd, 'utf-8');
|
|
346
|
-
createdFiles.push('AGENTS.md');
|
|
347
|
-
}
|
|
348
|
-
const mcpConfig = templates['mcp-configs/base.json'];
|
|
349
|
-
if (mcpConfig) {
|
|
350
|
-
await mergeMcpConfig(cwd, mcpConfig);
|
|
351
|
-
createdFiles.push('.mcp.json');
|
|
352
|
-
}
|
|
353
|
-
await updateGitignore(cwd);
|
|
354
|
-
}
|
|
355
|
-
// Claude Code files
|
|
356
|
-
if (tools.claude) {
|
|
357
|
-
const claudeSettings = templates['claude-settings.json'];
|
|
358
|
-
if (claudeSettings) {
|
|
359
|
-
await fs.ensureDir(path.join(cwd, '.claude'));
|
|
360
|
-
await mergeClaudeSettings(cwd, claudeSettings);
|
|
361
|
-
createdFiles.push('.claude/settings.json');
|
|
362
|
-
}
|
|
363
|
-
for (const name of workflows) {
|
|
364
|
-
const workflowContent = templates[`workflows/${name}.md`];
|
|
365
|
-
if (workflowContent) {
|
|
366
|
-
const skillDir = path.join(cwd, `.claude/skills/melt-${name}`);
|
|
367
|
-
await fs.ensureDir(skillDir);
|
|
368
|
-
const skillContent = SKILL_FRONTMATTER[name] + workflowContent;
|
|
369
|
-
await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
createdFiles.push('.claude/skills/melt-{setup,plan,validate,review,pr,debug,audit,ux-audit,security-audit,update,help}/SKILL.md');
|
|
373
|
-
}
|
|
374
|
-
// Cursor files
|
|
375
|
-
if (tools.cursor) {
|
|
376
|
-
await fs.ensureDir(path.join(cwd, '.cursor/commands'));
|
|
377
|
-
for (const name of workflows) {
|
|
378
|
-
const workflowContent = templates[`workflows/${name}.md`];
|
|
379
|
-
if (workflowContent) {
|
|
380
|
-
await fs.writeFile(path.join(cwd, `.cursor/commands/melt-${name}.md`), workflowContent, 'utf-8');
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
createdFiles.push('.cursor/commands/melt-{setup,plan,validate,review,pr,debug,audit,ux-audit,security-audit,update,help}.md');
|
|
384
|
-
}
|
|
385
|
-
// OpenCode files
|
|
386
|
-
if (tools.opencode) {
|
|
387
|
-
await fs.ensureDir(path.join(cwd, '.opencode/commands'));
|
|
388
|
-
for (const name of workflows) {
|
|
389
|
-
const workflowContent = templates[`workflows/${name}.md`];
|
|
390
|
-
if (workflowContent) {
|
|
391
|
-
const commandContent = OPENCODE_COMMAND_FRONTMATTER[name] + workflowContent;
|
|
392
|
-
await fs.writeFile(path.join(cwd, `.opencode/commands/melt-${name}.md`), commandContent, 'utf-8');
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
createdFiles.push('.opencode/commands/melt-{setup,plan,validate,review,pr,debug,audit,ux-audit,security-audit,update,help}.md');
|
|
396
|
-
}
|
|
397
|
-
// Print summary
|
|
398
|
-
console.log(chalk.green('Created files:'));
|
|
399
|
-
for (const file of createdFiles) {
|
|
400
|
-
console.log(chalk.dim(` ${file}`));
|
|
401
|
-
}
|
|
402
|
-
console.log();
|
|
403
|
-
if (tools.other) {
|
|
404
|
-
console.log(chalk.cyan('Want support for your tool? Let us know in #dev on Slack'));
|
|
405
|
-
console.log();
|
|
406
|
-
}
|
|
407
|
-
const commandNames = 'melt-setup, melt-plan, melt-validate, melt-review, melt-pr, melt-debug, melt-audit, melt-ux-audit, melt-security-audit, melt-update, melt-help';
|
|
408
|
-
if (tools.claude) {
|
|
409
|
-
console.log(chalk.dim(`Available skills: /${commandNames.replace(/, /g, ', /')}`));
|
|
410
|
-
}
|
|
411
|
-
if (tools.cursor) {
|
|
412
|
-
console.log(chalk.dim(`Available Cursor commands: ${commandNames}`));
|
|
413
|
-
}
|
|
414
|
-
if (tools.opencode) {
|
|
415
|
-
console.log(chalk.dim(`Available OpenCode commands: /${commandNames.replace(/, /g, ', /')}`));
|
|
416
|
-
}
|
|
417
|
-
if (tools.claude || tools.cursor || tools.opencode) {
|
|
418
|
-
console.log();
|
|
419
|
-
}
|
|
420
|
-
if (!isReInit) {
|
|
421
|
-
console.log(chalk.bold.cyan(' Next step: run /melt-setup to customize AGENTS.md for your project'));
|
|
422
|
-
console.log();
|
|
423
|
-
const toolInstructions = [];
|
|
424
|
-
if (tools.claude) {
|
|
425
|
-
toolInstructions.push({
|
|
426
|
-
name: 'Claude Code',
|
|
427
|
-
steps: [
|
|
428
|
-
'Type /melt-setup in the chat prompt, or',
|
|
429
|
-
'Open the skills menu and select melt-setup',
|
|
430
|
-
],
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
if (tools.cursor) {
|
|
434
|
-
toolInstructions.push({
|
|
435
|
-
name: 'Cursor',
|
|
436
|
-
steps: ['Open the command menu (Cmd+K) and search for melt-setup'],
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
if (tools.opencode) {
|
|
440
|
-
toolInstructions.push({
|
|
441
|
-
name: 'OpenCode',
|
|
442
|
-
steps: ['Type /melt-setup in the chat prompt'],
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
if (toolInstructions.length === 1 && toolInstructions[0]) {
|
|
446
|
-
console.log(chalk.dim(` In ${toolInstructions[0].name}:`));
|
|
447
|
-
for (const step of toolInstructions[0].steps) {
|
|
448
|
-
console.log(chalk.dim(` - ${step}`));
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
for (const tool of toolInstructions) {
|
|
453
|
-
console.log(chalk.dim(` ${tool.name}:`));
|
|
454
|
-
for (const step of tool.steps) {
|
|
455
|
-
console.log(chalk.dim(` - ${step}`));
|
|
456
|
-
}
|
|
457
|
-
console.log();
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
console.log();
|
|
461
|
-
console.log(chalk.dim(' The setup skill will analyze your project and fill in AGENTS.md.'));
|
|
462
|
-
console.log(chalk.dim(' Then run /melt-link to connect your ticket tracker and browser testing tools.'));
|
|
463
|
-
console.log();
|
|
464
|
-
}
|
|
465
|
-
console.log(chalk.green('Done!'));
|
|
466
|
-
}
|
|
467
|
-
async function mergeMcpConfig(cwd, templateContent) {
|
|
468
|
-
const mcpPath = path.join(cwd, '.mcp.json');
|
|
469
|
-
const templateConfig = JSON.parse(templateContent);
|
|
470
|
-
if (await fs.pathExists(mcpPath)) {
|
|
471
|
-
const existingContent = await fs.readFile(mcpPath, 'utf-8');
|
|
472
|
-
const existingConfig = JSON.parse(existingContent);
|
|
473
|
-
// Merge: add our servers without overwriting existing ones
|
|
474
|
-
existingConfig.mcpServers = {
|
|
475
|
-
...existingConfig.mcpServers,
|
|
476
|
-
...templateConfig.mcpServers,
|
|
477
|
-
};
|
|
478
|
-
await fs.writeFile(mcpPath, JSON.stringify(existingConfig, null, 2) + '\n', 'utf-8');
|
|
479
|
-
}
|
|
480
|
-
else {
|
|
481
|
-
await fs.writeFile(mcpPath, templateContent, 'utf-8');
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
async function mergeClaudeSettings(cwd, templateContent) {
|
|
485
|
-
const settingsPath = path.join(cwd, '.claude/settings.json');
|
|
486
|
-
const templateConfig = JSON.parse(templateContent);
|
|
487
|
-
if (await fs.pathExists(settingsPath)) {
|
|
488
|
-
const existingContent = await fs.readFile(settingsPath, 'utf-8');
|
|
489
|
-
const existingConfig = JSON.parse(existingContent);
|
|
490
|
-
// Merge permissions: combine allow/deny lists, deduplicate
|
|
491
|
-
const existingAllow = existingConfig.permissions?.allow ?? [];
|
|
492
|
-
const existingDeny = existingConfig.permissions?.deny ?? [];
|
|
493
|
-
const templateAllow = templateConfig.permissions?.allow ?? [];
|
|
494
|
-
const templateDeny = templateConfig.permissions?.deny ?? [];
|
|
495
|
-
existingConfig.permissions = {
|
|
496
|
-
...existingConfig.permissions,
|
|
497
|
-
allow: [...new Set([...existingAllow, ...templateAllow])],
|
|
498
|
-
deny: [...new Set([...existingDeny, ...templateDeny])],
|
|
499
|
-
};
|
|
500
|
-
await fs.writeFile(settingsPath, JSON.stringify(existingConfig, null, 2) + '\n', 'utf-8');
|
|
501
|
-
}
|
|
502
|
-
else {
|
|
503
|
-
await fs.writeFile(settingsPath, templateContent, 'utf-8');
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
async function updateGitignore(cwd) {
|
|
507
|
-
const gitignorePath = path.join(cwd, '.gitignore');
|
|
508
|
-
let content = '';
|
|
509
|
-
if (await fs.pathExists(gitignorePath)) {
|
|
510
|
-
content = await fs.readFile(gitignorePath, 'utf-8');
|
|
511
|
-
}
|
|
512
|
-
const missingEntries = GITIGNORE_ENTRIES.filter(entry => !content.includes(entry));
|
|
513
|
-
if (missingEntries.length > 0) {
|
|
514
|
-
const suffix = content.endsWith('\n') || content === '' ? '' : '\n';
|
|
515
|
-
const section = missingEntries.length > 0
|
|
516
|
-
? `${suffix}\n# Melt - local settings\n${missingEntries.join('\n')}\n`
|
|
517
|
-
: '';
|
|
518
|
-
await fs.writeFile(gitignorePath, content + section, 'utf-8');
|
|
519
|
-
}
|
|
520
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|