@meltstudio/meltctl 3.0.0 → 4.0.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.
@@ -1,9 +1,7 @@
1
1
  import chalk from 'chalk';
2
2
  import fs from 'fs-extra';
3
3
  import path from 'path';
4
- import { fileURLToPath } from 'url';
5
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
- const TEMPLATES_DIR = path.join(__dirname, '../../templates');
4
+ import { authenticatedFetch, isAuthenticated } from '../utils/auth.js';
7
5
  const SKILL_FRONTMATTER = {
8
6
  plan: `---
9
7
  user-invocable: true
@@ -31,6 +29,14 @@ description: Systematically investigate and fix bugs
31
29
  `,
32
30
  };
33
31
  const GITIGNORE_ENTRIES = ['.env.local', '.claude/settings.local.json'];
32
+ async function fetchTemplates() {
33
+ const response = await authenticatedFetch('/templates');
34
+ if (!response.ok) {
35
+ throw new Error(`Failed to fetch templates: ${response.statusText}`);
36
+ }
37
+ const data = (await response.json());
38
+ return data.files;
39
+ }
34
40
  export async function initCommand(options) {
35
41
  const cwd = process.cwd();
36
42
  // Check if already initialized (AGENTS.md exists)
@@ -38,34 +44,75 @@ export async function initCommand(options) {
38
44
  console.log(chalk.yellow('Project already has an AGENTS.md file. Use --force to overwrite.'));
39
45
  process.exit(1);
40
46
  }
47
+ // Require authentication
48
+ if (!(await isAuthenticated())) {
49
+ console.error(chalk.red('Not authenticated. Run `meltctl login` first.'));
50
+ process.exit(1);
51
+ }
52
+ let templates;
53
+ try {
54
+ templates = await fetchTemplates();
55
+ }
56
+ catch (error) {
57
+ if (error instanceof Error && error.message.includes('expired')) {
58
+ console.error(chalk.red('Session expired. Run `meltctl login` to re-authenticate.'));
59
+ }
60
+ else if (error instanceof Error && error.message.includes('fetch')) {
61
+ console.error(chalk.red('Could not reach Melt API. Check your connection.'));
62
+ }
63
+ else {
64
+ console.error(chalk.red(`Failed to fetch templates: ${error instanceof Error ? error.message : 'Unknown error'}`));
65
+ }
66
+ process.exit(1);
67
+ }
41
68
  console.log(chalk.bold('Initializing Melt development tools...'));
42
69
  console.log();
43
70
  // Copy AGENTS.md
44
- await fs.copyFile(path.join(TEMPLATES_DIR, 'agents-md.md'), path.join(cwd, 'AGENTS.md'));
71
+ const agentsMd = templates['agents-md.md'];
72
+ if (agentsMd) {
73
+ await fs.writeFile(path.join(cwd, 'AGENTS.md'), agentsMd, 'utf-8');
74
+ }
45
75
  // Copy .claude/settings.json
46
- await fs.ensureDir(path.join(cwd, '.claude'));
47
- await fs.copyFile(path.join(TEMPLATES_DIR, 'claude-settings.json'), path.join(cwd, '.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
+ }
48
81
  // Create Claude skills from workflow templates
49
82
  const workflows = ['plan', 'review', 'pr', 'debug'];
50
83
  for (const name of workflows) {
51
- const skillDir = path.join(cwd, `.claude/skills/melt-${name}`);
52
- await fs.ensureDir(skillDir);
53
- const workflowContent = await fs.readFile(path.join(TEMPLATES_DIR, `workflows/${name}.md`), 'utf-8');
54
- const skillContent = SKILL_FRONTMATTER[name] + workflowContent;
55
- await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
84
+ const workflowContent = templates[`workflows/${name}.md`];
85
+ if (workflowContent) {
86
+ const skillDir = path.join(cwd, `.claude/skills/melt-${name}`);
87
+ await fs.ensureDir(skillDir);
88
+ const skillContent = SKILL_FRONTMATTER[name] + workflowContent;
89
+ await fs.writeFile(path.join(skillDir, 'SKILL.md'), skillContent, 'utf-8');
90
+ }
56
91
  }
57
92
  // Copy .cursor/rules/standards.mdc
58
- await fs.ensureDir(path.join(cwd, '.cursor/rules'));
59
- await fs.copyFile(path.join(TEMPLATES_DIR, 'cursor-rules.mdc'), path.join(cwd, '.cursor/rules/standards.mdc'));
93
+ const cursorRules = templates['cursor-rules.mdc'];
94
+ if (cursorRules) {
95
+ await fs.ensureDir(path.join(cwd, '.cursor/rules'));
96
+ await fs.writeFile(path.join(cwd, '.cursor/rules/standards.mdc'), cursorRules, 'utf-8');
97
+ }
60
98
  // Copy Cursor commands from workflow templates
61
99
  await fs.ensureDir(path.join(cwd, '.cursor/commands'));
62
100
  for (const name of workflows) {
63
- await fs.copyFile(path.join(TEMPLATES_DIR, `workflows/${name}.md`), path.join(cwd, `.cursor/commands/melt-${name}.md`));
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');
104
+ }
64
105
  }
65
106
  // Copy .mcp.json
66
- await fs.copyFile(path.join(TEMPLATES_DIR, 'mcp-configs/base.json'), path.join(cwd, '.mcp.json'));
107
+ const mcpConfig = templates['mcp-configs/base.json'];
108
+ if (mcpConfig) {
109
+ await fs.writeFile(path.join(cwd, '.mcp.json'), mcpConfig, 'utf-8');
110
+ }
67
111
  // Copy .env.melt.example
68
- await fs.copyFile(path.join(TEMPLATES_DIR, 'env-melt-example'), path.join(cwd, '.env.melt.example'));
112
+ const envExample = templates['env-melt-example'];
113
+ if (envExample) {
114
+ await fs.writeFile(path.join(cwd, '.env.melt.example'), envExample, 'utf-8');
115
+ }
69
116
  // Update .gitignore
70
117
  await updateGitignore(cwd);
71
118
  // Print summary
@@ -0,0 +1 @@
1
+ export declare function loginCommand(): Promise<void>;
@@ -0,0 +1,90 @@
1
+ import chalk from 'chalk';
2
+ import http from 'http';
3
+ import { URL } from 'url';
4
+ import { exec } from 'child_process';
5
+ import { API_BASE, storeAuth } from '../utils/auth.js';
6
+ import { printBanner } from '../utils/banner.js';
7
+ const LOGIN_TIMEOUT_MS = 60_000;
8
+ function openBrowser(url) {
9
+ const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
10
+ exec(`${command} "${url}"`);
11
+ }
12
+ function findFreePort() {
13
+ return new Promise((resolve, reject) => {
14
+ const server = http.createServer();
15
+ server.listen(0, () => {
16
+ const address = server.address();
17
+ if (address && typeof address === 'object') {
18
+ const port = address.port;
19
+ server.close(() => resolve(port));
20
+ }
21
+ else {
22
+ reject(new Error('Could not find free port'));
23
+ }
24
+ });
25
+ });
26
+ }
27
+ export async function loginCommand() {
28
+ printBanner();
29
+ console.log(chalk.bold(' Logging in to Melt...'));
30
+ const port = await findFreePort();
31
+ const redirectUri = `http://localhost:${port.toString()}`;
32
+ const authCode = await new Promise((resolve, reject) => {
33
+ const timeout = setTimeout(() => {
34
+ server.close();
35
+ reject(new Error('Authentication timed out. Please try again.'));
36
+ }, LOGIN_TIMEOUT_MS);
37
+ const server = http.createServer((req, res) => {
38
+ const url = new URL(req.url ?? '/', `http://localhost:${port.toString()}`);
39
+ const code = url.searchParams.get('code');
40
+ const error = url.searchParams.get('error');
41
+ if (error) {
42
+ res.writeHead(200, { 'Content-Type': 'text/html' });
43
+ res.end('<html><body><h2>Authentication failed</h2><p>You can close this tab.</p></body></html>');
44
+ clearTimeout(timeout);
45
+ server.close();
46
+ reject(new Error(`Authentication denied: ${error}`));
47
+ return;
48
+ }
49
+ if (!code) {
50
+ res.writeHead(400, { 'Content-Type': 'text/html' });
51
+ res.end('<html><body><h2>Missing authorization code</h2></body></html>');
52
+ return;
53
+ }
54
+ res.writeHead(200, { 'Content-Type': 'text/html' });
55
+ res.end('<html><body><h2>Authentication successful!</h2><p>You can close this tab and return to your terminal.</p></body></html>');
56
+ clearTimeout(timeout);
57
+ server.close();
58
+ resolve(code);
59
+ });
60
+ server.listen(port, () => {
61
+ const authUrl = `${API_BASE}/auth/google?redirect_uri=${encodeURIComponent(redirectUri)}`;
62
+ console.log(chalk.dim('Opening browser for authentication...'));
63
+ openBrowser(authUrl);
64
+ console.log(chalk.dim(`If the browser doesn't open, visit: ${authUrl}`));
65
+ });
66
+ });
67
+ console.log(chalk.dim('Exchanging authorization code...'));
68
+ const response = await fetch(`${API_BASE}/auth/token`, {
69
+ method: 'POST',
70
+ headers: { 'Content-Type': 'application/json' },
71
+ body: JSON.stringify({ code: authCode, redirect_uri: redirectUri }),
72
+ });
73
+ if (!response.ok) {
74
+ const error = (await response.json());
75
+ if (response.status === 403) {
76
+ console.error(chalk.red('Only @meltstudio.co accounts can use this tool.'));
77
+ process.exit(1);
78
+ }
79
+ console.error(chalk.red(`Authentication failed: ${error.error ?? 'Unknown error'}`));
80
+ process.exit(1);
81
+ }
82
+ const data = (await response.json());
83
+ await storeAuth({
84
+ token: data.token,
85
+ email: data.email,
86
+ expiresAt: data.expiresAt,
87
+ });
88
+ console.log();
89
+ console.log(chalk.green(`Logged in as ${data.email}`));
90
+ }
@@ -0,0 +1 @@
1
+ export declare function logoutCommand(): Promise<void>;
@@ -0,0 +1,12 @@
1
+ import chalk from 'chalk';
2
+ import { clearAuth, getStoredAuth } from '../utils/auth.js';
3
+ export async function logoutCommand() {
4
+ const auth = await getStoredAuth();
5
+ await clearAuth();
6
+ if (auth) {
7
+ console.log(chalk.green(`Logged out (was ${auth.email})`));
8
+ }
9
+ else {
10
+ console.log(chalk.dim('No active session found.'));
11
+ }
12
+ }
package/dist/index.js CHANGED
@@ -4,6 +4,9 @@ import { readFileSync } from 'fs';
4
4
  import { join, dirname } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { initCommand } from './commands/init.js';
7
+ import { loginCommand } from './commands/login.js';
8
+ import { logoutCommand } from './commands/logout.js';
9
+ import { printBanner } from './utils/banner.js';
7
10
  import { checkAndEnforceUpdate } from './utils/version-check.js';
8
11
  import { versionCheckCommand } from './commands/version.js';
9
12
  // Read version from package.json
@@ -13,22 +16,39 @@ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'),
13
16
  const program = new Command();
14
17
  program
15
18
  .name('meltctl')
16
- .description('AI-first development tools for teams')
19
+ .description('Set up AI-first development standards (AGENTS.md, Claude skills, Cursor rules, MCP config) in your project.\n\nRequires a @meltstudio.co Google Workspace account. Run `meltctl login` first, then `meltctl project init` in your repo.')
17
20
  .version(packageJson.version)
21
+ .addHelpText('beforeAll', () => {
22
+ printBanner();
23
+ return '';
24
+ })
18
25
  .hook('preAction', async () => {
19
26
  await checkAndEnforceUpdate();
20
27
  });
21
28
  program
29
+ .command('login')
30
+ .description('authenticate with Google Workspace (opens browser)')
31
+ .action(async () => {
32
+ await loginCommand();
33
+ });
34
+ program
35
+ .command('logout')
36
+ .description('clear stored credentials from ~/.meltctl/')
37
+ .action(async () => {
38
+ await logoutCommand();
39
+ });
40
+ const project = program.command('project').description('manage project configuration');
41
+ project
22
42
  .command('init')
23
- .description('Initialize project with Melt development tools')
24
- .option('--force', 'overwrite existing files')
43
+ .description('scaffold Melt development tools into the current directory (AGENTS.md, .claude/, .cursor/, .mcp.json)')
44
+ .option('--force', 'overwrite existing files if already initialized')
25
45
  .action(options => {
26
46
  return initCommand({ force: options.force });
27
47
  });
28
48
  program
29
49
  .command('version')
30
- .description('Display version information')
31
- .option('--check', 'check for updates')
50
+ .description('show current version')
51
+ .option('--check', 'also check for available updates')
32
52
  .action(async (options) => {
33
53
  if (options.check) {
34
54
  await versionCheckCommand();
@@ -0,0 +1,12 @@
1
+ export declare const API_BASE: string;
2
+ interface StoredAuth {
3
+ token: string;
4
+ email: string;
5
+ expiresAt: string;
6
+ }
7
+ export declare function getStoredAuth(): Promise<StoredAuth | undefined>;
8
+ export declare function storeAuth(auth: StoredAuth): Promise<void>;
9
+ export declare function clearAuth(): Promise<void>;
10
+ export declare function isAuthenticated(): Promise<boolean>;
11
+ export declare function authenticatedFetch(urlPath: string): Promise<Response>;
12
+ export {};
@@ -0,0 +1,52 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ const AUTH_DIR = path.join(os.homedir(), '.meltctl');
5
+ const AUTH_FILE = path.join(AUTH_DIR, 'auth.json');
6
+ export const API_BASE = process.env['MELTCTL_API_URL'] ??
7
+ 'https://ewszkw32he2ebgkwlbwmoubf5y0hllpx.lambda-url.us-east-1.on.aws';
8
+ export async function getStoredAuth() {
9
+ if (!(await fs.pathExists(AUTH_FILE))) {
10
+ return undefined;
11
+ }
12
+ try {
13
+ return (await fs.readJson(AUTH_FILE));
14
+ }
15
+ catch {
16
+ return undefined;
17
+ }
18
+ }
19
+ export async function storeAuth(auth) {
20
+ await fs.ensureDir(AUTH_DIR);
21
+ await fs.writeJson(AUTH_FILE, auth, { spaces: 2 });
22
+ }
23
+ export async function clearAuth() {
24
+ if (await fs.pathExists(AUTH_FILE)) {
25
+ await fs.remove(AUTH_FILE);
26
+ }
27
+ }
28
+ export async function isAuthenticated() {
29
+ const auth = await getStoredAuth();
30
+ if (!auth) {
31
+ return false;
32
+ }
33
+ return new Date(auth.expiresAt) > new Date();
34
+ }
35
+ export async function authenticatedFetch(urlPath) {
36
+ const auth = await getStoredAuth();
37
+ if (!auth) {
38
+ throw new Error('Not authenticated. Run `meltctl login` first.');
39
+ }
40
+ if (new Date(auth.expiresAt) <= new Date()) {
41
+ throw new Error('Session expired. Run `meltctl login` to re-authenticate.');
42
+ }
43
+ const response = await fetch(`${API_BASE}${urlPath}`, {
44
+ headers: {
45
+ Authorization: `Bearer ${auth.token}`,
46
+ },
47
+ });
48
+ if (response.status === 401) {
49
+ throw new Error('Session expired. Run `meltctl login` to re-authenticate.');
50
+ }
51
+ return response;
52
+ }
@@ -0,0 +1 @@
1
+ export declare function printBanner(): void;
@@ -0,0 +1,22 @@
1
+ import chalk from 'chalk';
2
+ import gradient from 'gradient-string';
3
+ import { readFileSync } from 'fs';
4
+ import { join, dirname } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const pkg = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
8
+ // Melt brand colors: yellow, magenta/pink, cyan, red, orange
9
+ const meltGradient = gradient(['#FFC107', '#E91E63', '#00BCD4', '#FF5722']);
10
+ const LOGO = `
11
+ ███╗ ███╗███████╗██╗ ████████╗ ██████╗████████╗██╗
12
+ ████╗ ████║██╔════╝██║ ╚══██╔══╝██╔════╝╚══██╔══╝██║
13
+ ██╔████╔██║█████╗ ██║ ██║ ██║ ██║ ██║
14
+ ██║╚██╔╝██║██╔══╝ ██║ ██║ ██║ ██║ ██║
15
+ ██║ ╚═╝ ██║███████╗███████╗██║ ╚██████╗ ██║ ███████╗
16
+ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚══════╝`;
17
+ export function printBanner() {
18
+ console.log(meltGradient(LOGO));
19
+ console.log();
20
+ console.log(` ${chalk.dim('v' + pkg.version)} ${chalk.dim('·')} ${chalk.dim('AI-first development tools for teams')}`);
21
+ console.log();
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meltstudio/meltctl",
3
- "version": "3.0.0",
3
+ "version": "4.0.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",
@@ -9,7 +9,6 @@
9
9
  },
10
10
  "files": [
11
11
  "dist/**/*",
12
- "templates/**/*",
13
12
  "README.md",
14
13
  "LICENSE"
15
14
  ],
@@ -48,10 +47,11 @@
48
47
  "author": "Melt Studio",
49
48
  "license": "MIT",
50
49
  "dependencies": {
51
- "commander": "^12.1.0",
52
50
  "@commander-js/extra-typings": "^12.1.0",
53
51
  "chalk": "^5.4.1",
54
- "fs-extra": "^11.2.0"
52
+ "commander": "^12.1.0",
53
+ "fs-extra": "^11.2.0",
54
+ "gradient-string": "^3.0.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@types/fs-extra": "^11.0.4",
@@ -1,117 +0,0 @@
1
- # AGENTS.md
2
-
3
- ## Project Overview
4
-
5
- <!-- Describe your project here: what it does, key technologies, and architecture overview -->
6
-
7
- ## Architecture Standards
8
-
9
- ### Important: Respect Existing Code
10
-
11
- Before applying any standards below, **understand the existing project structure first**. If the project already follows a different architecture or pattern, continue following the existing conventions. These standards apply to new code in greenfield areas - never refactor or restructure existing code to match these guidelines unless explicitly asked.
12
-
13
- ### Recommended Structure (for new projects/domains)
14
-
15
- For new frontend code, prefer domain-driven architecture:
16
-
17
- ```
18
- src/
19
- domains/
20
- <domain>/
21
- components/ # UI components scoped to this domain
22
- hooks/ # Custom hooks for this domain
23
- services/ # API calls and business logic
24
- types/ # TypeScript types and interfaces
25
- utils/ # Domain-specific utilities
26
- shared/
27
- components/ # Shared UI components
28
- hooks/ # Shared custom hooks
29
- services/ # Shared API services
30
- types/ # Shared TypeScript types
31
- utils/ # Shared utilities
32
- ```
33
-
34
- - Each domain is self-contained with its own components, hooks, services, types, and utils
35
- - Cross-domain imports go through the `shared/` directory
36
- - Never import directly between domains
37
-
38
- If the project uses a different structure, follow the existing patterns instead.
39
-
40
- ### TypeScript Standards
41
- - Strict mode enabled (`strict: true` in tsconfig)
42
- - No `any` types - use `unknown` with type guards when the type is truly unknown
43
- - Validate external data with Zod schemas at system boundaries
44
- - Export types from dedicated `types.ts` files
45
-
46
- ### Code Quality
47
- - Minimum 80% test coverage for new code
48
- - Use conventional commits (feat:, fix:, chore:, docs:, refactor:, test:)
49
- - No eslint-disable comments without team approval
50
- - All functions must have explicit return types
51
- - Prefer composition over inheritance
52
-
53
- ## Agent Permissions
54
-
55
- ### Automatically Approved (No Confirmation Needed)
56
- - Reading any file in the repository
57
- - Running tests, linters, type checkers, and formatters
58
- - Git read operations (status, log, diff, branch)
59
- - Searching code and exploring the codebase
60
- - Package dependency lookups
61
-
62
- ### Requires Approval
63
- - Writing or modifying files
64
- - Git write operations (add, commit, checkout, branch creation)
65
- - Running build commands
66
- - Installing or removing dependencies
67
- - Creating pull requests or issues
68
-
69
- ### Blocked (Never Execute)
70
- - `git push --force` or `git push --force-with-lease`
71
- - `git reset --hard`
72
- - `rm -rf /` or any recursive delete of root paths
73
- - Force push to main or master branches
74
- - Dropping database tables in production
75
- - Modifying CI/CD pipeline files without explicit request
76
-
77
- ## Tool Access
78
-
79
- ### CLI Tools
80
- - Use `gh` CLI for GitHub operations (PRs, issues, releases)
81
- - Use project's package manager (check for yarn.lock, pnpm-lock.yaml, or package-lock.json)
82
- - Run tests with the project's configured test runner
83
-
84
- ### Browser (via DevTools MCP)
85
- - Use Chrome DevTools MCP server for browser testing when available
86
- - Inspect elements, check console errors, verify visual output
87
- - Test responsive layouts and interactions
88
-
89
- ### Databases
90
- - Read queries are safe to execute
91
- - Write queries require approval
92
- - Schema changes require explicit request and approval
93
-
94
- ## Project Management
95
-
96
- - Reference issue/ticket IDs in commit messages and PR descriptions
97
- - Follow the team's workflow for issue progression
98
- - Update ticket status when starting and completing work
99
-
100
- ## Workflow Skills
101
-
102
- The following workflows are available as AI skills:
103
-
104
- - **plan** - Gather requirements, explore codebase, design approach, present plan for approval
105
- - **review** - Review changes against these standards, categorize findings
106
- - **pr** - Analyze changes, draft PR description, run pre-flight checks, create PR
107
- - **debug** - Investigate issues, isolate root cause, write regression test, fix
108
-
109
- ## Customization
110
-
111
- <!-- Add project-specific standards below this line -->
112
- <!-- Examples of things to add: -->
113
- <!-- - API conventions (REST patterns, error formats, pagination) -->
114
- <!-- - Component patterns (naming, file structure, state management) -->
115
- <!-- - Database rules (naming conventions, migration patterns) -->
116
- <!-- - Testing patterns (what to mock, integration test setup) -->
117
- <!-- - Deployment rules (environment-specific concerns) -->
@@ -1,36 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(git status*)",
5
- "Bash(git log*)",
6
- "Bash(git diff*)",
7
- "Bash(git branch*)",
8
- "Bash(git show*)",
9
- "Bash(npm test*)",
10
- "Bash(yarn test*)",
11
- "Bash(pnpm test*)",
12
- "Bash(npx vitest*)",
13
- "Bash(npx jest*)",
14
- "Bash(npm run lint*)",
15
- "Bash(yarn lint*)",
16
- "Bash(pnpm lint*)",
17
- "Bash(npm run build*)",
18
- "Bash(yarn build*)",
19
- "Bash(pnpm build*)",
20
- "Bash(npx tsc*)",
21
- "Bash(gh pr *)",
22
- "Bash(gh issue *)",
23
- "Read(*)"
24
- ],
25
- "deny": [
26
- "Bash(git push --force*)",
27
- "Bash(git push * --force*)",
28
- "Bash(git push --force-with-lease*)",
29
- "Bash(git push * --force-with-lease*)",
30
- "Bash(git reset --hard*)",
31
- "Bash(rm -rf /*)",
32
- "Bash(git push * main*)",
33
- "Bash(git push * master*)"
34
- ]
35
- }
36
- }
@@ -1,39 +0,0 @@
1
- ---
2
- description: Melt development standards and architecture guidelines
3
- globs:
4
- alwaysApply: true
5
- ---
6
-
7
- # Project Standards
8
-
9
- ## Important
10
- - Always understand the existing project structure before making changes
11
- - If the project follows different conventions than listed here, follow the existing patterns
12
- - These standards apply to new greenfield code - never refactor existing code to match unless asked
13
-
14
- ## Architecture
15
- - Prefer domain-driven architecture for new code: `src/domains/<domain>/{components,hooks,services,types,utils}`
16
- - Cross-domain imports go through `src/shared/`
17
- - Never import directly between domains
18
- - Follow existing project patterns when they differ from the above
19
-
20
- ## TypeScript
21
- - Strict mode enabled, no `any` types
22
- - Validate external data with Zod at system boundaries
23
- - All functions must have explicit return types
24
-
25
- ## Code Quality
26
- - 80% minimum test coverage for new code
27
- - Conventional commits (feat:, fix:, chore:, docs:, refactor:, test:)
28
- - No eslint-disable comments without team approval
29
-
30
- ## Agent Behavior
31
- - Read operations: auto-approved
32
- - Write operations: require developer approval
33
- - Destructive operations: blocked (no force push, no hard reset)
34
-
35
- ## Workflows
36
- - Use `plan` before starting non-trivial implementations
37
- - Use `review` to check changes against these standards
38
- - Use `pr` to create well-structured pull requests
39
- - Use `debug` for systematic bug investigation
@@ -1,23 +0,0 @@
1
- # Melt Development Tools - Environment Variables
2
- # Copy this file to .env.local and fill in your values
3
- # Never commit .env.local to version control
4
-
5
- # --- Linear (if using Linear for project management) ---
6
- # LINEAR_API_KEY=lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
7
-
8
- # --- Jira (if using Jira for project management) ---
9
- # JIRA_API_TOKEN=your-jira-api-token
10
- # JIRA_BASE_URL=https://your-org.atlassian.net
11
- # JIRA_USER_EMAIL=your-email@company.com
12
-
13
- # --- Database (if agents need database access) ---
14
- # DATABASE_URL=postgresql://user:password@localhost:5432/dbname
15
-
16
- # --- AWS (if agents need AWS access) ---
17
- # AWS_ACCESS_KEY_ID=your-access-key
18
- # AWS_SECRET_ACCESS_KEY=your-secret-key
19
- # AWS_REGION=us-east-1
20
-
21
- # --- Other Integrations ---
22
- # OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
23
- # ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
@@ -1,8 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "chrome-devtools": {
4
- "command": "npx",
5
- "args": ["-y", "@anthropic-ai/chrome-devtools-mcp@latest"]
6
- }
7
- }
8
- }
@@ -1,32 +0,0 @@
1
- # Debug
2
-
3
- Investigate and fix bugs systematically.
4
-
5
- ## Instructions
6
-
7
- 1. **Understand the Problem**
8
- - Read the bug report or error description
9
- - Reproduce the issue if possible
10
- - Identify expected vs actual behavior
11
-
12
- 2. **Investigate**
13
- - Search the codebase for relevant code paths
14
- - Read error messages and stack traces carefully
15
- - Use browser DevTools MCP if it's a UI issue
16
- - Check recent changes that might have introduced the bug
17
- - Add temporary logging if needed to trace execution
18
-
19
- 3. **Isolate the Root Cause**
20
- - Narrow down to the specific file and function
21
- - Understand why the current code produces the wrong behavior
22
- - Verify your hypothesis by checking related code paths
23
-
24
- 4. **Write a Regression Test**
25
- - Write a test that reproduces the bug (it should fail before the fix)
26
- - Cover the specific edge case that caused the issue
27
-
28
- 5. **Fix the Bug**
29
- - Make the minimal change needed to fix the issue
30
- - Verify the regression test now passes
31
- - Run the full test suite to check for regressions
32
- - Clean up any temporary debugging code
@@ -1,32 +0,0 @@
1
- # Plan
2
-
3
- Design an implementation approach before writing code.
4
-
5
- ## Instructions
6
-
7
- 1. **Gather Requirements**
8
- - Read the task description carefully
9
- - Identify acceptance criteria and constraints
10
- - Ask clarifying questions if requirements are ambiguous
11
-
12
- 2. **Explore the Codebase**
13
- - Find relevant files and understand existing patterns
14
- - Check for similar implementations to follow as examples
15
- - Identify files that will need changes
16
-
17
- 3. **Design the Approach**
18
- - Break the task into concrete implementation steps
19
- - Consider edge cases and error handling
20
- - Note any dependencies or ordering constraints
21
- - Estimate which files will be created or modified
22
-
23
- 4. **Present the Plan**
24
- - Summarize the approach in a clear, numbered list
25
- - Highlight any architectural decisions or trade-offs
26
- - List files to be modified with a brief description of changes
27
- - Call out any risks or open questions
28
-
29
- 5. **Wait for Approval**
30
- - Do not start implementation until the developer approves
31
- - Adjust the plan based on feedback
32
- - Once approved, proceed with implementation
@@ -1,28 +0,0 @@
1
- # Pull Request
2
-
3
- Create a well-structured pull request from the current changes.
4
-
5
- ## Instructions
6
-
7
- 1. **Analyze Changes**
8
- - Run `git diff` to understand all changes
9
- - Run `git log` to review commit history on this branch
10
- - Identify the purpose and scope of the changes
11
-
12
- 2. **Draft PR Description**
13
- - Write a clear title (under 70 characters)
14
- - Summarize changes in 1-3 bullet points
15
- - Reference related issues or tickets
16
- - Note any breaking changes or migration steps
17
-
18
- 3. **Run Pre-flight Checks**
19
- - Run the test suite and verify all tests pass
20
- - Run the linter and fix any issues
21
- - Run type checking and resolve any errors
22
- - Verify the build succeeds
23
-
24
- 4. **Create the PR**
25
- - Use `gh pr create` with the drafted title and description
26
- - Add appropriate labels if the project uses them
27
- - Request reviewers if specified
28
- - Return the PR URL to the developer
@@ -1,28 +0,0 @@
1
- # Review
2
-
3
- Review code changes against project standards.
4
-
5
- ## Instructions
6
-
7
- 1. **Understand Context**
8
- - Read the PR description or task context
9
- - Understand what the changes are trying to accomplish
10
- - Check AGENTS.md for project-specific standards
11
-
12
- 2. **Review the Changes**
13
- - Read all modified files carefully
14
- - Check for correctness, readability, and maintainability
15
- - Verify adherence to architecture standards (domain structure, typing, etc.)
16
- - Look for potential bugs, edge cases, or security issues
17
- - Check that tests cover the changes adequately
18
-
19
- 3. **Categorize Findings**
20
- - **Must Fix**: Bugs, security issues, broken functionality, standards violations
21
- - **Should Fix**: Code quality issues, missing tests, unclear naming
22
- - **Suggestion**: Style preferences, optional improvements, alternative approaches
23
-
24
- 4. **Present the Review**
25
- - Start with a summary of what the changes do
26
- - List findings by category with file paths and line numbers
27
- - Provide specific suggestions for how to fix each issue
28
- - End with an overall assessment (approve, request changes, or needs discussion)