moltengine-cli 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/README.md +119 -0
- package/package.json +41 -0
- package/src/moltengine.js +256 -0
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Moltengine CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for Moltengine — The WP Engine for AI Agents.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Via npm (Recommended)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g moltengine-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Via npx (No Install)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx moltengine-cli status
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Direct Download
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
curl -fsSL https://moltengine.com/install.sh | bash
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
Set your environment variables:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
export MOLTENGINE_API="https://api.moltengine.com"
|
|
31
|
+
export MOLT_TENANT_KEY="your-api-key-here"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Add to your shell config (`~/.bashrc` or `~/.zshrc`) for persistence:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
echo 'export MOLTENGINE_API="https://api.moltengine.com"' >> ~/.bashrc
|
|
38
|
+
echo 'export MOLT_TENANT_KEY="your-api-key-here"' >> ~/.bashrc
|
|
39
|
+
source ~/.bashrc
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Show tenant information
|
|
46
|
+
moltengine whoami
|
|
47
|
+
|
|
48
|
+
# Check status
|
|
49
|
+
moltengine status
|
|
50
|
+
|
|
51
|
+
# List deployments
|
|
52
|
+
moltengine deployments
|
|
53
|
+
|
|
54
|
+
# Show help
|
|
55
|
+
moltengine help
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Commands
|
|
59
|
+
|
|
60
|
+
| Command | Description |
|
|
61
|
+
|---------|-------------|
|
|
62
|
+
| `moltengine whoami` | Show current tenant information |
|
|
63
|
+
| `moltengine status` | Show tenant status and deployment info |
|
|
64
|
+
| `moltengine deployments` | List recent deployments |
|
|
65
|
+
| `moltengine help` | Show help message |
|
|
66
|
+
|
|
67
|
+
## Environment Variables
|
|
68
|
+
|
|
69
|
+
| Variable | Required | Description |
|
|
70
|
+
|----------|----------|-------------|
|
|
71
|
+
| `MOLTENGINE_API` | Yes | API URL (e.g., `https://api.moltengine.com`) |
|
|
72
|
+
| `MOLT_TENANT_KEY` | Yes | Your tenant API key |
|
|
73
|
+
|
|
74
|
+
## Getting Your API Key
|
|
75
|
+
|
|
76
|
+
Your API key is displayed on the success page after completing checkout at [moltengine.com](https://moltengine.com).
|
|
77
|
+
|
|
78
|
+
If you've lost your API key, contact support@moltengine.com.
|
|
79
|
+
|
|
80
|
+
## Development
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Clone the repo
|
|
84
|
+
git clone https://github.com/moltengine/moltengine.git
|
|
85
|
+
cd moltengine/cli
|
|
86
|
+
|
|
87
|
+
# Install dependencies
|
|
88
|
+
npm install
|
|
89
|
+
|
|
90
|
+
# Run locally
|
|
91
|
+
npm start -- status
|
|
92
|
+
|
|
93
|
+
# Link for local development
|
|
94
|
+
npm link
|
|
95
|
+
moltengine status
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Publishing (Maintainers)
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Bump version
|
|
102
|
+
npm version patch # or minor, major
|
|
103
|
+
|
|
104
|
+
# Publish to npm
|
|
105
|
+
npm publish
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Requirements
|
|
109
|
+
|
|
110
|
+
- Node.js 20+
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
MIT
|
|
115
|
+
|
|
116
|
+
## Support
|
|
117
|
+
|
|
118
|
+
- Email: support@moltengine.com
|
|
119
|
+
- Docs: https://docs.moltengine.com
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "moltengine-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Moltengine - The WP Engine for AI Agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Moltengine",
|
|
8
|
+
"homepage": "https://moltengine.com",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/moltengine/moltengine.git",
|
|
12
|
+
"directory": "cli"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/moltengine/moltengine/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"moltengine",
|
|
19
|
+
"moltbot",
|
|
20
|
+
"clawdbot",
|
|
21
|
+
"ai-agents",
|
|
22
|
+
"cli"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"moltengine": "src/moltengine.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"src/**/*"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"start": "node src/moltengine.js",
|
|
32
|
+
"test": "node src/moltengine.js --help",
|
|
33
|
+
"prepublishOnly": "npm test"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"undici": "^6.21.0"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { request } from "undici";
|
|
4
|
+
|
|
5
|
+
// Configuration
|
|
6
|
+
const API_URL = process.env.MOLTENGINE_API || "http://localhost:8080";
|
|
7
|
+
const TENANT_KEY = process.env.MOLT_TENANT_KEY || "";
|
|
8
|
+
|
|
9
|
+
// ANSI colors
|
|
10
|
+
const colors = {
|
|
11
|
+
reset: "\x1b[0m",
|
|
12
|
+
bold: "\x1b[1m",
|
|
13
|
+
dim: "\x1b[2m",
|
|
14
|
+
green: "\x1b[32m",
|
|
15
|
+
yellow: "\x1b[33m",
|
|
16
|
+
red: "\x1b[31m",
|
|
17
|
+
cyan: "\x1b[36m",
|
|
18
|
+
blue: "\x1b[34m"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Print colored output
|
|
23
|
+
*/
|
|
24
|
+
function print(message, color = "") {
|
|
25
|
+
console.log(color ? `${color}${message}${colors.reset}` : message);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Print error and exit
|
|
30
|
+
*/
|
|
31
|
+
function error(message) {
|
|
32
|
+
print(`Error: ${message}`, colors.red);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Make an authenticated GET request
|
|
38
|
+
*/
|
|
39
|
+
async function apiGet(path) {
|
|
40
|
+
if (!TENANT_KEY) {
|
|
41
|
+
error("MOLT_TENANT_KEY environment variable is required");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const url = `${API_URL}${path}`;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const response = await request(url, {
|
|
48
|
+
method: "GET",
|
|
49
|
+
headers: {
|
|
50
|
+
"x-tenant-key": TENANT_KEY,
|
|
51
|
+
"Accept": "application/json"
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const text = await response.body.text();
|
|
56
|
+
|
|
57
|
+
if (response.statusCode >= 400) {
|
|
58
|
+
const data = text ? JSON.parse(text) : {};
|
|
59
|
+
error(data.error || `Request failed with status ${response.statusCode}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return JSON.parse(text);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
if (err.code === "ECONNREFUSED") {
|
|
65
|
+
error(`Cannot connect to API at ${API_URL}`);
|
|
66
|
+
}
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Format a date string
|
|
73
|
+
*/
|
|
74
|
+
function formatDate(dateStr) {
|
|
75
|
+
if (!dateStr) return "N/A";
|
|
76
|
+
return new Date(dateStr).toLocaleString();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Format status with color
|
|
81
|
+
*/
|
|
82
|
+
function formatStatus(status) {
|
|
83
|
+
const statusColors = {
|
|
84
|
+
active: colors.green,
|
|
85
|
+
pending: colors.yellow,
|
|
86
|
+
inactive: colors.dim,
|
|
87
|
+
past_due: colors.red,
|
|
88
|
+
canceled: colors.red,
|
|
89
|
+
suspended: colors.red,
|
|
90
|
+
succeeded: colors.green,
|
|
91
|
+
running: colors.cyan,
|
|
92
|
+
queued: colors.yellow,
|
|
93
|
+
failed: colors.red
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const color = statusColors[status?.toLowerCase()] || colors.reset;
|
|
97
|
+
return `${color}${status}${colors.reset}`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ============================================================================
|
|
101
|
+
// COMMANDS
|
|
102
|
+
// ============================================================================
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Display help
|
|
106
|
+
*/
|
|
107
|
+
function showHelp() {
|
|
108
|
+
console.log(`
|
|
109
|
+
${colors.bold}moltengine${colors.reset} - Moltengine CLI
|
|
110
|
+
|
|
111
|
+
${colors.bold}USAGE${colors.reset}
|
|
112
|
+
moltengine <command> [options]
|
|
113
|
+
|
|
114
|
+
${colors.bold}COMMANDS${colors.reset}
|
|
115
|
+
whoami Show current tenant information
|
|
116
|
+
status Show tenant status and deployment info
|
|
117
|
+
deployments List recent deployments
|
|
118
|
+
help Show this help message
|
|
119
|
+
|
|
120
|
+
${colors.bold}ENVIRONMENT${colors.reset}
|
|
121
|
+
MOLTENGINE_API API URL (default: http://localhost:8080)
|
|
122
|
+
MOLT_TENANT_KEY Your tenant API key (required)
|
|
123
|
+
|
|
124
|
+
${colors.bold}EXAMPLES${colors.reset}
|
|
125
|
+
# Set up environment
|
|
126
|
+
export MOLTENGINE_API="https://api.moltengine.io"
|
|
127
|
+
export MOLT_TENANT_KEY="your-tenant-key-here"
|
|
128
|
+
|
|
129
|
+
# Check your tenant info
|
|
130
|
+
moltengine whoami
|
|
131
|
+
|
|
132
|
+
# Check status
|
|
133
|
+
moltengine status
|
|
134
|
+
`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Show tenant information
|
|
139
|
+
*/
|
|
140
|
+
async function cmdWhoami() {
|
|
141
|
+
const data = await apiGet("/tenant/me");
|
|
142
|
+
|
|
143
|
+
console.log(`
|
|
144
|
+
${colors.bold}Tenant Information${colors.reset}
|
|
145
|
+
${"─".repeat(40)}
|
|
146
|
+
${colors.dim}ID:${colors.reset} ${data.tenantId}
|
|
147
|
+
${colors.dim}Name:${colors.reset} ${data.name}
|
|
148
|
+
${colors.dim}Email:${colors.reset} ${data.email}
|
|
149
|
+
${colors.dim}Status:${colors.reset} ${formatStatus(data.status)}
|
|
150
|
+
${colors.dim}FQDN:${colors.reset} ${data.fqdn || "(not configured)"}
|
|
151
|
+
${colors.dim}Created:${colors.reset} ${formatDate(data.createdAt)}
|
|
152
|
+
`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Show tenant status
|
|
157
|
+
*/
|
|
158
|
+
async function cmdStatus() {
|
|
159
|
+
const data = await apiGet("/tenant/me");
|
|
160
|
+
|
|
161
|
+
print(`\n${colors.bold}Moltengine Status${colors.reset}`);
|
|
162
|
+
print("─".repeat(40));
|
|
163
|
+
|
|
164
|
+
// Status line
|
|
165
|
+
const statusIcon = data.status === "active" ? "●" : "○";
|
|
166
|
+
const statusColor = data.status === "active" ? colors.green : colors.yellow;
|
|
167
|
+
print(` Status: ${statusColor}${statusIcon} ${data.status}${colors.reset}`);
|
|
168
|
+
|
|
169
|
+
// FQDN
|
|
170
|
+
if (data.fqdn) {
|
|
171
|
+
print(` URL: ${colors.cyan}https://${data.fqdn}${colors.reset}`);
|
|
172
|
+
} else {
|
|
173
|
+
print(` URL: ${colors.dim}(provisioning...)${colors.reset}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Last provisioned
|
|
177
|
+
print(` Last Deployed: ${formatDate(data.lastProvisioned)}`);
|
|
178
|
+
|
|
179
|
+
// Error (if any)
|
|
180
|
+
if (data.lastError) {
|
|
181
|
+
print(` ${colors.red}Error: ${data.lastError}${colors.reset}`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log();
|
|
185
|
+
|
|
186
|
+
// Show connection info if active
|
|
187
|
+
if (data.status === "active" && data.fqdn) {
|
|
188
|
+
print(`${colors.bold}Connect to your Moltbot:${colors.reset}`);
|
|
189
|
+
print(` Dashboard: ${colors.cyan}https://${data.fqdn}${colors.reset}`);
|
|
190
|
+
print(` Gateway: ${colors.cyan}https://${data.fqdn}:18789${colors.reset}`);
|
|
191
|
+
console.log();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* List recent deployments
|
|
197
|
+
*/
|
|
198
|
+
async function cmdDeployments() {
|
|
199
|
+
const data = await apiGet("/tenant/deployments");
|
|
200
|
+
|
|
201
|
+
print(`\n${colors.bold}Recent Deployments${colors.reset}`);
|
|
202
|
+
print("─".repeat(60));
|
|
203
|
+
|
|
204
|
+
if (!data.deployments || data.deployments.length === 0) {
|
|
205
|
+
print(" No deployments found");
|
|
206
|
+
console.log();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
for (const dep of data.deployments) {
|
|
211
|
+
const date = formatDate(dep.created_at);
|
|
212
|
+
const status = formatStatus(dep.status);
|
|
213
|
+
print(` ${colors.dim}[${date}]${colors.reset} ${dep.kind} - ${status}`);
|
|
214
|
+
if (dep.error) {
|
|
215
|
+
print(` ${colors.red}Error: ${dep.error.substring(0, 60)}...${colors.reset}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// MAIN
|
|
224
|
+
// ============================================================================
|
|
225
|
+
|
|
226
|
+
async function main() {
|
|
227
|
+
const [, , command, ...args] = process.argv;
|
|
228
|
+
|
|
229
|
+
if (!command || command === "help" || command === "--help" || command === "-h") {
|
|
230
|
+
showHelp();
|
|
231
|
+
process.exit(0);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
switch (command) {
|
|
235
|
+
case "whoami":
|
|
236
|
+
await cmdWhoami();
|
|
237
|
+
break;
|
|
238
|
+
|
|
239
|
+
case "status":
|
|
240
|
+
await cmdStatus();
|
|
241
|
+
break;
|
|
242
|
+
|
|
243
|
+
case "deployments":
|
|
244
|
+
await cmdDeployments();
|
|
245
|
+
break;
|
|
246
|
+
|
|
247
|
+
default:
|
|
248
|
+
print(`Unknown command: ${command}`, colors.red);
|
|
249
|
+
print(`Run 'moltengine help' for usage information`);
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
main().catch((err) => {
|
|
255
|
+
error(err.message || String(err));
|
|
256
|
+
});
|