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.
Files changed (3) hide show
  1. package/README.md +119 -0
  2. package/package.json +41 -0
  3. 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
+ });