@meltstudio/meltctl 4.7.4 → 4.9.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/README.md CHANGED
@@ -25,6 +25,9 @@ meltctl project init --claude --cursor # Both
25
25
  # Re-initialize
26
26
  meltctl project init --force
27
27
 
28
+ # Fetch latest templates (used by /melt-update)
29
+ meltctl project templates
30
+
28
31
  # Other commands
29
32
  meltctl logout
30
33
  meltctl version --check
@@ -34,8 +37,8 @@ meltctl version --check
34
37
 
35
38
  - `AGENTS.md` — AI agent instructions and project standards
36
39
  - `.claude/settings.json` — Claude Code permissions
37
- - `.claude/skills/melt-{setup,plan,review,pr,debug,audit}/SKILL.md` — Claude Code workflow skills
38
- - `.cursor/commands/melt-{setup,plan,review,pr,debug,audit}.md` — Cursor workflow commands
40
+ - `.claude/skills/melt-{setup,plan,...,update}/SKILL.md` — Claude Code workflow skills
41
+ - `.cursor/commands/melt-{setup,plan,...,update}.md` — Cursor workflow commands
39
42
  - `.mcp.json` — MCP server configuration (Chrome DevTools)
40
43
 
41
44
  ## Requirements
@@ -2,7 +2,8 @@ import chalk from 'chalk';
2
2
  import { checkbox, confirm } from '@inquirer/prompts';
3
3
  import fs from 'fs-extra';
4
4
  import path from 'path';
5
- import { authenticatedFetch, isAuthenticated } from '../utils/auth.js';
5
+ import { isAuthenticated } from '../utils/auth.js';
6
+ import { fetchTemplates } from '../utils/templates.js';
6
7
  const SKILL_FRONTMATTER = {
7
8
  setup: `---
8
9
  user-invocable: true
@@ -39,17 +40,15 @@ user-invocable: true
39
40
  description: Run a project compliance audit against team standards
40
41
  ---
41
42
 
43
+ `,
44
+ update: `---
45
+ user-invocable: true
46
+ description: Update Melt skills and standards to the latest version
47
+ ---
48
+
42
49
  `,
43
50
  };
44
51
  const GITIGNORE_ENTRIES = ['.env.local', '.claude/settings.local.json'];
