myaidev-method 0.0.7 ā 0.1.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/.claude/CLAUDE.md +52 -0
- package/.claude/agents/content-writer.md +155 -0
- package/.claude/commands/myai-configure.md +44 -0
- package/.claude/commands/myai-content-writer.md +78 -0
- package/.claude/commands/myai-wordpress-publish.md +120 -0
- package/.claude/mcp/gutenberg-converter.js +447 -0
- package/.claude/mcp/mcp-config.json +101 -0
- package/.claude/mcp/wordpress-server-simple.js +182 -0
- package/.claude/mcp/wordpress-server.js +1277 -0
- package/.claude/settings.local.json +12 -0
- package/COOLIFY_DEPLOYMENT.md +750 -0
- package/README.md +6 -6
- package/WORDPRESS_ADMIN_SCRIPTS.md +474 -0
- package/bin/cli.js +17 -22
- package/dist/mcp/gutenberg-converter.js +447 -0
- package/dist/mcp/mcp-config.json +101 -0
- package/dist/mcp/wordpress-server-simple.js +182 -0
- package/dist/mcp/wordpress-server.js +1277 -0
- package/package.json +29 -5
- package/src/lib/coolify-utils.js +380 -0
- package/src/lib/report-synthesizer.js +504 -0
- package/src/lib/wordpress-admin-utils.js +703 -0
- package/src/mcp/health-check.js +190 -0
- package/src/mcp/mcp-launcher.js +237 -0
- package/src/scripts/coolify-deploy-app.js +287 -0
- package/src/scripts/coolify-list-resources.js +199 -0
- package/src/scripts/coolify-status.js +97 -0
- package/src/scripts/test-coolify-deploy.js +47 -0
- package/src/scripts/wordpress-comprehensive-report.js +325 -0
- package/src/scripts/wordpress-health-check.js +175 -0
- package/src/scripts/wordpress-performance-check.js +461 -0
- package/src/scripts/wordpress-security-scan.js +221 -0
- package/src/templates/claude/agents/coolify-deploy.md +563 -0
- package/src/templates/claude/agents/wordpress-admin.md +228 -271
- package/src/templates/claude/commands/myai-configure.md +10 -74
- package/src/templates/claude/commands/myai-coolify-deploy.md +172 -0
- package/src/templates/claude/commands/myai-wordpress-publish.md +16 -8
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP Server Health Check Script
|
|
5
|
+
* Validates MCP server configuration and connectivity
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import { promises as fs } from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
|
|
15
|
+
export default async function healthCheck() {
|
|
16
|
+
console.log('š MyAIDev Method MCP Server Health Check');
|
|
17
|
+
console.log('==========================================\n');
|
|
18
|
+
|
|
19
|
+
const checks = [];
|
|
20
|
+
|
|
21
|
+
// Check 1: Environment variables
|
|
22
|
+
console.log('š Checking environment configuration...');
|
|
23
|
+
const envChecks = {
|
|
24
|
+
'WORDPRESS_URL': process.env.WORDPRESS_URL,
|
|
25
|
+
'WORDPRESS_USERNAME': process.env.WORDPRESS_USERNAME,
|
|
26
|
+
'WORDPRESS_APP_PASSWORD': process.env.WORDPRESS_APP_PASSWORD
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let envConfigured = true;
|
|
30
|
+
Object.entries(envChecks).forEach(([key, value]) => {
|
|
31
|
+
if (value) {
|
|
32
|
+
console.log(` ā
${key}: configured`);
|
|
33
|
+
} else {
|
|
34
|
+
console.log(` ā ${key}: missing`);
|
|
35
|
+
envConfigured = false;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
checks.push({
|
|
40
|
+
name: 'Environment Configuration',
|
|
41
|
+
status: envConfigured ? 'passed' : 'failed'
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Check 2: MCP server files
|
|
45
|
+
console.log('\nš Checking MCP server files...');
|
|
46
|
+
const mcpServerPath = path.resolve(__dirname, '../../.claude/mcp/wordpress-server.js');
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
await fs.access(mcpServerPath);
|
|
50
|
+
console.log(' ā
WordPress MCP server file exists');
|
|
51
|
+
checks.push({
|
|
52
|
+
name: 'MCP Server Files',
|
|
53
|
+
status: 'passed'
|
|
54
|
+
});
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.log(' ā WordPress MCP server file missing');
|
|
57
|
+
checks.push({
|
|
58
|
+
name: 'MCP Server Files',
|
|
59
|
+
status: 'failed'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check 3: Dependencies
|
|
64
|
+
console.log('\nš¦ Checking dependencies...');
|
|
65
|
+
const requiredDeps = [
|
|
66
|
+
{ name: '@modelcontextprotocol/sdk', path: '@modelcontextprotocol/sdk/server/mcp.js' },
|
|
67
|
+
{ name: 'node-fetch', path: 'node-fetch' },
|
|
68
|
+
{ name: 'dotenv', path: 'dotenv' },
|
|
69
|
+
{ name: 'zod', path: 'zod' }
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
let depsInstalled = true;
|
|
73
|
+
for (const dep of requiredDeps) {
|
|
74
|
+
try {
|
|
75
|
+
await import(dep.path);
|
|
76
|
+
console.log(` ā
${dep.name}: installed`);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.log(` ā ${dep.name}: missing or failed to import`);
|
|
79
|
+
depsInstalled = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
checks.push({
|
|
84
|
+
name: 'Dependencies',
|
|
85
|
+
status: depsInstalled ? 'passed' : 'failed'
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Check 4: MCP server startup test
|
|
89
|
+
if (envConfigured && depsInstalled) {
|
|
90
|
+
console.log('\nš Testing MCP server startup...');
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const startupTest = await testServerStartup(mcpServerPath);
|
|
94
|
+
console.log(` ā
MCP server starts successfully`);
|
|
95
|
+
checks.push({
|
|
96
|
+
name: 'MCP Server Startup',
|
|
97
|
+
status: 'passed'
|
|
98
|
+
});
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.log(` ā MCP server startup failed: ${error.message}`);
|
|
101
|
+
checks.push({
|
|
102
|
+
name: 'MCP Server Startup',
|
|
103
|
+
status: 'failed'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
console.log('\nāļø Skipping MCP server startup test (dependencies not met)');
|
|
108
|
+
checks.push({
|
|
109
|
+
name: 'MCP Server Startup',
|
|
110
|
+
status: 'skipped'
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Summary
|
|
115
|
+
console.log('\nš Health Check Summary:');
|
|
116
|
+
const passed = checks.filter(c => c.status === 'passed').length;
|
|
117
|
+
const failed = checks.filter(c => c.status === 'failed').length;
|
|
118
|
+
const skipped = checks.filter(c => c.status === 'skipped').length;
|
|
119
|
+
|
|
120
|
+
checks.forEach(check => {
|
|
121
|
+
const icon = check.status === 'passed' ? 'ā
' :
|
|
122
|
+
check.status === 'failed' ? 'ā' : 'āļø';
|
|
123
|
+
console.log(` ${icon} ${check.name}: ${check.status}`);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
console.log(`\nResult: ${passed} passed, ${failed} failed, ${skipped} skipped`);
|
|
127
|
+
|
|
128
|
+
if (failed === 0) {
|
|
129
|
+
console.log('\nš All checks passed! MCP server is ready to use.');
|
|
130
|
+
console.log('\nš” Next steps:');
|
|
131
|
+
console.log(' ⢠Run: npm run mcp:start');
|
|
132
|
+
console.log(' ⢠Or use: /myai-wordpress-publish "your-file.md"');
|
|
133
|
+
} else {
|
|
134
|
+
console.log('\nā ļø Some checks failed. Please address the issues above.');
|
|
135
|
+
console.log('\nš” Common solutions:');
|
|
136
|
+
console.log(' ⢠Set environment variables: /myai-configure wordpress');
|
|
137
|
+
console.log(' ⢠Install dependencies: npm install');
|
|
138
|
+
console.log(' ⢠Check file permissions and paths');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
passed,
|
|
143
|
+
failed,
|
|
144
|
+
skipped,
|
|
145
|
+
checks,
|
|
146
|
+
overall: failed === 0 ? 'healthy' : 'unhealthy'
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function testServerStartup(serverPath) {
|
|
151
|
+
return new Promise((resolve, reject) => {
|
|
152
|
+
const serverProcess = spawn('node', [serverPath], {
|
|
153
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
154
|
+
env: process.env
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
let startupOutput = '';
|
|
158
|
+
const timeout = setTimeout(() => {
|
|
159
|
+
serverProcess.kill();
|
|
160
|
+
reject(new Error('Server startup timeout'));
|
|
161
|
+
}, 5000);
|
|
162
|
+
|
|
163
|
+
serverProcess.stderr.on('data', (data) => {
|
|
164
|
+
startupOutput += data.toString();
|
|
165
|
+
if (startupOutput.includes('Enhanced WordPress MCP Server') ||
|
|
166
|
+
startupOutput.includes('running')) {
|
|
167
|
+
clearTimeout(timeout);
|
|
168
|
+
serverProcess.kill();
|
|
169
|
+
resolve(true);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
serverProcess.on('error', (error) => {
|
|
174
|
+
clearTimeout(timeout);
|
|
175
|
+
reject(error);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
serverProcess.on('exit', (code) => {
|
|
179
|
+
clearTimeout(timeout);
|
|
180
|
+
if (code !== 0 && code !== null) {
|
|
181
|
+
reject(new Error(`Server exited with code ${code}`));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Run if called directly
|
|
188
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
189
|
+
healthCheck().catch(console.error);
|
|
190
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MCP Server Launcher Script
|
|
5
|
+
* Manages MCP server lifecycle with proper error handling and configuration
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
import { promises as fs } from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
|
|
15
|
+
class MCPLauncher {
|
|
16
|
+
constructor() {
|
|
17
|
+
this.serverProcess = null;
|
|
18
|
+
this.serverPath = path.resolve(__dirname, '../../.claude/mcp/wordpress-server.js');
|
|
19
|
+
this.isShuttingDown = false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
log(message, level = 'info') {
|
|
23
|
+
const timestamp = new Date().toISOString();
|
|
24
|
+
const prefix = {
|
|
25
|
+
info: 'š§',
|
|
26
|
+
success: 'ā
',
|
|
27
|
+
error: 'ā',
|
|
28
|
+
warn: 'ā ļø'
|
|
29
|
+
}[level] || 'ā¹ļø';
|
|
30
|
+
|
|
31
|
+
console.log(`[${timestamp}] ${prefix} ${message}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async validateEnvironment() {
|
|
35
|
+
this.log('Validating environment configuration...');
|
|
36
|
+
|
|
37
|
+
const required = ['WORDPRESS_URL', 'WORDPRESS_USERNAME', 'WORDPRESS_APP_PASSWORD'];
|
|
38
|
+
const missing = required.filter(key => !process.env[key]);
|
|
39
|
+
|
|
40
|
+
if (missing.length > 0) {
|
|
41
|
+
throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.log('Environment validation passed', 'success');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async validateServerFile() {
|
|
48
|
+
this.log('Checking MCP server file...');
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
await fs.access(this.serverPath);
|
|
52
|
+
this.log('MCP server file found', 'success');
|
|
53
|
+
} catch (error) {
|
|
54
|
+
throw new Error(`MCP server file not found: ${this.serverPath}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async startServer() {
|
|
59
|
+
if (this.serverProcess) {
|
|
60
|
+
this.log('Server is already running', 'warn');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.log('Starting Enhanced WordPress MCP Server...');
|
|
65
|
+
|
|
66
|
+
this.serverProcess = spawn('node', [this.serverPath], {
|
|
67
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
68
|
+
env: process.env
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Handle server output
|
|
72
|
+
this.serverProcess.stdout.on('data', (data) => {
|
|
73
|
+
const output = data.toString().trim();
|
|
74
|
+
if (output) {
|
|
75
|
+
console.log(`[SERVER] ${output}`);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
this.serverProcess.stderr.on('data', (data) => {
|
|
80
|
+
const output = data.toString().trim();
|
|
81
|
+
if (output) {
|
|
82
|
+
if (output.includes('Enhanced WordPress MCP Server') && output.includes('running')) {
|
|
83
|
+
this.log('MCP Server started successfully', 'success');
|
|
84
|
+
this.log(`Server PID: ${this.serverProcess.pid}`);
|
|
85
|
+
this.log('MCP Server is ready to accept connections');
|
|
86
|
+
} else if (output.includes('ERROR') || output.includes('Error')) {
|
|
87
|
+
this.log(`Server error: ${output}`, 'error');
|
|
88
|
+
} else {
|
|
89
|
+
console.log(`[SERVER] ${output}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Handle server exit
|
|
95
|
+
this.serverProcess.on('exit', (code, signal) => {
|
|
96
|
+
if (!this.isShuttingDown) {
|
|
97
|
+
if (code === 0) {
|
|
98
|
+
this.log('Server exited gracefully');
|
|
99
|
+
} else {
|
|
100
|
+
this.log(`Server exited with code ${code} (signal: ${signal})`, 'error');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this.serverProcess = null;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
this.serverProcess.on('error', (error) => {
|
|
107
|
+
this.log(`Server startup error: ${error.message}`, 'error');
|
|
108
|
+
this.serverProcess = null;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Setup graceful shutdown
|
|
112
|
+
this.setupShutdownHandlers();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
setupShutdownHandlers() {
|
|
116
|
+
const shutdown = async (signal) => {
|
|
117
|
+
if (this.isShuttingDown) return;
|
|
118
|
+
|
|
119
|
+
this.isShuttingDown = true;
|
|
120
|
+
this.log(`Received ${signal}, shutting down gracefully...`);
|
|
121
|
+
|
|
122
|
+
if (this.serverProcess) {
|
|
123
|
+
this.log('Stopping MCP server...');
|
|
124
|
+
this.serverProcess.kill('SIGTERM');
|
|
125
|
+
|
|
126
|
+
// Force kill after 10 seconds
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
if (this.serverProcess) {
|
|
129
|
+
this.log('Force killing server...', 'warn');
|
|
130
|
+
this.serverProcess.kill('SIGKILL');
|
|
131
|
+
}
|
|
132
|
+
}, 10000);
|
|
133
|
+
|
|
134
|
+
// Wait for server to exit
|
|
135
|
+
await new Promise((resolve) => {
|
|
136
|
+
if (!this.serverProcess) {
|
|
137
|
+
resolve();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.serverProcess.on('exit', () => {
|
|
142
|
+
resolve();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.log('Shutdown complete');
|
|
148
|
+
process.exit(0);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
152
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
153
|
+
process.on('SIGHUP', () => shutdown('SIGHUP'));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async launch() {
|
|
157
|
+
try {
|
|
158
|
+
this.log('š MyAIDev Method MCP Server Launcher');
|
|
159
|
+
this.log('=====================================');
|
|
160
|
+
|
|
161
|
+
await this.validateEnvironment();
|
|
162
|
+
await this.validateServerFile();
|
|
163
|
+
await this.startServer();
|
|
164
|
+
|
|
165
|
+
// Keep the launcher running
|
|
166
|
+
this.log('Launcher is monitoring server...');
|
|
167
|
+
|
|
168
|
+
} catch (error) {
|
|
169
|
+
this.log(`Launch failed: ${error.message}`, 'error');
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async status() {
|
|
175
|
+
this.log('MCP Server Status Check');
|
|
176
|
+
this.log('======================');
|
|
177
|
+
|
|
178
|
+
if (this.serverProcess) {
|
|
179
|
+
this.log(`Server is running (PID: ${this.serverProcess.pid})`, 'success');
|
|
180
|
+
this.log(`Server path: ${this.serverPath}`);
|
|
181
|
+
} else {
|
|
182
|
+
this.log('Server is not running', 'warn');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Environment status
|
|
186
|
+
const envVars = ['WORDPRESS_URL', 'WORDPRESS_USERNAME', 'WORDPRESS_APP_PASSWORD'];
|
|
187
|
+
this.log('\nEnvironment variables:');
|
|
188
|
+
envVars.forEach(key => {
|
|
189
|
+
const status = process.env[key] ? 'ā
' : 'ā';
|
|
190
|
+
const value = process.env[key] ? 'configured' : 'missing';
|
|
191
|
+
console.log(` ${status} ${key}: ${value}`);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
running: !!this.serverProcess,
|
|
196
|
+
pid: this.serverProcess?.pid,
|
|
197
|
+
serverPath: this.serverPath
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// CLI interface
|
|
203
|
+
async function main() {
|
|
204
|
+
const launcher = new MCPLauncher();
|
|
205
|
+
const command = process.argv[2] || 'start';
|
|
206
|
+
|
|
207
|
+
switch (command) {
|
|
208
|
+
case 'start':
|
|
209
|
+
await launcher.launch();
|
|
210
|
+
break;
|
|
211
|
+
|
|
212
|
+
case 'status':
|
|
213
|
+
await launcher.status();
|
|
214
|
+
break;
|
|
215
|
+
|
|
216
|
+
case 'health':
|
|
217
|
+
const { default: healthCheck } = await import('./health-check.js');
|
|
218
|
+
await healthCheck();
|
|
219
|
+
break;
|
|
220
|
+
|
|
221
|
+
default:
|
|
222
|
+
console.log('Usage: node mcp-launcher.js [start|status|health]');
|
|
223
|
+
console.log('');
|
|
224
|
+
console.log('Commands:');
|
|
225
|
+
console.log(' start - Start the MCP server (default)');
|
|
226
|
+
console.log(' status - Show server status');
|
|
227
|
+
console.log(' health - Run health check');
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export { MCPLauncher };
|
|
233
|
+
|
|
234
|
+
// Run if called directly
|
|
235
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
236
|
+
main().catch(console.error);
|
|
237
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Coolify Application Deployment Script
|
|
5
|
+
* Deploy applications to Coolify with full configuration support
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { CoolifyUtils } from '../lib/coolify-utils.js';
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
|
|
12
|
+
const options = {
|
|
13
|
+
name: null,
|
|
14
|
+
repo: null,
|
|
15
|
+
branch: 'main',
|
|
16
|
+
buildPack: 'nixpacks',
|
|
17
|
+
port: '3000',
|
|
18
|
+
domain: null,
|
|
19
|
+
serverUuid: null,
|
|
20
|
+
projectUuid: null,
|
|
21
|
+
envFile: null,
|
|
22
|
+
instant: false,
|
|
23
|
+
force: false,
|
|
24
|
+
wait: true,
|
|
25
|
+
json: args.includes('--json'),
|
|
26
|
+
verbose: args.includes('--verbose') || args.includes('-v')
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// Parse arguments
|
|
30
|
+
for (let i = 0; i < args.length; i++) {
|
|
31
|
+
switch (args[i]) {
|
|
32
|
+
case '--name':
|
|
33
|
+
options.name = args[++i];
|
|
34
|
+
break;
|
|
35
|
+
case '--repo':
|
|
36
|
+
case '--repository':
|
|
37
|
+
options.repo = args[++i];
|
|
38
|
+
break;
|
|
39
|
+
case '--branch':
|
|
40
|
+
options.branch = args[++i];
|
|
41
|
+
break;
|
|
42
|
+
case '--build-pack':
|
|
43
|
+
options.buildPack = args[++i];
|
|
44
|
+
break;
|
|
45
|
+
case '--port':
|
|
46
|
+
options.port = args[++i];
|
|
47
|
+
break;
|
|
48
|
+
case '--domain':
|
|
49
|
+
options.domain = args[++i];
|
|
50
|
+
break;
|
|
51
|
+
case '--server-uuid':
|
|
52
|
+
options.serverUuid = args[++i];
|
|
53
|
+
break;
|
|
54
|
+
case '--project-uuid':
|
|
55
|
+
options.projectUuid = args[++i];
|
|
56
|
+
break;
|
|
57
|
+
case '--env-file':
|
|
58
|
+
options.envFile = args[++i];
|
|
59
|
+
break;
|
|
60
|
+
case '--instant':
|
|
61
|
+
options.instant = true;
|
|
62
|
+
break;
|
|
63
|
+
case '--force':
|
|
64
|
+
options.force = true;
|
|
65
|
+
break;
|
|
66
|
+
case '--no-wait':
|
|
67
|
+
options.wait = false;
|
|
68
|
+
break;
|
|
69
|
+
case '--help':
|
|
70
|
+
case '-h':
|
|
71
|
+
printHelp();
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function printHelp() {
|
|
77
|
+
console.log(`
|
|
78
|
+
Coolify Application Deployment Script
|
|
79
|
+
|
|
80
|
+
Usage: coolify-deploy-app [options]
|
|
81
|
+
|
|
82
|
+
Required Options:
|
|
83
|
+
--name <name> Application name
|
|
84
|
+
--repo <url> Git repository URL
|
|
85
|
+
--project-uuid <uuid> Target project UUID
|
|
86
|
+
--server-uuid <uuid> Target server UUID
|
|
87
|
+
|
|
88
|
+
Optional Options:
|
|
89
|
+
--branch <name> Git branch (default: main)
|
|
90
|
+
--build-pack <type> Build pack: nixpacks, dockerfile, static (default: nixpacks)
|
|
91
|
+
--port <port> Application port (default: 3000)
|
|
92
|
+
--domain <domain> Domain name for the application
|
|
93
|
+
--env-file <path> Environment variables file
|
|
94
|
+
--instant Deploy instantly (skip queue)
|
|
95
|
+
--force Force rebuild
|
|
96
|
+
--no-wait Don't wait for deployment to complete
|
|
97
|
+
--verbose Show detailed progress
|
|
98
|
+
-v Alias for --verbose
|
|
99
|
+
--json Output in JSON format
|
|
100
|
+
--help Show this help
|
|
101
|
+
-h Alias for --help
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
# Basic deployment
|
|
105
|
+
node src/scripts/coolify-deploy-app.js \\
|
|
106
|
+
--name "myapp" \\
|
|
107
|
+
--repo "https://github.com/user/myapp" \\
|
|
108
|
+
--project-uuid "zg44coscocg0sko8k0wgcgkw" \\
|
|
109
|
+
--server-uuid "vcscogc44gko4k880ww880kk"
|
|
110
|
+
|
|
111
|
+
# With custom domain and environment
|
|
112
|
+
node src/scripts/coolify-deploy-app.js \\
|
|
113
|
+
--name "api-prod" \\
|
|
114
|
+
--repo "https://github.com/user/api" \\
|
|
115
|
+
--branch "production" \\
|
|
116
|
+
--domain "api.example.com" \\
|
|
117
|
+
--env-file ".env.production" \\
|
|
118
|
+
--project-uuid "zg44coscocg0sko8k0wgcgkw" \\
|
|
119
|
+
--server-uuid "vcscogc44gko4k880ww880kk"
|
|
120
|
+
|
|
121
|
+
# Dockerfile-based deployment
|
|
122
|
+
node src/scripts/coolify-deploy-app.js \\
|
|
123
|
+
--name "docker-app" \\
|
|
124
|
+
--repo "https://github.com/user/docker-app" \\
|
|
125
|
+
--build-pack "dockerfile" \\
|
|
126
|
+
--port "8080" \\
|
|
127
|
+
--project-uuid "zg44coscocg0sko8k0wgcgkw" \\
|
|
128
|
+
--server-uuid "vcscogc44gko4k880ww880kk"
|
|
129
|
+
`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function deployApplication() {
|
|
133
|
+
try {
|
|
134
|
+
// Validate required options
|
|
135
|
+
if (!options.name || !options.repo || !options.projectUuid || !options.serverUuid) {
|
|
136
|
+
console.error('Error: Missing required options');
|
|
137
|
+
console.error('Required: --name, --repo, --project-uuid, --server-uuid');
|
|
138
|
+
console.error('Run with --help for usage information');
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (options.verbose) {
|
|
143
|
+
console.error('Initializing Coolify connection...');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const coolify = new CoolifyUtils();
|
|
147
|
+
|
|
148
|
+
// Verify connectivity
|
|
149
|
+
const healthy = await coolify.healthCheck();
|
|
150
|
+
if (!healthy) {
|
|
151
|
+
throw new Error('Coolify is not reachable');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (options.verbose) {
|
|
155
|
+
console.error('ā Coolify is reachable');
|
|
156
|
+
console.error(`Deploying application: ${options.name}`);
|
|
157
|
+
console.error(`Repository: ${options.repo}`);
|
|
158
|
+
console.error(`Branch: ${options.branch}`);
|
|
159
|
+
console.error(`Build pack: ${options.buildPack}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Build application configuration (Coolify API format)
|
|
163
|
+
const appConfig = {
|
|
164
|
+
project_uuid: options.projectUuid,
|
|
165
|
+
server_uuid: options.serverUuid,
|
|
166
|
+
environment_name: 'production', // Required field
|
|
167
|
+
git_repository: options.repo,
|
|
168
|
+
git_branch: options.branch,
|
|
169
|
+
name: options.name,
|
|
170
|
+
description: `Deployed via myaidev-method on ${new Date().toISOString()}`,
|
|
171
|
+
build_pack: options.buildPack,
|
|
172
|
+
ports_exposes: options.port,
|
|
173
|
+
instant_deploy: options.instant,
|
|
174
|
+
domains: options.domain ? [options.domain] : []
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Load environment variables if specified
|
|
178
|
+
if (options.envFile) {
|
|
179
|
+
if (options.verbose) {
|
|
180
|
+
console.error(`Loading environment from: ${options.envFile}`);
|
|
181
|
+
}
|
|
182
|
+
// Environment variables would be loaded here
|
|
183
|
+
// For now, we'll skip this as it requires reading the file
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (options.verbose) {
|
|
187
|
+
console.error('Creating application in Coolify...');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Create application
|
|
191
|
+
const app = await coolify.createApplication(appConfig);
|
|
192
|
+
|
|
193
|
+
if (options.verbose) {
|
|
194
|
+
console.error(`ā Application created: ${app.uuid}`);
|
|
195
|
+
console.error('Starting deployment...');
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Deploy application
|
|
199
|
+
const deployment = await coolify.deployApplication(app.uuid, {
|
|
200
|
+
force: options.force,
|
|
201
|
+
instant: options.instant
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (options.verbose) {
|
|
205
|
+
console.error('ā Deployment triggered');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let result = { success: true, status: 'deployed' };
|
|
209
|
+
|
|
210
|
+
// Wait for deployment to complete
|
|
211
|
+
if (options.wait) {
|
|
212
|
+
if (options.verbose) {
|
|
213
|
+
console.error('Waiting for deployment to complete...');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
result = await coolify.waitForDeployment(app.uuid, {
|
|
217
|
+
maxAttempts: 120,
|
|
218
|
+
interval: 5000
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
if (options.verbose) {
|
|
222
|
+
if (result.success) {
|
|
223
|
+
console.error(`ā Deployment completed successfully after ${result.attempts} checks`);
|
|
224
|
+
} else {
|
|
225
|
+
console.error(`ā Deployment failed with status: ${result.status}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Get final application state
|
|
231
|
+
const finalApp = await coolify.getApplication(app.uuid);
|
|
232
|
+
|
|
233
|
+
// Prepare output
|
|
234
|
+
const output = {
|
|
235
|
+
success: result.success,
|
|
236
|
+
application: {
|
|
237
|
+
uuid: finalApp.uuid,
|
|
238
|
+
name: finalApp.name,
|
|
239
|
+
status: finalApp.status || 'unknown',
|
|
240
|
+
url: finalApp.fqdn || 'Not configured',
|
|
241
|
+
repository: options.repo,
|
|
242
|
+
branch: options.branch
|
|
243
|
+
},
|
|
244
|
+
deployment: {
|
|
245
|
+
status: result.status,
|
|
246
|
+
timestamp: new Date().toISOString()
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
if (options.json) {
|
|
251
|
+
console.log(JSON.stringify(output, null, 2));
|
|
252
|
+
} else {
|
|
253
|
+
console.log('\n' + '='.repeat(60));
|
|
254
|
+
console.log('Deployment Result');
|
|
255
|
+
console.log('='.repeat(60));
|
|
256
|
+
console.log(`Status: ${result.success ? 'ā Success' : 'ā Failed'}`);
|
|
257
|
+
console.log(`Application: ${finalApp.name}`);
|
|
258
|
+
console.log(`UUID: ${finalApp.uuid}`);
|
|
259
|
+
console.log(`URL: ${finalApp.fqdn || 'Configure domain in Coolify'}`);
|
|
260
|
+
console.log(`Repository: ${options.repo}`);
|
|
261
|
+
console.log(`Branch: ${options.branch}`);
|
|
262
|
+
console.log('='.repeat(60));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
process.exit(result.success ? 0 : 1);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
if (options.json) {
|
|
268
|
+
console.log(JSON.stringify({
|
|
269
|
+
success: false,
|
|
270
|
+
error: error.message,
|
|
271
|
+
timestamp: new Date().toISOString()
|
|
272
|
+
}, null, 2));
|
|
273
|
+
} else {
|
|
274
|
+
console.error(`\nError: ${error.message}`);
|
|
275
|
+
if (options.verbose) {
|
|
276
|
+
console.error(`Stack: ${error.stack}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
284
|
+
deployApplication();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export { deployApplication };
|