@eagsolutions/phanom-cli 0.0.1
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/bin/phanom.js +2 -0
- package/package.json +17 -0
- package/src/commands/init.js +28 -0
- package/src/commands/logs.js +100 -0
- package/src/commands/ps.js +112 -0
- package/src/commands/restart.js +80 -0
- package/src/commands/shell.js +156 -0
- package/src/commands/start.js +80 -0
- package/src/commands/stop.js +80 -0
- package/src/commands/up.js +213 -0
- package/src/commands/upmemory.js +115 -0
- package/src/index.js +73 -0
- package/src/utils/config.js +29 -0
package/bin/phanom.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eagsolutions/phanom-cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "PhanomCloud CLI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"phanom": "bin/phanom.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node bin/phanom.js"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"chalk": "^5.3.0",
|
|
14
|
+
"commander": "^12.1.0",
|
|
15
|
+
"inquirer": "^9.3.7"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
|
|
7
|
+
export default async function init() {
|
|
8
|
+
const promptText =
|
|
9
|
+
chalk.black("(") +
|
|
10
|
+
chalk.gray(" @") +
|
|
11
|
+
chalk.black(" ) ") +
|
|
12
|
+
chalk.gray("API key: ") +
|
|
13
|
+
chalk.white("");
|
|
14
|
+
|
|
15
|
+
const answers = await inquirer.prompt([
|
|
16
|
+
{
|
|
17
|
+
type: "password",
|
|
18
|
+
name: "apikey",
|
|
19
|
+
message: promptText,
|
|
20
|
+
mask: "*"
|
|
21
|
+
}
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
const rcPath = path.join(os.homedir(), ".openphanomid.rc");
|
|
25
|
+
const content = `API=${answers.apikey}\n`;
|
|
26
|
+
|
|
27
|
+
fs.writeFileSync(rcPath, content, "utf8");
|
|
28
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { getApiKey } from "../utils/config.js";
|
|
3
|
+
|
|
4
|
+
export default async function logs(name, options) {
|
|
5
|
+
const apiKey = getApiKey();
|
|
6
|
+
|
|
7
|
+
const botsResponse = await fetch(
|
|
8
|
+
"https://api.phanomcloud.online/bots",
|
|
9
|
+
{
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${apiKey}`
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (!botsResponse.ok) {
|
|
17
|
+
console.log(
|
|
18
|
+
chalk.red("Failed to fetch bots.")
|
|
19
|
+
);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const botsJson = await botsResponse.json();
|
|
24
|
+
|
|
25
|
+
if (!botsJson.success) {
|
|
26
|
+
console.log(
|
|
27
|
+
chalk.red("Invalid API response.")
|
|
28
|
+
);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const bot = botsJson.data.find(
|
|
33
|
+
(b) =>
|
|
34
|
+
b.name.toLowerCase() ===
|
|
35
|
+
name.toLowerCase()
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (!bot) {
|
|
39
|
+
console.log(
|
|
40
|
+
chalk.red(`Bot "${name}" not found.`)
|
|
41
|
+
);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let url =
|
|
46
|
+
`https://api.phanomcloud.online/bots/${bot.id}/logs`;
|
|
47
|
+
|
|
48
|
+
if (options.lines) {
|
|
49
|
+
url += `?lines=${options.lines}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const logsResponse = await fetch(url, {
|
|
53
|
+
headers: {
|
|
54
|
+
Authorization: `Bearer ${apiKey}`
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!logsResponse.ok) {
|
|
59
|
+
console.log(
|
|
60
|
+
chalk.red("Failed to fetch logs.")
|
|
61
|
+
);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const logsJson = await logsResponse.json();
|
|
66
|
+
|
|
67
|
+
if (!logsJson.success) {
|
|
68
|
+
console.log(
|
|
69
|
+
chalk.red("Invalid logs response.")
|
|
70
|
+
);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const logs = logsJson.data.logs || [];
|
|
75
|
+
|
|
76
|
+
if (!logs.length) {
|
|
77
|
+
console.log(
|
|
78
|
+
chalk.gray("No logs available.")
|
|
79
|
+
);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log("");
|
|
84
|
+
|
|
85
|
+
for (const line of logs) {
|
|
86
|
+
if (line.startsWith("[SYSTEM]")) {
|
|
87
|
+
console.log(
|
|
88
|
+
chalk.green(line)
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(
|
|
95
|
+
chalk.gray(line)
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log("");
|
|
100
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { getApiKey } from "../utils/config.js";
|
|
3
|
+
|
|
4
|
+
function truncate(text, max) {
|
|
5
|
+
if (!text) return "";
|
|
6
|
+
return text.length > max ? text.slice(0, max - 1) + "…" : text;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function pad(text, width) {
|
|
10
|
+
const str = String(text ?? "");
|
|
11
|
+
return str.length >= width ? str : str + " ".repeat(width - str.length);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function formatAge(createdAt) {
|
|
15
|
+
const created = new Date(createdAt);
|
|
16
|
+
const diffMs = Date.now() - created.getTime();
|
|
17
|
+
|
|
18
|
+
const mins = Math.floor(diffMs / 60000);
|
|
19
|
+
const hours = Math.floor(diffMs / 3600000);
|
|
20
|
+
const days = Math.floor(diffMs / 86400000);
|
|
21
|
+
|
|
22
|
+
if (days > 0) return `${days}d ago`;
|
|
23
|
+
if (hours > 0) return `${hours}h ago`;
|
|
24
|
+
if (mins > 0) return `${mins}m ago`;
|
|
25
|
+
return "now";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default async function ps(options) {
|
|
29
|
+
const apiKey = getApiKey();
|
|
30
|
+
|
|
31
|
+
const response = await fetch("https://api.phanomcloud.online/bots", {
|
|
32
|
+
headers: {
|
|
33
|
+
Authorization: `Bearer ${apiKey}`
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const json = await response.json();
|
|
38
|
+
let bots = json.data || [];
|
|
39
|
+
|
|
40
|
+
if (options.aZ) {
|
|
41
|
+
bots.sort((a, b) => a.name.localeCompare(b.name));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (options.zA) {
|
|
45
|
+
bots.sort((a, b) => b.name.localeCompare(a.name));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!bots.length) {
|
|
49
|
+
console.log("No bots found.");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const rows = bots.map((bot) => ({
|
|
54
|
+
id: bot.id.slice(0, 12),
|
|
55
|
+
name: bot.name,
|
|
56
|
+
language: bot.language,
|
|
57
|
+
status: bot.status,
|
|
58
|
+
memory: `${bot.memory}MB`,
|
|
59
|
+
vcpu: `${bot.vcpu}`,
|
|
60
|
+
age: formatAge(bot.created_at),
|
|
61
|
+
command: bot.startup_command
|
|
62
|
+
}));
|
|
63
|
+
|
|
64
|
+
const widths = {
|
|
65
|
+
id: 12,
|
|
66
|
+
name: Math.max(4, ...rows.map((r) => r.name.length)),
|
|
67
|
+
language: Math.max(8, ...rows.map((r) => r.language.length)),
|
|
68
|
+
status: Math.max(6, ...rows.map((r) => r.status.length)),
|
|
69
|
+
memory: Math.max(6, ...rows.map((r) => r.memory.length)),
|
|
70
|
+
vcpu: Math.max(4, ...rows.map((r) => r.vcpu.length)),
|
|
71
|
+
age: Math.max(6, ...rows.map((r) => r.age.length)),
|
|
72
|
+
command: Math.max(7, ...rows.map((r) => r.command.length))
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
console.log("");
|
|
76
|
+
|
|
77
|
+
console.log(
|
|
78
|
+
chalk.gray(
|
|
79
|
+
pad("ID", widths.id) + " " +
|
|
80
|
+
pad("NAME", widths.name) + " " +
|
|
81
|
+
pad("LANG", widths.language) + " " +
|
|
82
|
+
pad("STATUS", widths.status) + " " +
|
|
83
|
+
pad("MEMORY", widths.memory) + " " +
|
|
84
|
+
pad("VCPU", widths.vcpu) + " " +
|
|
85
|
+
pad("AGE", widths.age) + " " +
|
|
86
|
+
"COMMAND"
|
|
87
|
+
)
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
for (const bot of rows) {
|
|
91
|
+
let statusColor = chalk.gray;
|
|
92
|
+
|
|
93
|
+
if (bot.status === "online") statusColor = chalk.green;
|
|
94
|
+
if (bot.status === "offline") statusColor = chalk.red;
|
|
95
|
+
if (bot.status === "starting") statusColor = chalk.yellow;
|
|
96
|
+
if (bot.status === "stopping") statusColor = chalk.magenta;
|
|
97
|
+
if (bot.status === "error") statusColor = chalk.redBright;
|
|
98
|
+
|
|
99
|
+
console.log(
|
|
100
|
+
chalk.white(pad(bot.id, widths.id)) + " " +
|
|
101
|
+
chalk.white(pad(truncate(bot.name, widths.name), widths.name)) + " " +
|
|
102
|
+
chalk.gray(pad(bot.language, widths.language)) + " " +
|
|
103
|
+
statusColor(pad(bot.status, widths.status)) + " " +
|
|
104
|
+
chalk.gray(pad(bot.memory, widths.memory)) + " " +
|
|
105
|
+
chalk.gray(pad(bot.vcpu, widths.vcpu)) + " " +
|
|
106
|
+
chalk.gray(pad(bot.age, widths.age)) + " " +
|
|
107
|
+
chalk.gray(truncate(bot.command, widths.command))
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log("");
|
|
112
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { getApiKey } from "../utils/config.js";
|
|
3
|
+
|
|
4
|
+
export default async function restart(name) {
|
|
5
|
+
const apiKey = getApiKey();
|
|
6
|
+
|
|
7
|
+
const botsResponse = await fetch(
|
|
8
|
+
"https://api.phanomcloud.online/bots",
|
|
9
|
+
{
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${apiKey}`
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (!botsResponse.ok) {
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const botsJson = await botsResponse.json();
|
|
21
|
+
|
|
22
|
+
if (!botsJson.success) {
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const bot = botsJson.data.find(
|
|
27
|
+
(b) =>
|
|
28
|
+
b.name.toLowerCase() ===
|
|
29
|
+
name.toLowerCase()
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (!bot) {
|
|
33
|
+
console.log(
|
|
34
|
+
chalk.gray("(") +
|
|
35
|
+
chalk.red("!") +
|
|
36
|
+
chalk.gray(") ") +
|
|
37
|
+
chalk.red(`Bot "${name}" not found.`)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const response = await fetch(
|
|
44
|
+
"https://api.phanomcloud.online/bots/restart",
|
|
45
|
+
{
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
Authorization: `Bearer ${apiKey}`,
|
|
49
|
+
"Content-Type": "application/json"
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
bot_id: bot.id
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const json = await response.json();
|
|
58
|
+
|
|
59
|
+
if (!json.success) {
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.gray("(") +
|
|
62
|
+
chalk.red("!") +
|
|
63
|
+
chalk.gray(") ") +
|
|
64
|
+
chalk.red(
|
|
65
|
+
json.error ||
|
|
66
|
+
"Failed to restart bot."
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.gray("(") +
|
|
75
|
+
chalk.yellow("*") +
|
|
76
|
+
chalk.gray(") Restarted ") +
|
|
77
|
+
chalk.yellow(bot.name) +
|
|
78
|
+
chalk.gray("...")
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import readline from "readline";
|
|
3
|
+
|
|
4
|
+
import { getApiKey } from "../utils/config.js";
|
|
5
|
+
|
|
6
|
+
export default async function shell(
|
|
7
|
+
target
|
|
8
|
+
) {
|
|
9
|
+
const apiKey = getApiKey();
|
|
10
|
+
|
|
11
|
+
const botsResponse = await fetch(
|
|
12
|
+
"https://api.phanomcloud.online/bots",
|
|
13
|
+
{
|
|
14
|
+
headers: {
|
|
15
|
+
Authorization: `Bearer ${apiKey}`
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
if (!botsResponse.ok) {
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const botsJson =
|
|
25
|
+
await botsResponse.json();
|
|
26
|
+
|
|
27
|
+
if (!botsJson.success) {
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const bot = botsJson.data.find(
|
|
32
|
+
(b) =>
|
|
33
|
+
b.name.toLowerCase() ===
|
|
34
|
+
target.toLowerCase() ||
|
|
35
|
+
b.id === target
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (!bot) {
|
|
39
|
+
console.log(
|
|
40
|
+
chalk.gray("(") +
|
|
41
|
+
chalk.red("!") +
|
|
42
|
+
chalk.gray(") ") +
|
|
43
|
+
chalk.red("Bot not found.")
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log("");
|
|
50
|
+
|
|
51
|
+
console.log(
|
|
52
|
+
chalk.gray("(") +
|
|
53
|
+
chalk.green("*") +
|
|
54
|
+
chalk.gray(") Connected to ") +
|
|
55
|
+
chalk.green(bot.name)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
console.log("");
|
|
59
|
+
|
|
60
|
+
const rl = readline.createInterface({
|
|
61
|
+
input: process.stdin,
|
|
62
|
+
output: process.stdout,
|
|
63
|
+
prompt:
|
|
64
|
+
chalk.gray(
|
|
65
|
+
`${bot.name}`
|
|
66
|
+
) + chalk.cyan(" ❯ ")
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
rl.prompt();
|
|
70
|
+
|
|
71
|
+
rl.on(
|
|
72
|
+
"line",
|
|
73
|
+
async (input) => {
|
|
74
|
+
const command =
|
|
75
|
+
input.trim();
|
|
76
|
+
|
|
77
|
+
if (!command) {
|
|
78
|
+
rl.prompt();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
command === "exit" ||
|
|
84
|
+
command === "quit"
|
|
85
|
+
) {
|
|
86
|
+
rl.close();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const response =
|
|
92
|
+
await fetch(
|
|
93
|
+
`https://api.phanomcloud.online/bots/${bot.id}/console`,
|
|
94
|
+
{
|
|
95
|
+
method: "POST",
|
|
96
|
+
headers: {
|
|
97
|
+
Authorization:
|
|
98
|
+
`Bearer ${apiKey}`,
|
|
99
|
+
"Content-Type":
|
|
100
|
+
"application/json"
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({
|
|
103
|
+
command
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const json =
|
|
109
|
+
await response.json();
|
|
110
|
+
|
|
111
|
+
if (!json.success) {
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.red(
|
|
114
|
+
json.error ||
|
|
115
|
+
"Command failed."
|
|
116
|
+
)
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
rl.prompt();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const output =
|
|
124
|
+
json.data.output;
|
|
125
|
+
|
|
126
|
+
if (output?.trim()) {
|
|
127
|
+
console.log(
|
|
128
|
+
chalk.gray(output)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
console.log(
|
|
133
|
+
chalk.red(
|
|
134
|
+
"Failed to execute command."
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
rl.prompt();
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
rl.on("close", () => {
|
|
144
|
+
console.log("");
|
|
145
|
+
|
|
146
|
+
console.log(
|
|
147
|
+
chalk.gray("(") +
|
|
148
|
+
chalk.yellow("*") +
|
|
149
|
+
chalk.gray(") Shell closed.")
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
console.log("");
|
|
153
|
+
|
|
154
|
+
process.exit(0);
|
|
155
|
+
});
|
|
156
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { getApiKey } from "../utils/config.js";
|
|
3
|
+
|
|
4
|
+
export default async function start(name) {
|
|
5
|
+
const apiKey = getApiKey();
|
|
6
|
+
|
|
7
|
+
const botsResponse = await fetch(
|
|
8
|
+
"https://api.phanomcloud.online/bots",
|
|
9
|
+
{
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${apiKey}`
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (!botsResponse.ok) {
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const botsJson = await botsResponse.json();
|
|
21
|
+
|
|
22
|
+
if (!botsJson.success) {
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const bot = botsJson.data.find(
|
|
27
|
+
(b) =>
|
|
28
|
+
b.name.toLowerCase() ===
|
|
29
|
+
name.toLowerCase()
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (!bot) {
|
|
33
|
+
console.log(
|
|
34
|
+
chalk.gray("(") +
|
|
35
|
+
chalk.red("!") +
|
|
36
|
+
chalk.gray(") ") +
|
|
37
|
+
chalk.red(`Bot "${name}" not found.`)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const response = await fetch(
|
|
44
|
+
"https://api.phanomcloud.online/bots/start",
|
|
45
|
+
{
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
Authorization: `Bearer ${apiKey}`,
|
|
49
|
+
"Content-Type": "application/json"
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
bot_id: bot.id
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const json = await response.json();
|
|
58
|
+
|
|
59
|
+
if (!json.success) {
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.gray("(") +
|
|
62
|
+
chalk.red("!") +
|
|
63
|
+
chalk.gray(") ") +
|
|
64
|
+
chalk.red(
|
|
65
|
+
json.error ||
|
|
66
|
+
"Failed to start bot."
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.gray("(") +
|
|
75
|
+
chalk.green("*") +
|
|
76
|
+
chalk.gray(") Starting ") +
|
|
77
|
+
chalk.green(bot.name) +
|
|
78
|
+
chalk.gray("...")
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { getApiKey } from "../utils/config.js";
|
|
3
|
+
|
|
4
|
+
export default async function stop(name) {
|
|
5
|
+
const apiKey = getApiKey();
|
|
6
|
+
|
|
7
|
+
const botsResponse = await fetch(
|
|
8
|
+
"https://api.phanomcloud.online/bots",
|
|
9
|
+
{
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `Bearer ${apiKey}`
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (!botsResponse.ok) {
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const botsJson = await botsResponse.json();
|
|
21
|
+
|
|
22
|
+
if (!botsJson.success) {
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const bot = botsJson.data.find(
|
|
27
|
+
(b) =>
|
|
28
|
+
b.name.toLowerCase() ===
|
|
29
|
+
name.toLowerCase()
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (!bot) {
|
|
33
|
+
console.log(
|
|
34
|
+
chalk.gray("(") +
|
|
35
|
+
chalk.red("!") +
|
|
36
|
+
chalk.gray(") ") +
|
|
37
|
+
chalk.red(`Bot "${name}" not found.`)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const response = await fetch(
|
|
44
|
+
"https://api.phanomcloud.online/bots/stop",
|
|
45
|
+
{
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
Authorization: `Bearer ${apiKey}`,
|
|
49
|
+
"Content-Type": "application/json"
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
bot_id: bot.id
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const json = await response.json();
|
|
58
|
+
|
|
59
|
+
if (!json.success) {
|
|
60
|
+
console.log(
|
|
61
|
+
chalk.gray("(") +
|
|
62
|
+
chalk.red("!") +
|
|
63
|
+
chalk.gray(") ") +
|
|
64
|
+
chalk.red(
|
|
65
|
+
json.error ||
|
|
66
|
+
"Failed to stop bot."
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.gray("(") +
|
|
75
|
+
chalk.red("*") +
|
|
76
|
+
chalk.gray(") Stopped ") +
|
|
77
|
+
chalk.red(bot.name) +
|
|
78
|
+
chalk.gray("...")
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import AdmZip from "adm-zip";
|
|
6
|
+
|
|
7
|
+
import { getApiKey } from "../utils/config.js";
|
|
8
|
+
|
|
9
|
+
function parseConfig(content) {
|
|
10
|
+
const lines = content.split("\n");
|
|
11
|
+
|
|
12
|
+
const data = {};
|
|
13
|
+
|
|
14
|
+
for (const line of lines) {
|
|
15
|
+
const parts = line.split("=");
|
|
16
|
+
|
|
17
|
+
const key = parts.shift()?.trim();
|
|
18
|
+
const value = parts.join("=")?.trim();
|
|
19
|
+
|
|
20
|
+
if (!key || !value) continue;
|
|
21
|
+
|
|
22
|
+
data[key] = value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default async function up(filePath) {
|
|
29
|
+
const apiKey = getApiKey();
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(filePath)) {
|
|
32
|
+
console.log(
|
|
33
|
+
chalk.gray("(") +
|
|
34
|
+
chalk.red("!") +
|
|
35
|
+
chalk.gray(") ") +
|
|
36
|
+
chalk.red("File not found.")
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const ext = path.extname(filePath);
|
|
43
|
+
|
|
44
|
+
if (
|
|
45
|
+
ext !== ".zip" &&
|
|
46
|
+
ext !== ".rar"
|
|
47
|
+
) {
|
|
48
|
+
console.log(
|
|
49
|
+
chalk.gray("(") +
|
|
50
|
+
chalk.red("!") +
|
|
51
|
+
chalk.gray(") ") +
|
|
52
|
+
chalk.red(
|
|
53
|
+
"Only .zip and .rar are allowed."
|
|
54
|
+
)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const zip = new AdmZip(filePath);
|
|
61
|
+
|
|
62
|
+
const configEntry =
|
|
63
|
+
zip.getEntry(
|
|
64
|
+
"phanom-compose.config"
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
if (!configEntry) {
|
|
68
|
+
console.log(
|
|
69
|
+
chalk.gray("(") +
|
|
70
|
+
chalk.red("!") +
|
|
71
|
+
chalk.gray(") ") +
|
|
72
|
+
chalk.red(
|
|
73
|
+
"Missing phanom-compose.config"
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const configContent =
|
|
81
|
+
zip
|
|
82
|
+
.readAsText(configEntry)
|
|
83
|
+
.toString();
|
|
84
|
+
|
|
85
|
+
const config =
|
|
86
|
+
parseConfig(configContent);
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
!config.NAME ||
|
|
90
|
+
!config.STARTUP ||
|
|
91
|
+
!config.RAM ||
|
|
92
|
+
!config.RUNTIME
|
|
93
|
+
) {
|
|
94
|
+
console.log(
|
|
95
|
+
chalk.gray("(") +
|
|
96
|
+
chalk.red("!") +
|
|
97
|
+
chalk.gray(") ") +
|
|
98
|
+
chalk.red(
|
|
99
|
+
"Invalid phanom-compose.config"
|
|
100
|
+
)
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log(
|
|
107
|
+
chalk.gray("(") +
|
|
108
|
+
chalk.cyan("*") +
|
|
109
|
+
chalk.gray(") Creating ") +
|
|
110
|
+
chalk.cyan(config.NAME) +
|
|
111
|
+
chalk.gray("...")
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const createResponse =
|
|
115
|
+
await fetch(
|
|
116
|
+
"https://api.phanomcloud.online/bots/create",
|
|
117
|
+
{
|
|
118
|
+
method: "POST",
|
|
119
|
+
headers: {
|
|
120
|
+
Authorization: `Bearer ${apiKey}`,
|
|
121
|
+
"Content-Type":
|
|
122
|
+
"application/json"
|
|
123
|
+
},
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
name: config.NAME,
|
|
126
|
+
language: config.RUNTIME,
|
|
127
|
+
memory: Number(config.RAM),
|
|
128
|
+
startup_command:
|
|
129
|
+
config.STARTUP
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const createJson =
|
|
135
|
+
await createResponse.json();
|
|
136
|
+
|
|
137
|
+
if (!createJson.success) {
|
|
138
|
+
console.log(
|
|
139
|
+
chalk.gray("(") +
|
|
140
|
+
chalk.red("!") +
|
|
141
|
+
chalk.gray(") ") +
|
|
142
|
+
chalk.red(
|
|
143
|
+
createJson.error ||
|
|
144
|
+
"Failed to create bot."
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const botId =
|
|
152
|
+
createJson.data.id;
|
|
153
|
+
|
|
154
|
+
console.log(
|
|
155
|
+
chalk.gray("(") +
|
|
156
|
+
chalk.cyan("*") +
|
|
157
|
+
chalk.gray(") Uploading files...")
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const fileBuffer =
|
|
161
|
+
await fs.promises.readFile(
|
|
162
|
+
filePath
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const blob = new Blob([
|
|
166
|
+
fileBuffer
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
const form = new FormData();
|
|
170
|
+
|
|
171
|
+
form.append(
|
|
172
|
+
"file",
|
|
173
|
+
blob,
|
|
174
|
+
path.basename(filePath)
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
const uploadResponse =
|
|
178
|
+
await fetch(
|
|
179
|
+
`https://api.phanomcloud.online/bots/${botId}/upload`,
|
|
180
|
+
{
|
|
181
|
+
method: "POST",
|
|
182
|
+
headers: {
|
|
183
|
+
Authorization: `Bearer ${apiKey}`
|
|
184
|
+
},
|
|
185
|
+
body: form
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const uploadJson =
|
|
190
|
+
await uploadResponse.json();
|
|
191
|
+
|
|
192
|
+
if (!uploadJson.success) {
|
|
193
|
+
console.log(
|
|
194
|
+
chalk.gray("(") +
|
|
195
|
+
chalk.red("!") +
|
|
196
|
+
chalk.gray(") ") +
|
|
197
|
+
chalk.red(
|
|
198
|
+
uploadJson.error ||
|
|
199
|
+
"Upload failed."
|
|
200
|
+
)
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
console.log(
|
|
207
|
+
chalk.gray("(") +
|
|
208
|
+
chalk.green("*") +
|
|
209
|
+
chalk.gray(") Uploaded ") +
|
|
210
|
+
chalk.green(config.NAME) +
|
|
211
|
+
chalk.gray(".")
|
|
212
|
+
);
|
|
213
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
|
|
4
|
+
import { getApiKey } from "../utils/config.js";
|
|
5
|
+
|
|
6
|
+
export default async function upmemory(
|
|
7
|
+
name
|
|
8
|
+
) {
|
|
9
|
+
const apiKey = getApiKey();
|
|
10
|
+
|
|
11
|
+
const botsResponse = await fetch(
|
|
12
|
+
"https://api.phanomcloud.online/bots",
|
|
13
|
+
{
|
|
14
|
+
headers: {
|
|
15
|
+
Authorization: `Bearer ${apiKey}`
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
if (!botsResponse.ok) {
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const botsJson = await botsResponse.json();
|
|
25
|
+
|
|
26
|
+
if (!botsJson.success) {
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const bot = botsJson.data.find(
|
|
31
|
+
(b) =>
|
|
32
|
+
b.name.toLowerCase() ===
|
|
33
|
+
name.toLowerCase()
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if (!bot) {
|
|
37
|
+
console.log(
|
|
38
|
+
chalk.gray("(") +
|
|
39
|
+
chalk.red("!") +
|
|
40
|
+
chalk.gray(") ") +
|
|
41
|
+
chalk.red(`Bot "${name}" not found.`)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const answers = await inquirer.prompt([
|
|
48
|
+
{
|
|
49
|
+
type: "input",
|
|
50
|
+
name: "memory",
|
|
51
|
+
message:
|
|
52
|
+
chalk.gray("(") +
|
|
53
|
+
chalk.cyan("?") +
|
|
54
|
+
chalk.gray(") ") +
|
|
55
|
+
chalk.gray("Memory (MB): "),
|
|
56
|
+
validate(value) {
|
|
57
|
+
const num = Number(value);
|
|
58
|
+
|
|
59
|
+
if (isNaN(num)) {
|
|
60
|
+
return "Invalid number.";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (num < 64) {
|
|
64
|
+
return "Minimum memory is 64MB.";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
const response = await fetch(
|
|
73
|
+
`https://api.phanomcloud.online/bots/${bot.id}/memory`,
|
|
74
|
+
{
|
|
75
|
+
method: "PATCH",
|
|
76
|
+
headers: {
|
|
77
|
+
Authorization: `Bearer ${apiKey}`,
|
|
78
|
+
"Content-Type": "application/json"
|
|
79
|
+
},
|
|
80
|
+
body: JSON.stringify({
|
|
81
|
+
memory: Number(
|
|
82
|
+
answers.memory
|
|
83
|
+
)
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const json = await response.json();
|
|
89
|
+
|
|
90
|
+
if (!json.success) {
|
|
91
|
+
console.log(
|
|
92
|
+
chalk.gray("(") +
|
|
93
|
+
chalk.red("!") +
|
|
94
|
+
chalk.gray(") ") +
|
|
95
|
+
chalk.red(
|
|
96
|
+
json.error ||
|
|
97
|
+
"Failed to update memory."
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log(
|
|
105
|
+
chalk.gray("(") +
|
|
106
|
+
chalk.green("*") +
|
|
107
|
+
chalk.gray(") Updated ") +
|
|
108
|
+
chalk.green(bot.name) +
|
|
109
|
+
chalk.gray(" to ") +
|
|
110
|
+
chalk.green(
|
|
111
|
+
`${json.data.memory}MB`
|
|
112
|
+
) +
|
|
113
|
+
chalk.gray(".")
|
|
114
|
+
);
|
|
115
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
|
|
3
|
+
import init from "./commands/init.js";
|
|
4
|
+
import ps from "./commands/ps.js";
|
|
5
|
+
import logs from "./commands/logs.js";
|
|
6
|
+
import start from "./commands/start.js";
|
|
7
|
+
import stop from "./commands/stop.js";
|
|
8
|
+
import restart from "./commands/restart.js";
|
|
9
|
+
import upmemory from "./commands/upmemory.js";
|
|
10
|
+
import up from "./commands/up.js";
|
|
11
|
+
import shell from "./commands/shell.js";
|
|
12
|
+
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name("phanom")
|
|
17
|
+
.description("PhanomCloud CLI")
|
|
18
|
+
.version("0.0.1-beta");
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.command("init")
|
|
22
|
+
.description("Create or update your connection")
|
|
23
|
+
.action(init);
|
|
24
|
+
|
|
25
|
+
program
|
|
26
|
+
.command("ps")
|
|
27
|
+
.description("List your bots")
|
|
28
|
+
.option("--a-z", "Sort from A to Z")
|
|
29
|
+
.option("--z-a", "Sort from Z to A")
|
|
30
|
+
.action((opts) =>
|
|
31
|
+
ps({
|
|
32
|
+
aZ: opts["a-z"],
|
|
33
|
+
zA: opts["z-a"]
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
program
|
|
38
|
+
.command("logs <name>")
|
|
39
|
+
.description("Get bot logs")
|
|
40
|
+
.option("--lines <number>")
|
|
41
|
+
.action(logs);
|
|
42
|
+
|
|
43
|
+
program
|
|
44
|
+
.command("start <name>")
|
|
45
|
+
.description("Start a bot")
|
|
46
|
+
.action(start);
|
|
47
|
+
|
|
48
|
+
program
|
|
49
|
+
.command("stop <name>")
|
|
50
|
+
.description("Stop a bot")
|
|
51
|
+
.action(stop);
|
|
52
|
+
|
|
53
|
+
program
|
|
54
|
+
.command("restart <name>")
|
|
55
|
+
.description("Restart a bot")
|
|
56
|
+
.action(restart);
|
|
57
|
+
|
|
58
|
+
program
|
|
59
|
+
.command("upmemory <name>")
|
|
60
|
+
.description("Update bot memory")
|
|
61
|
+
.action(upmemory);
|
|
62
|
+
|
|
63
|
+
program
|
|
64
|
+
.command("up <file>")
|
|
65
|
+
.description("Upload a PhanomCompose package")
|
|
66
|
+
.action(up);
|
|
67
|
+
|
|
68
|
+
program
|
|
69
|
+
.command("shell <target>")
|
|
70
|
+
.description("Execute commands inside a bot")
|
|
71
|
+
.action(shell);
|
|
72
|
+
|
|
73
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
export function getApiKey() {
|
|
6
|
+
const rcPath = path.join(
|
|
7
|
+
os.homedir(),
|
|
8
|
+
".openphanomid.rc"
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
if (!fs.existsSync(rcPath)) {
|
|
12
|
+
console.log("Missing API key.");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const content = fs.readFileSync(
|
|
17
|
+
rcPath,
|
|
18
|
+
"utf8"
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const match = content.match(/API=(.+)/);
|
|
22
|
+
|
|
23
|
+
if (!match) {
|
|
24
|
+
console.log("Invalid config.");
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return match[1].trim();
|
|
29
|
+
}
|