45
- async function fetchTemplates() {
46
- const response = await authenticatedFetch('/templates');
47
- if (!response.ok) {
48
- throw new Error(`Failed to fetch templates: ${response.statusText}`);
49
- }
50
- const data = (await response.json());
51
- return data.files;
52
- }
53
52
  function detectExistingTools(cwd) {
54
53
  return {
55
54
  claude: fs.pathExistsSync(path.join(cwd, '.claude/settings.json')),
@@ -147,7 +146,7 @@ export async function initCommand(options) {
147
146
  console.log(chalk.bold('Initializing Melt development tools...'));
148
147
  console.log();
149
148
  const createdFiles = [];
150
- const workflows = ['setup', 'plan', 'review', 'pr', 'debug', 'audit'];
149
+ const workflows = ['setup', 'plan', 'review', 'pr', 'debug', 'audit', 'update'];
151
150
  // Shared files (skip on re-init)
152
151
  if (!isReInit) {
153
152
  const agentsMd = templates['agents-md.md'];
@@ -179,7 +178,7 @@ export async function initCommand(options) {
179
178
  await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
180
179
  }
181
180
  }
182
- createdFiles.push('.claude/skills/melt-{setup,plan,review,pr,debug,audit}/SKILL.md');
181
+ createdFiles.push('.claude/skills/melt-{setup,plan,review,pr,debug,audit,update}/SKILL.md');
183
182
  }
184
183
  // Cursor files
185
184
  if (tools.cursor) {
@@ -190,7 +189,7 @@ export async function initCommand(options) {
190
189
  await fs.writeFile(path.join(cwd, `.cursor/commands/melt-${name}.md`), workflowContent, 'utf-8');
191
190
  }
192
191
  }
193
- createdFiles.push('.cursor/commands/melt-{setup,plan,review,pr,debug,audit}.md');
192
+ createdFiles.push('.cursor/commands/melt-{setup,plan,review,pr,debug,audit,update}.md');
194
193
  }
195
194
  // Print summary
196
195
  console.log(chalk.green('Created files:'));
@@ -203,11 +202,11 @@ export async function initCommand(options) {
203
202
  console.log();
204
203
  }
205
204
  if (tools.claude) {
206
- const skills = '/melt-setup, /melt-plan, /melt-review, /melt-pr, /melt-debug, /melt-audit';
205
+ const skills = '/melt-setup, /melt-plan, /melt-review, /melt-pr, /melt-debug, /melt-audit, /melt-update';
207
206
  console.log(chalk.dim(`Available skills: ${skills}`));
208
207
  }
209
208
  if (tools.cursor) {
210
- console.log(chalk.dim('Available commands: melt-setup, melt-plan, melt-review, melt-pr, melt-debug, melt-audit'));
209
+ console.log(chalk.dim('Available commands: melt-setup, melt-plan, melt-review, melt-pr, melt-debug, melt-audit, melt-update'));
211
210
  }
212
211
  if (tools.claude || tools.cursor) {
213
212
  console.log();
@@ -0,0 +1 @@
1
+ export declare function templatesCommand(): Promise<void>;
@@ -0,0 +1,37 @@
1
+ import chalk from 'chalk';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import os from 'os';
5
+ import { isAuthenticated } from '../utils/auth.js';
6
+ import { fetchTemplates } from '../utils/templates.js';
7
+ export async function templatesCommand() {
8
+ if (!(await isAuthenticated())) {
9
+ console.error(chalk.red('Not authenticated. Run `npx @meltstudio/meltctl@latest login` first.'));
10
+ process.exit(1);
11
+ }
12
+ let templates;
13
+ try {
14
+ templates = await fetchTemplates();
15
+ }
16
+ catch (error) {
17
+ if (error instanceof Error && error.message.includes('expired')) {
18
+ console.error(chalk.red('Session expired. Run `npx @meltstudio/meltctl@latest login` to re-authenticate.'));
19
+ }
20
+ else if (error instanceof Error && error.message.includes('fetch')) {
21
+ console.error(chalk.red('Could not reach Melt API. Check your connection.'));
22
+ }
23
+ else {
24
+ console.error(chalk.red(`Failed to fetch templates: ${error instanceof Error ? error.message : 'Unknown error'}`));
25
+ }
26
+ process.exit(1);
27
+ }
28
+ const tmpDir = path.join(os.tmpdir(), `melt-templates-${Date.now()}`);
29
+ await fs.ensureDir(tmpDir);
30
+ for (const [filePath, content] of Object.entries(templates)) {
31
+ const fullPath = path.join(tmpDir, filePath);
32
+ await fs.ensureDir(path.dirname(fullPath));
33
+ await fs.writeFile(fullPath, content, 'utf-8');
34
+ }
35
+ // Print only the temp dir path to stdout (agent parses this)
36
+ console.log(tmpDir);
37
+ }
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import { readFileSync } from 'fs';
5
5
  import { join, dirname } from 'path';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { initCommand } from './commands/init.js';
8
+ import { templatesCommand } from './commands/templates.js';
8
9
  import { loginCommand } from './commands/login.js';
9
10
  import { logoutCommand } from './commands/logout.js';
10
11
  import { printBanner } from './utils/banner.js';
@@ -48,6 +49,12 @@ project
48
49
  .action(options => {
49
50
  return initCommand({ force: options.force, claude: options.claude, cursor: options.cursor });
50
51
  });
52
+ project
53
+ .command('templates')
54
+ .description('fetch latest templates to a temp directory (for /melt-update)')
55
+ .action(async () => {
56
+ await templatesCommand();
57
+ });
51
58
  program
52
59
  .command('version')
53
60
  .description('show current version')
@@ -0,0 +1,4 @@
1
+ export interface TemplateFiles {
2
+ [key: string]: string;
3
+ }
4
+ export declare function fetchTemplates(): Promise<TemplateFiles>;
@@ -0,0 +1,9 @@
1
+ import { authenticatedFetch } from './auth.js';
2
+ export async function fetchTemplates() {
3
+ const response = await authenticatedFetch('/templates');
4
+ if (!response.ok) {
5
+ throw new Error(`Failed to fetch templates: ${response.statusText}`);
6
+ }
7
+ const data = (await response.json());
8
+ return data.files;
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltstudio/meltctl",
3
- "version": "4.7.4",
3
+ "version": "4.9.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",