flingit 0.0.11 → 0.0.13
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 +8 -1
- package/dist/cli/commands/db.d.ts +11 -0
- package/dist/cli/commands/db.d.ts.map +1 -1
- package/dist/cli/commands/db.js +60 -48
- package/dist/cli/commands/db.js.map +1 -1
- package/dist/cli/commands/dev.d.ts +9 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +96 -100
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/feedback.d.ts +23 -0
- package/dist/cli/commands/feedback.d.ts.map +1 -1
- package/dist/cli/commands/feedback.js +60 -73
- package/dist/cli/commands/feedback.js.map +1 -1
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +96 -107
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/launch.d.ts +11 -1
- package/dist/cli/commands/launch.d.ts.map +1 -1
- package/dist/cli/commands/launch.js +32 -36
- package/dist/cli/commands/launch.js.map +1 -1
- package/dist/cli/commands/login.d.ts +30 -0
- package/dist/cli/commands/login.d.ts.map +1 -1
- package/dist/cli/commands/login.js +71 -58
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/logs.d.ts +39 -0
- package/dist/cli/commands/logs.d.ts.map +1 -1
- package/dist/cli/commands/logs.js +121 -90
- package/dist/cli/commands/logs.js.map +1 -1
- package/dist/cli/commands/onboard.d.ts +1 -1
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/onboard.js +94 -41
- package/dist/cli/commands/onboard.js.map +1 -1
- package/dist/cli/commands/plugin.d.ts +43 -0
- package/dist/cli/commands/plugin.d.ts.map +1 -1
- package/dist/cli/commands/plugin.js +229 -211
- package/dist/cli/commands/plugin.js.map +1 -1
- package/dist/cli/commands/project.d.ts +27 -0
- package/dist/cli/commands/project.d.ts.map +1 -1
- package/dist/cli/commands/project.js +101 -85
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/push.d.ts +39 -0
- package/dist/cli/commands/push.d.ts.map +1 -1
- package/dist/cli/commands/push.js +152 -118
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/storage.d.ts +32 -0
- package/dist/cli/commands/storage.d.ts.map +1 -1
- package/dist/cli/commands/storage.js +180 -140
- package/dist/cli/commands/storage.js.map +1 -1
- package/dist/cli/commands/tunnel.d.ts +41 -0
- package/dist/cli/commands/tunnel.d.ts.map +1 -0
- package/dist/cli/commands/tunnel.js +210 -0
- package/dist/cli/commands/tunnel.js.map +1 -0
- package/dist/cli/commands/upgrade.d.ts +15 -0
- package/dist/cli/commands/upgrade.d.ts.map +1 -0
- package/dist/cli/commands/upgrade.js +82 -0
- package/dist/cli/commands/upgrade.js.map +1 -0
- package/dist/cli/index.js +35 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/cli-io-impl.d.ts +64 -0
- package/dist/cli/utils/cli-io-impl.d.ts.map +1 -0
- package/dist/cli/utils/cli-io-impl.js +521 -0
- package/dist/cli/utils/cli-io-impl.js.map +1 -0
- package/dist/cli/utils/cli-io.d.ts +350 -0
- package/dist/cli/utils/cli-io.d.ts.map +1 -0
- package/dist/cli/utils/cli-io.js +13 -0
- package/dist/cli/utils/cli-io.js.map +1 -0
- package/dist/cli/utils/config.d.ts +60 -2
- package/dist/cli/utils/config.d.ts.map +1 -1
- package/dist/cli/utils/config.js +158 -37
- package/dist/cli/utils/config.js.map +1 -1
- package/dist/cli/utils/project.d.ts +60 -0
- package/dist/cli/utils/project.d.ts.map +1 -1
- package/dist/cli/utils/project.js +112 -2
- package/dist/cli/utils/project.js.map +1 -1
- package/dist/cli/utils/prompt-new-project.d.ts +7 -3
- package/dist/cli/utils/prompt-new-project.d.ts.map +1 -1
- package/dist/cli/utils/prompt-new-project.js +12 -17
- package/dist/cli/utils/prompt-new-project.js.map +1 -1
- package/dist/cli/utils/registry.d.ts +2 -2
- package/dist/cli/utils/registry.d.ts.map +1 -1
- package/dist/cli/utils/registry.js +13 -3
- package/dist/cli/utils/registry.js.map +1 -1
- package/dist/runtime/log.d.ts.map +1 -1
- package/dist/runtime/log.js +8 -4
- package/dist/runtime/log.js.map +1 -1
- package/dist/runtime/storage.js +1 -1
- package/dist/runtime/storage.js.map +1 -1
- package/package.json +3 -2
- package/templates/default/CLAUDE.md +1 -0
- package/templates/default/skills/fling/.hash +1 -0
- package/templates/default/skills/fling/SKILL.md +12 -4
- /package/templates/default/skills/{discord/SKILL.md → fling/DISCORD.md} +0 -0
|
@@ -4,75 +4,58 @@
|
|
|
4
4
|
* Install, configure, and manage platform plugins like Discord.
|
|
5
5
|
*/
|
|
6
6
|
import { Command } from "commander";
|
|
7
|
-
import { createInterface } from "node:readline";
|
|
8
|
-
import { spawn } from "node:child_process";
|
|
9
7
|
import { isLoggedIn, platformFetch, getApiUrl, getToken } from "../utils/config.js";
|
|
8
|
+
import { consoleIO, processIO, createSimplePromptIO, browserIO, timingIO } from "../utils/cli-io-impl.js";
|
|
10
9
|
const SUPPORTED_PLUGINS = ["discord"];
|
|
10
|
+
// ═══════════════════════════════════════════════════════
|
|
11
|
+
// DEFAULT IMPLEMENTATIONS
|
|
12
|
+
// ═══════════════════════════════════════════════════════
|
|
13
|
+
export function createDefaultPluginDeps() {
|
|
14
|
+
return {
|
|
15
|
+
console: consoleIO,
|
|
16
|
+
process: processIO,
|
|
17
|
+
user: createSimplePromptIO(processIO),
|
|
18
|
+
browser: browserIO,
|
|
19
|
+
timing: timingIO,
|
|
20
|
+
isLoggedIn,
|
|
21
|
+
getToken,
|
|
22
|
+
getApiUrl,
|
|
23
|
+
platformFetch,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export const defaultPluginDeps = createDefaultPluginDeps();
|
|
27
|
+
// ═══════════════════════════════════════════════════════
|
|
28
|
+
// CORE FUNCTIONS (with DI)
|
|
29
|
+
// ═══════════════════════════════════════════════════════
|
|
11
30
|
/**
|
|
12
31
|
* Guard: exit if not logged in.
|
|
13
32
|
*/
|
|
14
|
-
function requireLogin() {
|
|
15
|
-
if (!isLoggedIn()) {
|
|
16
|
-
console.error("Error: Not logged in. Run 'fling login' first.");
|
|
17
|
-
process.exit(1);
|
|
33
|
+
function requireLogin(deps) {
|
|
34
|
+
if (!deps.isLoggedIn()) {
|
|
35
|
+
deps.console.error("Error: Not logged in. Run 'fling login' first.");
|
|
36
|
+
deps.process.exit(1);
|
|
18
37
|
}
|
|
19
38
|
}
|
|
20
39
|
/**
|
|
21
40
|
* Guard: exit if plugin name is not recognized.
|
|
22
41
|
*/
|
|
23
|
-
function requireValidPlugin(plugin) {
|
|
42
|
+
function requireValidPlugin(plugin, deps) {
|
|
24
43
|
if (!SUPPORTED_PLUGINS.includes(plugin)) {
|
|
25
|
-
console.error(`Error: Unknown plugin '${plugin}'.`);
|
|
26
|
-
console.error(`Available plugins: ${SUPPORTED_PLUGINS.join(", ")}`);
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Prompt for input.
|
|
32
|
-
*/
|
|
33
|
-
async function prompt(question) {
|
|
34
|
-
const rl = createInterface({
|
|
35
|
-
input: process.stdin,
|
|
36
|
-
output: process.stdout,
|
|
37
|
-
});
|
|
38
|
-
return new Promise((resolve) => {
|
|
39
|
-
rl.question(question, (answer) => {
|
|
40
|
-
rl.close();
|
|
41
|
-
resolve(answer);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Open a URL in the default browser.
|
|
47
|
-
*/
|
|
48
|
-
function openBrowser(url) {
|
|
49
|
-
const platform = process.platform;
|
|
50
|
-
let command;
|
|
51
|
-
let args;
|
|
52
|
-
if (platform === "darwin") {
|
|
53
|
-
command = "open";
|
|
54
|
-
args = [url];
|
|
55
|
-
}
|
|
56
|
-
else if (platform === "win32") {
|
|
57
|
-
command = "cmd";
|
|
58
|
-
args = ["/c", "start", url];
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
command = "xdg-open";
|
|
62
|
-
args = [url];
|
|
44
|
+
deps.console.error(`Error: Unknown plugin '${plugin}'.`);
|
|
45
|
+
deps.console.error(`Available plugins: ${SUPPORTED_PLUGINS.join(", ")}`);
|
|
46
|
+
deps.process.exit(1);
|
|
63
47
|
}
|
|
64
|
-
spawn(command, args, { detached: true, stdio: "ignore" }).unref();
|
|
65
48
|
}
|
|
66
49
|
/**
|
|
67
50
|
* Wait for Discord OAuth to complete by polling status.
|
|
68
51
|
*/
|
|
69
|
-
async function waitForDiscordOAuth(maxWaitMs = 120000) {
|
|
52
|
+
async function waitForDiscordOAuth(deps, maxWaitMs = 120000) {
|
|
70
53
|
const pollInterval = 2000;
|
|
71
54
|
const maxAttempts = Math.ceil(maxWaitMs / pollInterval);
|
|
72
55
|
for (let i = 0; i < maxAttempts; i++) {
|
|
73
|
-
await
|
|
56
|
+
await deps.timing.sleep(pollInterval);
|
|
74
57
|
try {
|
|
75
|
-
const response = await platformFetch("/discord/status");
|
|
58
|
+
const response = await deps.platformFetch("/discord/status");
|
|
76
59
|
if (response.ok) {
|
|
77
60
|
const data = (await response.json());
|
|
78
61
|
if (data.connected) {
|
|
@@ -86,44 +69,24 @@ async function waitForDiscordOAuth(maxWaitMs = 120000) {
|
|
|
86
69
|
}
|
|
87
70
|
return false;
|
|
88
71
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
fling plugin install discord Install and configure Discord
|
|
97
|
-
fling plugin permissions discord Show Discord permissions/status
|
|
98
|
-
fling plugin remove discord Disconnect Discord
|
|
99
|
-
`);
|
|
100
|
-
// =============================================================================
|
|
101
|
-
// Install Command
|
|
102
|
-
// =============================================================================
|
|
103
|
-
pluginCommand
|
|
104
|
-
.command("install <plugin>")
|
|
105
|
-
.description("Install and configure a plugin")
|
|
106
|
-
.addHelpText("after", `
|
|
107
|
-
Supported plugins:
|
|
108
|
-
discord Connect Discord for chatops
|
|
109
|
-
|
|
110
|
-
Examples:
|
|
111
|
-
fling plugin install discord OAuth with Discord, add bot to server
|
|
112
|
-
`)
|
|
113
|
-
.action(async (plugin) => {
|
|
114
|
-
requireLogin();
|
|
115
|
-
requireValidPlugin(plugin);
|
|
72
|
+
/**
|
|
73
|
+
* Run the plugin install command.
|
|
74
|
+
* Exported for testing with injected dependencies.
|
|
75
|
+
*/
|
|
76
|
+
export async function runPluginInstall(plugin, deps = defaultPluginDeps) {
|
|
77
|
+
requireLogin(deps);
|
|
78
|
+
requireValidPlugin(plugin, deps);
|
|
116
79
|
// Check if already connected
|
|
117
80
|
try {
|
|
118
|
-
const statusRes = await platformFetch("/discord/status");
|
|
81
|
+
const statusRes = await deps.platformFetch("/discord/status");
|
|
119
82
|
if (statusRes.ok) {
|
|
120
83
|
const status = (await statusRes.json());
|
|
121
84
|
if (status.connected) {
|
|
122
|
-
console.log(`Discord already connected as ${status.discordUser?.username}`);
|
|
123
|
-
console.log(`Servers: ${status.servers.map((s) => s.name).join(", ") || "(none claimed)"}`);
|
|
124
|
-
console.log("");
|
|
125
|
-
console.log("To add more servers: fling plugin discord add-server");
|
|
126
|
-
console.log("To reconnect: fling plugin remove discord && fling plugin install discord");
|
|
85
|
+
deps.console.log(`Discord already connected as ${status.discordUser?.username}`);
|
|
86
|
+
deps.console.log(`Servers: ${status.servers.map((s) => s.name).join(", ") || "(none claimed)"}`);
|
|
87
|
+
deps.console.log("");
|
|
88
|
+
deps.console.log("To add more servers: fling plugin discord add-server");
|
|
89
|
+
deps.console.log("To reconnect: fling plugin remove discord && fling plugin install discord");
|
|
127
90
|
return;
|
|
128
91
|
}
|
|
129
92
|
}
|
|
@@ -131,277 +94,332 @@ Examples:
|
|
|
131
94
|
catch {
|
|
132
95
|
// Not connected or endpoint not available
|
|
133
96
|
}
|
|
134
|
-
console.log("Opening Discord authorization...\n");
|
|
97
|
+
deps.console.log("Opening Discord authorization...\n");
|
|
135
98
|
// Open browser to OAuth URL (pass token as query param since browser can't send auth headers).
|
|
136
99
|
// TODO: Replace with a short-lived, single-use exchange token to avoid exposing the
|
|
137
100
|
// long-lived API token in browser history. Flow: CLI POSTs to /discord/oauth/initiate
|
|
138
101
|
// with Authorization header, gets back a single-use code, opens browser with just that code.
|
|
139
|
-
const token = getToken();
|
|
102
|
+
const token = deps.getToken();
|
|
140
103
|
if (!token) {
|
|
141
|
-
console.error("Error: Not logged in. Run 'fling login' first.");
|
|
142
|
-
process.exit(1);
|
|
104
|
+
deps.console.error("Error: Not logged in. Run 'fling login' first.");
|
|
105
|
+
deps.process.exit(1);
|
|
143
106
|
}
|
|
144
|
-
const oauthUrl = `${getApiUrl()}/discord/oauth/authorize?token=${encodeURIComponent(token)}`;
|
|
145
|
-
|
|
146
|
-
console.log("Please complete the authorization in your browser.");
|
|
147
|
-
console.log("Waiting for Discord connection...\n");
|
|
107
|
+
const oauthUrl = `${deps.getApiUrl()}/discord/oauth/authorize?token=${encodeURIComponent(token)}`;
|
|
108
|
+
deps.browser.open(oauthUrl);
|
|
109
|
+
deps.console.log("Please complete the authorization in your browser.");
|
|
110
|
+
deps.console.log("Waiting for Discord connection...\n");
|
|
148
111
|
// Poll for completion
|
|
149
|
-
const connected = await waitForDiscordOAuth();
|
|
112
|
+
const connected = await waitForDiscordOAuth(deps);
|
|
150
113
|
if (!connected) {
|
|
151
|
-
console.error("\nError: OAuth timed out. Please try again.");
|
|
152
|
-
process.exit(1);
|
|
114
|
+
deps.console.error("\nError: OAuth timed out. Please try again.");
|
|
115
|
+
deps.process.exit(1);
|
|
153
116
|
}
|
|
154
117
|
// Get updated status
|
|
155
|
-
const statusRes = await platformFetch("/discord/status");
|
|
118
|
+
const statusRes = await deps.platformFetch("/discord/status");
|
|
156
119
|
const status = (await statusRes.json());
|
|
157
|
-
console.log(`\nConnected as ${status.discordUser?.username}!`);
|
|
120
|
+
deps.console.log(`\nConnected as ${status.discordUser?.username}!`);
|
|
158
121
|
if (status.servers.length > 0) {
|
|
159
|
-
console.log(`Fling Bot joined: ${status.servers.map((s) => s.name).join(", ")}`);
|
|
122
|
+
deps.console.log(`Fling Bot joined: ${status.servers.map((s) => s.name).join(", ")}`);
|
|
160
123
|
}
|
|
161
|
-
console.log("\nTip: You can rename the bot in Server Settings > Members > Right-click Fling Bot > Change Nickname");
|
|
162
|
-
console.log("\nTo add more servers:");
|
|
163
|
-
console.log(" fling plugin discord add-server");
|
|
164
|
-
}
|
|
124
|
+
deps.console.log("\nTip: You can rename the bot in Server Settings > Members > Right-click Fling Bot > Change Nickname");
|
|
125
|
+
deps.console.log("\nTo add more servers:");
|
|
126
|
+
deps.console.log(" fling plugin discord add-server");
|
|
127
|
+
}
|
|
128
|
+
export const pluginCommand = new Command("plugin")
|
|
129
|
+
.description("Manage platform plugins")
|
|
130
|
+
.addHelpText("after", `
|
|
131
|
+
Available plugins:
|
|
132
|
+
discord Discord chatops integration
|
|
133
|
+
|
|
134
|
+
Examples:
|
|
135
|
+
fling plugin install discord Install and configure Discord
|
|
136
|
+
fling plugin permissions discord Show Discord permissions/status
|
|
137
|
+
fling plugin remove discord Disconnect Discord
|
|
138
|
+
`);
|
|
165
139
|
// =============================================================================
|
|
166
|
-
//
|
|
140
|
+
// Install Command
|
|
167
141
|
// =============================================================================
|
|
168
142
|
pluginCommand
|
|
169
|
-
.command("
|
|
170
|
-
.description("
|
|
143
|
+
.command("install <plugin>")
|
|
144
|
+
.description("Install and configure a plugin")
|
|
171
145
|
.addHelpText("after", `
|
|
146
|
+
Supported plugins:
|
|
147
|
+
discord Connect Discord for chatops
|
|
148
|
+
|
|
172
149
|
Examples:
|
|
173
|
-
fling plugin
|
|
150
|
+
fling plugin install discord OAuth with Discord, add bot to server
|
|
174
151
|
`)
|
|
175
152
|
.action(async (plugin) => {
|
|
176
|
-
|
|
177
|
-
|
|
153
|
+
await runPluginInstall(plugin);
|
|
154
|
+
});
|
|
155
|
+
// =============================================================================
|
|
156
|
+
// Permissions Command
|
|
157
|
+
// =============================================================================
|
|
158
|
+
/**
|
|
159
|
+
* Run the plugin permissions command.
|
|
160
|
+
* Exported for testing with injected dependencies.
|
|
161
|
+
*/
|
|
162
|
+
export async function runPluginPermissions(plugin, deps = defaultPluginDeps) {
|
|
163
|
+
requireLogin(deps);
|
|
164
|
+
requireValidPlugin(plugin, deps);
|
|
178
165
|
try {
|
|
179
|
-
const response = await platformFetch("/discord/status");
|
|
166
|
+
const response = await deps.platformFetch("/discord/status");
|
|
180
167
|
if (!response.ok) {
|
|
181
168
|
if (response.status === 503) {
|
|
182
|
-
console.error("Discord plugin is not configured on the platform.");
|
|
183
|
-
process.exit(1);
|
|
169
|
+
deps.console.error("Discord plugin is not configured on the platform.");
|
|
170
|
+
deps.process.exit(1);
|
|
184
171
|
}
|
|
185
172
|
const data = (await response.json());
|
|
186
|
-
console.error(`Error: ${data.error ?? "Failed to get status"}`);
|
|
187
|
-
process.exit(1);
|
|
173
|
+
deps.console.error(`Error: ${data.error ?? "Failed to get status"}`);
|
|
174
|
+
deps.process.exit(1);
|
|
188
175
|
}
|
|
189
176
|
const status = (await response.json());
|
|
190
|
-
console.log("Discord Plugin");
|
|
191
|
-
console.log("──────────────");
|
|
192
|
-
console.log(`Status: ${status.connected ? "Connected" : "Not connected"}`);
|
|
177
|
+
deps.console.log("Discord Plugin");
|
|
178
|
+
deps.console.log("──────────────");
|
|
179
|
+
deps.console.log(`Status: ${status.connected ? "Connected" : "Not connected"}`);
|
|
193
180
|
if (status.discordUser) {
|
|
194
|
-
console.log(`Discord User: ${status.discordUser.username}`);
|
|
181
|
+
deps.console.log(`Discord User: ${status.discordUser.username}`);
|
|
195
182
|
}
|
|
196
|
-
console.log("");
|
|
183
|
+
deps.console.log("");
|
|
197
184
|
if (status.servers.length > 0) {
|
|
198
|
-
console.log("Claimed Servers:");
|
|
185
|
+
deps.console.log("Claimed Servers:");
|
|
199
186
|
for (const server of status.servers) {
|
|
200
187
|
const claimedDate = new Date(server.claimedAt).toLocaleDateString();
|
|
201
|
-
console.log(` • ${server.name} (ID: ${server.id})`);
|
|
202
|
-
console.log(` - Claimed: ${claimedDate}`);
|
|
188
|
+
deps.console.log(` • ${server.name} (ID: ${server.id})`);
|
|
189
|
+
deps.console.log(` - Claimed: ${claimedDate}`);
|
|
203
190
|
}
|
|
204
191
|
}
|
|
205
192
|
else {
|
|
206
|
-
console.log("Claimed Servers: (none)");
|
|
207
|
-
console.log(" Run 'fling plugin discord add-server' to claim a server.");
|
|
193
|
+
deps.console.log("Claimed Servers: (none)");
|
|
194
|
+
deps.console.log(" Run 'fling plugin discord add-server' to claim a server.");
|
|
208
195
|
}
|
|
209
|
-
console.log("");
|
|
210
|
-
console.log("Available APIs:");
|
|
211
|
-
console.log(" discord.sendMessage()");
|
|
212
|
-
console.log(" discord.editMessage()");
|
|
213
|
-
console.log(" discord.addReaction()");
|
|
214
|
-
console.log(" discord.replyToInteraction()");
|
|
215
|
-
console.log(" discord.verifyInteraction()");
|
|
196
|
+
deps.console.log("");
|
|
197
|
+
deps.console.log("Available APIs:");
|
|
198
|
+
deps.console.log(" discord.sendMessage()");
|
|
199
|
+
deps.console.log(" discord.editMessage()");
|
|
200
|
+
deps.console.log(" discord.addReaction()");
|
|
201
|
+
deps.console.log(" discord.replyToInteraction()");
|
|
202
|
+
deps.console.log(" discord.verifyInteraction()");
|
|
216
203
|
}
|
|
217
204
|
catch (error) {
|
|
218
|
-
console.error(`Error: ${error instanceof Error ? error.message : "Failed to get plugin status"}`);
|
|
219
|
-
process.exit(1);
|
|
205
|
+
deps.console.error(`Error: ${error instanceof Error ? error.message : "Failed to get plugin status"}`);
|
|
206
|
+
deps.process.exit(1);
|
|
220
207
|
}
|
|
221
|
-
}
|
|
222
|
-
// =============================================================================
|
|
223
|
-
// Remove Command
|
|
224
|
-
// =============================================================================
|
|
208
|
+
}
|
|
225
209
|
pluginCommand
|
|
226
|
-
.command("
|
|
227
|
-
.description("
|
|
210
|
+
.command("permissions <plugin>")
|
|
211
|
+
.description("Show plugin permissions and status")
|
|
228
212
|
.addHelpText("after", `
|
|
229
213
|
Examples:
|
|
230
|
-
fling plugin
|
|
214
|
+
fling plugin permissions discord Show Discord connection status
|
|
231
215
|
`)
|
|
232
216
|
.action(async (plugin) => {
|
|
233
|
-
|
|
234
|
-
|
|
217
|
+
await runPluginPermissions(plugin);
|
|
218
|
+
});
|
|
219
|
+
// =============================================================================
|
|
220
|
+
// Remove Command
|
|
221
|
+
// =============================================================================
|
|
222
|
+
/**
|
|
223
|
+
* Run the plugin remove command.
|
|
224
|
+
* Exported for testing with injected dependencies.
|
|
225
|
+
*/
|
|
226
|
+
export async function runPluginRemove(plugin, deps = defaultPluginDeps) {
|
|
227
|
+
requireLogin(deps);
|
|
228
|
+
requireValidPlugin(plugin, deps);
|
|
235
229
|
// Get current status
|
|
236
|
-
const statusRes = await platformFetch("/discord/status");
|
|
230
|
+
const statusRes = await deps.platformFetch("/discord/status");
|
|
237
231
|
if (!statusRes.ok) {
|
|
238
|
-
console.log("Discord plugin is not connected.");
|
|
232
|
+
deps.console.log("Discord plugin is not connected.");
|
|
239
233
|
return;
|
|
240
234
|
}
|
|
241
235
|
const status = (await statusRes.json());
|
|
242
236
|
if (!status.connected) {
|
|
243
|
-
console.log("Discord plugin is not connected.");
|
|
237
|
+
deps.console.log("Discord plugin is not connected.");
|
|
244
238
|
return;
|
|
245
239
|
}
|
|
246
240
|
// Confirm removal
|
|
247
241
|
if (status.servers.length > 0) {
|
|
248
|
-
console.log("This will release the following servers:");
|
|
242
|
+
deps.console.log("This will release the following servers:");
|
|
249
243
|
for (const server of status.servers) {
|
|
250
|
-
console.log(` • ${server.name}`);
|
|
244
|
+
deps.console.log(` • ${server.name}`);
|
|
251
245
|
}
|
|
252
|
-
console.log("");
|
|
246
|
+
deps.console.log("");
|
|
253
247
|
}
|
|
254
|
-
const answer = await prompt("Remove Discord plugin? (y/N) ");
|
|
248
|
+
const answer = await deps.user.prompt("Remove Discord plugin? (y/N) ");
|
|
255
249
|
if (answer.toLowerCase() !== "y") {
|
|
256
|
-
console.log("Cancelled.");
|
|
250
|
+
deps.console.log("Cancelled.");
|
|
257
251
|
return;
|
|
258
252
|
}
|
|
259
253
|
// Release all servers
|
|
260
254
|
const failedServers = [];
|
|
261
255
|
for (const server of status.servers) {
|
|
262
256
|
try {
|
|
263
|
-
await platformFetch(`/discord/servers/${server.id}`, {
|
|
257
|
+
await deps.platformFetch(`/discord/servers/${server.id}`, {
|
|
264
258
|
method: "DELETE",
|
|
265
259
|
});
|
|
266
260
|
}
|
|
267
261
|
catch (err) {
|
|
268
|
-
console.error(`Warning: Failed to release server "${server.name}": ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
262
|
+
deps.console.error(`Warning: Failed to release server "${server.name}": ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
269
263
|
failedServers.push(server.name);
|
|
270
264
|
}
|
|
271
265
|
}
|
|
272
266
|
if (failedServers.length > 0) {
|
|
273
|
-
console.log(`\nDiscord plugin removed (${failedServers.length} server(s) could not be released).`);
|
|
267
|
+
deps.console.log(`\nDiscord plugin removed (${failedServers.length} server(s) could not be released).`);
|
|
274
268
|
}
|
|
275
269
|
else {
|
|
276
|
-
console.log("\nDiscord plugin removed.");
|
|
270
|
+
deps.console.log("\nDiscord plugin removed.");
|
|
277
271
|
}
|
|
278
|
-
console.log("Note: Fling Bot will remain in your Discord servers.");
|
|
279
|
-
console.log("You can kick it from Server Settings > Members if desired.");
|
|
272
|
+
deps.console.log("Note: Fling Bot will remain in your Discord servers.");
|
|
273
|
+
deps.console.log("You can kick it from Server Settings > Members if desired.");
|
|
274
|
+
}
|
|
275
|
+
pluginCommand
|
|
276
|
+
.command("remove <plugin>")
|
|
277
|
+
.description("Disconnect and remove a plugin")
|
|
278
|
+
.addHelpText("after", `
|
|
279
|
+
Examples:
|
|
280
|
+
fling plugin remove discord Disconnect Discord, release all servers
|
|
281
|
+
`)
|
|
282
|
+
.action(async (plugin) => {
|
|
283
|
+
await runPluginRemove(plugin);
|
|
280
284
|
});
|
|
281
285
|
// =============================================================================
|
|
282
286
|
// Discord Subcommand
|
|
283
287
|
// =============================================================================
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
requireLogin();
|
|
288
|
+
/**
|
|
289
|
+
* Run the discord add-server command.
|
|
290
|
+
* Exported for testing with injected dependencies.
|
|
291
|
+
*/
|
|
292
|
+
export async function runDiscordAddServer(deps = defaultPluginDeps) {
|
|
293
|
+
requireLogin(deps);
|
|
291
294
|
// Check connection status
|
|
292
|
-
const statusRes = await platformFetch("/discord/status");
|
|
295
|
+
const statusRes = await deps.platformFetch("/discord/status");
|
|
293
296
|
if (!statusRes.ok) {
|
|
294
|
-
console.error("Error: Discord not connected. Run 'fling plugin install discord' first.");
|
|
295
|
-
process.exit(1);
|
|
297
|
+
deps.console.error("Error: Discord not connected. Run 'fling plugin install discord' first.");
|
|
298
|
+
deps.process.exit(1);
|
|
296
299
|
}
|
|
297
300
|
const status = (await statusRes.json());
|
|
298
301
|
if (!status.connected) {
|
|
299
|
-
console.error("Error: Discord not connected. Run 'fling plugin install discord' first.");
|
|
300
|
-
process.exit(1);
|
|
302
|
+
deps.console.error("Error: Discord not connected. Run 'fling plugin install discord' first.");
|
|
303
|
+
deps.process.exit(1);
|
|
301
304
|
}
|
|
302
305
|
// Get available servers
|
|
303
|
-
console.log("Fetching available servers...\n");
|
|
304
|
-
const serversRes = await platformFetch("/discord/servers");
|
|
306
|
+
deps.console.log("Fetching available servers...\n");
|
|
307
|
+
const serversRes = await deps.platformFetch("/discord/servers");
|
|
305
308
|
if (!serversRes.ok) {
|
|
306
309
|
const data = (await serversRes.json());
|
|
307
|
-
console.error(`Error: ${data.error ?? "Failed to fetch servers"}`);
|
|
308
|
-
process.exit(1);
|
|
310
|
+
deps.console.error(`Error: ${data.error ?? "Failed to fetch servers"}`);
|
|
311
|
+
deps.process.exit(1);
|
|
309
312
|
}
|
|
310
313
|
const { servers } = (await serversRes.json());
|
|
311
314
|
// Filter to unclaimed servers
|
|
312
315
|
const available = servers.filter((s) => !s.claimed);
|
|
313
316
|
const alreadyClaimed = servers.filter((s) => s.claimedByMe);
|
|
314
317
|
if (alreadyClaimed.length > 0) {
|
|
315
|
-
console.log("Already claimed by this project:");
|
|
318
|
+
deps.console.log("Already claimed by this project:");
|
|
316
319
|
for (const s of alreadyClaimed) {
|
|
317
|
-
console.log(` • ${s.name}`);
|
|
320
|
+
deps.console.log(` • ${s.name}`);
|
|
318
321
|
}
|
|
319
|
-
console.log("");
|
|
322
|
+
deps.console.log("");
|
|
320
323
|
}
|
|
321
324
|
if (available.length === 0) {
|
|
322
|
-
console.log("No available servers to claim.");
|
|
323
|
-
console.log("\nTo add Fling Bot to a new server:");
|
|
324
|
-
console.log(" 1. Go to Discord and open Server Settings > Integrations");
|
|
325
|
-
console.log(" 2. Add the Fling Bot application");
|
|
326
|
-
console.log(" 3. Run this command again");
|
|
325
|
+
deps.console.log("No available servers to claim.");
|
|
326
|
+
deps.console.log("\nTo add Fling Bot to a new server:");
|
|
327
|
+
deps.console.log(" 1. Go to Discord and open Server Settings > Integrations");
|
|
328
|
+
deps.console.log(" 2. Add the Fling Bot application");
|
|
329
|
+
deps.console.log(" 3. Run this command again");
|
|
327
330
|
return;
|
|
328
331
|
}
|
|
329
|
-
console.log("Available servers:");
|
|
332
|
+
deps.console.log("Available servers:");
|
|
330
333
|
for (let i = 0; i < available.length; i++) {
|
|
331
334
|
const s = available[i];
|
|
332
335
|
if (s) {
|
|
333
|
-
console.log(` ${i + 1}. ${s.name}`);
|
|
336
|
+
deps.console.log(` ${i + 1}. ${s.name}`);
|
|
334
337
|
}
|
|
335
338
|
}
|
|
336
|
-
console.log("");
|
|
337
|
-
const choice = await prompt(`Select server (1-${available.length}): `);
|
|
339
|
+
deps.console.log("");
|
|
340
|
+
const choice = await deps.user.prompt(`Select server (1-${available.length}): `);
|
|
338
341
|
const idx = parseInt(choice, 10) - 1;
|
|
339
342
|
const server = available[idx];
|
|
340
343
|
if (!server) {
|
|
341
|
-
console.error("Invalid selection.");
|
|
342
|
-
process.exit(1);
|
|
344
|
+
deps.console.error("Invalid selection.");
|
|
345
|
+
deps.process.exit(1);
|
|
343
346
|
}
|
|
344
347
|
// Claim the server
|
|
345
|
-
const claimRes = await platformFetch(`/discord/servers/${server.id}/claim`, {
|
|
348
|
+
const claimRes = await deps.platformFetch(`/discord/servers/${server.id}/claim`, {
|
|
346
349
|
method: "POST",
|
|
347
350
|
headers: { "Content-Type": "application/json" },
|
|
348
351
|
body: JSON.stringify({ guildName: server.name }),
|
|
349
352
|
});
|
|
350
353
|
if (!claimRes.ok) {
|
|
351
354
|
const data = (await claimRes.json());
|
|
352
|
-
console.error(`Error: ${data.error ?? "Failed to claim server"}`);
|
|
353
|
-
process.exit(1);
|
|
355
|
+
deps.console.error(`Error: ${data.error ?? "Failed to claim server"}`);
|
|
356
|
+
deps.process.exit(1);
|
|
354
357
|
}
|
|
355
|
-
console.log(`\nServer "${server.name}" claimed successfully!`);
|
|
356
|
-
console.log("\nYour slash commands will be registered when you run 'fling push'.");
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
358
|
+
deps.console.log(`\nServer "${server.name}" claimed successfully!`);
|
|
359
|
+
deps.console.log("\nYour slash commands will be registered when you run 'fling push'.");
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Run the discord remove-server command.
|
|
363
|
+
* Exported for testing with injected dependencies.
|
|
364
|
+
*/
|
|
365
|
+
export async function runDiscordRemoveServer(deps = defaultPluginDeps) {
|
|
366
|
+
requireLogin(deps);
|
|
363
367
|
// Get current status
|
|
364
|
-
const statusRes = await platformFetch("/discord/status");
|
|
368
|
+
const statusRes = await deps.platformFetch("/discord/status");
|
|
365
369
|
if (!statusRes.ok) {
|
|
366
|
-
console.error("Error: Discord not connected.");
|
|
367
|
-
process.exit(1);
|
|
370
|
+
deps.console.error("Error: Discord not connected.");
|
|
371
|
+
deps.process.exit(1);
|
|
368
372
|
}
|
|
369
373
|
const status = (await statusRes.json());
|
|
370
374
|
if (status.servers.length === 0) {
|
|
371
|
-
console.log("No servers claimed.");
|
|
375
|
+
deps.console.log("No servers claimed.");
|
|
372
376
|
return;
|
|
373
377
|
}
|
|
374
|
-
console.log("Claimed servers:");
|
|
378
|
+
deps.console.log("Claimed servers:");
|
|
375
379
|
for (let i = 0; i < status.servers.length; i++) {
|
|
376
380
|
const s = status.servers[i];
|
|
377
381
|
if (s) {
|
|
378
|
-
console.log(` ${i + 1}. ${s.name}`);
|
|
382
|
+
deps.console.log(` ${i + 1}. ${s.name}`);
|
|
379
383
|
}
|
|
380
384
|
}
|
|
381
|
-
console.log("");
|
|
382
|
-
const choice = await prompt(`Select server to remove (1-${status.servers.length}): `);
|
|
385
|
+
deps.console.log("");
|
|
386
|
+
const choice = await deps.user.prompt(`Select server to remove (1-${status.servers.length}): `);
|
|
383
387
|
const idx = parseInt(choice, 10) - 1;
|
|
384
388
|
const server = status.servers[idx];
|
|
385
389
|
if (!server) {
|
|
386
|
-
console.error("Invalid selection.");
|
|
387
|
-
process.exit(1);
|
|
390
|
+
deps.console.error("Invalid selection.");
|
|
391
|
+
deps.process.exit(1);
|
|
388
392
|
}
|
|
389
|
-
const confirm = await prompt(`Remove "${server.name}"? (y/N) `);
|
|
393
|
+
const confirm = await deps.user.prompt(`Remove "${server.name}"? (y/N) `);
|
|
390
394
|
if (confirm.toLowerCase() !== "y") {
|
|
391
|
-
console.log("Cancelled.");
|
|
395
|
+
deps.console.log("Cancelled.");
|
|
392
396
|
return;
|
|
393
397
|
}
|
|
394
398
|
// Remove the server
|
|
395
|
-
const removeRes = await platformFetch(`/discord/servers/${server.id}`, {
|
|
399
|
+
const removeRes = await deps.platformFetch(`/discord/servers/${server.id}`, {
|
|
396
400
|
method: "DELETE",
|
|
397
401
|
});
|
|
398
402
|
if (!removeRes.ok) {
|
|
399
403
|
const data = (await removeRes.json());
|
|
400
|
-
console.error(`Error: ${data.error ?? "Failed to remove server"}`);
|
|
401
|
-
process.exit(1);
|
|
404
|
+
deps.console.error(`Error: ${data.error ?? "Failed to remove server"}`);
|
|
405
|
+
deps.process.exit(1);
|
|
402
406
|
}
|
|
403
|
-
console.log(`\nServer "${server.name}" removed.`);
|
|
404
|
-
console.log("Slash commands have been unregistered from this server.");
|
|
407
|
+
deps.console.log(`\nServer "${server.name}" removed.`);
|
|
408
|
+
deps.console.log("Slash commands have been unregistered from this server.");
|
|
409
|
+
}
|
|
410
|
+
const discordSubcommand = new Command("discord")
|
|
411
|
+
.description("Discord-specific plugin commands");
|
|
412
|
+
discordSubcommand
|
|
413
|
+
.command("add-server")
|
|
414
|
+
.description("Add another Discord server to your project")
|
|
415
|
+
.action(async () => {
|
|
416
|
+
await runDiscordAddServer();
|
|
417
|
+
});
|
|
418
|
+
discordSubcommand
|
|
419
|
+
.command("remove-server")
|
|
420
|
+
.description("Remove a Discord server from your project")
|
|
421
|
+
.action(async () => {
|
|
422
|
+
await runDiscordRemoveServer();
|
|
405
423
|
});
|
|
406
424
|
pluginCommand.addCommand(discordSubcommand);
|
|
407
425
|
//# sourceMappingURL=plugin.js.map
|