@byfungsi/funforge 0.2.3 → 0.4.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/dist/__tests__/mcp.test.js +13 -1
- package/dist/api.d.ts +38 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +54 -0
- package/dist/cli.js +22 -1
- package/dist/commands/apps.d.ts +8 -0
- package/dist/commands/apps.d.ts.map +1 -1
- package/dist/commands/apps.js +49 -1
- package/dist/commands/control.d.ts +26 -0
- package/dist/commands/control.d.ts.map +1 -0
- package/dist/commands/control.js +91 -0
- package/dist/commands/deploy.js +8 -3
- package/dist/mcp.js +225 -1
- package/package.json +3 -12
|
@@ -124,19 +124,31 @@ describe("MCP Integration", () => {
|
|
|
124
124
|
"funforge_whoami",
|
|
125
125
|
"funforge_apps_list",
|
|
126
126
|
"funforge_apps_create",
|
|
127
|
+
"funforge_apps_delete",
|
|
127
128
|
"funforge_status",
|
|
128
129
|
"funforge_deploy",
|
|
130
|
+
"funforge_stop",
|
|
131
|
+
"funforge_start",
|
|
132
|
+
"funforge_cancel",
|
|
129
133
|
"funforge_env_list",
|
|
130
134
|
"funforge_env_set",
|
|
131
135
|
"funforge_env_unset",
|
|
132
136
|
"funforge_domains_list",
|
|
133
137
|
"funforge_domains_add",
|
|
138
|
+
"funforge_domains_remove",
|
|
139
|
+
"funforge_domains_verify",
|
|
134
140
|
];
|
|
135
141
|
it("should define all expected tools", () => {
|
|
136
142
|
// This is a documentation test to ensure we have all tools
|
|
137
|
-
expect(expectedTools).toHaveLength(
|
|
143
|
+
expect(expectedTools).toHaveLength(16);
|
|
138
144
|
expect(expectedTools).toContain("funforge_deploy");
|
|
139
145
|
expect(expectedTools).toContain("funforge_whoami");
|
|
146
|
+
expect(expectedTools).toContain("funforge_stop");
|
|
147
|
+
expect(expectedTools).toContain("funforge_start");
|
|
148
|
+
expect(expectedTools).toContain("funforge_cancel");
|
|
149
|
+
expect(expectedTools).toContain("funforge_apps_delete");
|
|
150
|
+
expect(expectedTools).toContain("funforge_domains_remove");
|
|
151
|
+
expect(expectedTools).toContain("funforge_domains_verify");
|
|
140
152
|
});
|
|
141
153
|
});
|
|
142
154
|
});
|
package/dist/api.d.ts
CHANGED
|
@@ -154,5 +154,43 @@ export declare function getDeployment(deploymentId: string): Promise<{
|
|
|
154
154
|
* Stream deployment logs (returns EventSource URL)
|
|
155
155
|
*/
|
|
156
156
|
export declare function getDeploymentLogsUrl(deploymentId: string): string;
|
|
157
|
+
/**
|
|
158
|
+
* Stop the current deployment for an app
|
|
159
|
+
*/
|
|
160
|
+
export declare function stopDeployment(appId: string): Promise<{
|
|
161
|
+
success: boolean;
|
|
162
|
+
}>;
|
|
163
|
+
/**
|
|
164
|
+
* Start a stopped deployment for an app
|
|
165
|
+
*/
|
|
166
|
+
export declare function startDeployment(appId: string): Promise<{
|
|
167
|
+
success: boolean;
|
|
168
|
+
}>;
|
|
169
|
+
/**
|
|
170
|
+
* Cancel an in-progress deployment
|
|
171
|
+
*/
|
|
172
|
+
export declare function cancelDeployment(appId: string): Promise<{
|
|
173
|
+
success: boolean;
|
|
174
|
+
}>;
|
|
175
|
+
/**
|
|
176
|
+
* Delete an app
|
|
177
|
+
*/
|
|
178
|
+
export declare function deleteApp(appId: string): Promise<{
|
|
179
|
+
success: boolean;
|
|
180
|
+
}>;
|
|
181
|
+
/**
|
|
182
|
+
* Remove a custom domain from an app
|
|
183
|
+
*/
|
|
184
|
+
export declare function removeDomain(appId: string, domainId: string): Promise<{
|
|
185
|
+
success: boolean;
|
|
186
|
+
}>;
|
|
187
|
+
/**
|
|
188
|
+
* Verify DNS and provision SSL for a domain
|
|
189
|
+
*/
|
|
190
|
+
export declare function verifyDomain(appId: string, domainId: string): Promise<{
|
|
191
|
+
verified: boolean;
|
|
192
|
+
sslStatus?: string;
|
|
193
|
+
message?: string;
|
|
194
|
+
}>;
|
|
157
195
|
export {};
|
|
158
196
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/dist/api.js
CHANGED
|
@@ -208,3 +208,57 @@ export function getDeploymentLogsUrl(deploymentId) {
|
|
|
208
208
|
const apiKey = getApiKey();
|
|
209
209
|
return `${config.apiUrl}/api/cli/deployments/${deploymentId}/logs?token=${apiKey}`;
|
|
210
210
|
}
|
|
211
|
+
// ============================================
|
|
212
|
+
// DEPLOYMENT CONTROL ENDPOINTS
|
|
213
|
+
// ============================================
|
|
214
|
+
/**
|
|
215
|
+
* Stop the current deployment for an app
|
|
216
|
+
*/
|
|
217
|
+
export async function stopDeployment(appId) {
|
|
218
|
+
return apiRequest(`/api/cli/apps/${appId}/stop`, {
|
|
219
|
+
method: "POST",
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Start a stopped deployment for an app
|
|
224
|
+
*/
|
|
225
|
+
export async function startDeployment(appId) {
|
|
226
|
+
return apiRequest(`/api/cli/apps/${appId}/start`, {
|
|
227
|
+
method: "POST",
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Cancel an in-progress deployment
|
|
232
|
+
*/
|
|
233
|
+
export async function cancelDeployment(appId) {
|
|
234
|
+
return apiRequest(`/api/cli/apps/${appId}/cancel`, {
|
|
235
|
+
method: "POST",
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Delete an app
|
|
240
|
+
*/
|
|
241
|
+
export async function deleteApp(appId) {
|
|
242
|
+
return apiRequest(`/api/cli/apps/${appId}`, {
|
|
243
|
+
method: "DELETE",
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
// ============================================
|
|
247
|
+
// DOMAIN ENDPOINTS
|
|
248
|
+
// ============================================
|
|
249
|
+
/**
|
|
250
|
+
* Remove a custom domain from an app
|
|
251
|
+
*/
|
|
252
|
+
export async function removeDomain(appId, domainId) {
|
|
253
|
+
return apiRequest(`/api/cli/apps/${appId}/domains/${domainId}`, {
|
|
254
|
+
method: "DELETE",
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Verify DNS and provision SSL for a domain
|
|
259
|
+
*/
|
|
260
|
+
export async function verifyDomain(appId, domainId) {
|
|
261
|
+
return apiRequest(`/api/cli/apps/${appId}/domains/${domainId}/verify`, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
});
|
|
264
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -10,10 +10,11 @@ import { Command } from "commander";
|
|
|
10
10
|
// Load version from package.json
|
|
11
11
|
const require = createRequire(import.meta.url);
|
|
12
12
|
const pkg = require("../package.json");
|
|
13
|
-
import { appsCreateCommand, appsListCommand, linkCommand, } from "./commands/apps.js";
|
|
13
|
+
import { appsCreateCommand, appsDeleteCommand, appsListCommand, linkCommand, } from "./commands/apps.js";
|
|
14
14
|
// Import commands
|
|
15
15
|
import { loginCommand, logoutCommand, whoamiCommand } from "./commands/auth.js";
|
|
16
16
|
import { configPullCommand, configPushCommand, configShowCommand, } from "./commands/config.js";
|
|
17
|
+
import { cancelCommand, startCommand, stopCommand, } from "./commands/control.js";
|
|
17
18
|
import { deployCommand } from "./commands/deploy.js";
|
|
18
19
|
import { domainsAddCommand, domainsListCommand, domainsRemoveCommand, domainsVerifyCommand, } from "./commands/domains.js";
|
|
19
20
|
import { envListCommand, envSetCommand, envUnsetCommand, } from "./commands/env.js";
|
|
@@ -49,6 +50,11 @@ appsCmd
|
|
|
49
50
|
.option("-s, --slug <slug>", "Custom slug (subdomain)")
|
|
50
51
|
.option("-t, --tier <tier>", "Tier key (e.g., cost-optimized.small)")
|
|
51
52
|
.action(appsCreateCommand);
|
|
53
|
+
appsCmd
|
|
54
|
+
.command("delete <appId>")
|
|
55
|
+
.description("Delete an app")
|
|
56
|
+
.option("-y, --yes", "Skip confirmation prompt")
|
|
57
|
+
.action(appsDeleteCommand);
|
|
52
58
|
program
|
|
53
59
|
.command("link [appId]")
|
|
54
60
|
.description("Link current directory to an app")
|
|
@@ -63,6 +69,21 @@ program
|
|
|
63
69
|
.option("--no-watch", "Don't watch deployment logs")
|
|
64
70
|
.action(deployCommand);
|
|
65
71
|
// ============================================
|
|
72
|
+
// DEPLOYMENT CONTROL COMMANDS
|
|
73
|
+
// ============================================
|
|
74
|
+
program
|
|
75
|
+
.command("stop")
|
|
76
|
+
.description("Stop the current deployment")
|
|
77
|
+
.action(stopCommand);
|
|
78
|
+
program
|
|
79
|
+
.command("start")
|
|
80
|
+
.description("Start a stopped deployment")
|
|
81
|
+
.action(startCommand);
|
|
82
|
+
program
|
|
83
|
+
.command("cancel")
|
|
84
|
+
.description("Cancel an in-progress deployment")
|
|
85
|
+
.action(cancelCommand);
|
|
86
|
+
// ============================================
|
|
66
87
|
// ENVIRONMENT VARIABLES
|
|
67
88
|
// ============================================
|
|
68
89
|
const envCmd = program
|
package/dist/commands/apps.d.ts
CHANGED
|
@@ -27,4 +27,12 @@ export declare function appsCreateCommand(name: string, options: {
|
|
|
27
27
|
* If no appId provided, shows interactive selector.
|
|
28
28
|
*/
|
|
29
29
|
export declare function linkCommand(appId?: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* funforge apps delete <appId>
|
|
32
|
+
*
|
|
33
|
+
* Delete an app (requires confirmation).
|
|
34
|
+
*/
|
|
35
|
+
export declare function appsDeleteCommand(appId: string, options: {
|
|
36
|
+
yes?: boolean;
|
|
37
|
+
}): Promise<void>;
|
|
30
38
|
//# sourceMappingURL=apps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/commands/apps.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAgCrD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,IAAI,CAAC,CAyCf;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D/D;AAaD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB,OAAO,CAAC,IAAI,CAAC,CA8Cf"}
|
package/dist/commands/apps.js
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* - apps create: Create a new app (with interactive tier selection)
|
|
6
6
|
* - link: Link current directory to an app
|
|
7
7
|
*/
|
|
8
|
+
import { confirm } from "@inquirer/prompts";
|
|
8
9
|
import chalk from "chalk";
|
|
9
10
|
import ora from "ora";
|
|
10
|
-
import { createApp, getApp, listApps } from "../api.js";
|
|
11
|
+
import { createApp, deleteApp, getApp, listApps } from "../api.js";
|
|
11
12
|
import { isAuthenticated } from "../credentials.js";
|
|
12
13
|
import { handleError } from "../errors.js";
|
|
13
14
|
import { readConfig, updateConfig } from "../project-config.js";
|
|
@@ -151,3 +152,50 @@ function requireAuth() {
|
|
|
151
152
|
process.exit(1);
|
|
152
153
|
}
|
|
153
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* funforge apps delete <appId>
|
|
157
|
+
*
|
|
158
|
+
* Delete an app (requires confirmation).
|
|
159
|
+
*/
|
|
160
|
+
export async function appsDeleteCommand(appId, options) {
|
|
161
|
+
requireAuth();
|
|
162
|
+
// Get app info first
|
|
163
|
+
const infoSpinner = ora("Fetching app info...").start();
|
|
164
|
+
let app;
|
|
165
|
+
try {
|
|
166
|
+
const result = await getApp(appId);
|
|
167
|
+
app = result.app;
|
|
168
|
+
infoSpinner.stop();
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
infoSpinner.fail("Failed to fetch app");
|
|
172
|
+
handleError(error);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
console.log();
|
|
176
|
+
console.log(chalk.bold("App to delete:"));
|
|
177
|
+
console.log(` Name: ${app.name}`);
|
|
178
|
+
console.log(` Slug: ${chalk.cyan(app.slug)}`);
|
|
179
|
+
console.log(` ID: ${app.id}`);
|
|
180
|
+
console.log();
|
|
181
|
+
// Confirm deletion
|
|
182
|
+
if (!options.yes) {
|
|
183
|
+
const confirmed = await confirm({
|
|
184
|
+
message: `Are you sure you want to delete "${app.name}"? This cannot be undone.`,
|
|
185
|
+
default: false,
|
|
186
|
+
});
|
|
187
|
+
if (!confirmed) {
|
|
188
|
+
console.log(chalk.gray("Deletion canceled."));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const deleteSpinner = ora(`Deleting ${app.name}...`).start();
|
|
193
|
+
try {
|
|
194
|
+
await deleteApp(appId);
|
|
195
|
+
deleteSpinner.succeed(`App "${app.name}" deleted`);
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
deleteSpinner.fail("Failed to delete app");
|
|
199
|
+
handleError(error);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment Control Commands
|
|
3
|
+
*
|
|
4
|
+
* - stop: Stop the current deployment
|
|
5
|
+
* - start: Start a stopped deployment
|
|
6
|
+
* - cancel: Cancel an in-progress deployment
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* funforge stop
|
|
10
|
+
*
|
|
11
|
+
* Stop the current deployment for the linked app.
|
|
12
|
+
*/
|
|
13
|
+
export declare function stopCommand(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* funforge start
|
|
16
|
+
*
|
|
17
|
+
* Start a stopped deployment for the linked app.
|
|
18
|
+
*/
|
|
19
|
+
export declare function startCommand(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* funforge cancel
|
|
22
|
+
*
|
|
23
|
+
* Cancel an in-progress deployment for the linked app.
|
|
24
|
+
*/
|
|
25
|
+
export declare function cancelCommand(): Promise<void>;
|
|
26
|
+
//# sourceMappingURL=control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../../src/commands/control.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH;;;;GAIG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAejD;AAED;;;;GAIG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAalD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAanD"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deployment Control Commands
|
|
3
|
+
*
|
|
4
|
+
* - stop: Stop the current deployment
|
|
5
|
+
* - start: Start a stopped deployment
|
|
6
|
+
* - cancel: Cancel an in-progress deployment
|
|
7
|
+
*/
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import ora from "ora";
|
|
10
|
+
import { cancelDeployment, startDeployment, stopDeployment } from "../api.js";
|
|
11
|
+
import { isAuthenticated } from "../credentials.js";
|
|
12
|
+
import { handleError } from "../errors.js";
|
|
13
|
+
import { readConfig } from "../project-config.js";
|
|
14
|
+
/**
|
|
15
|
+
* funforge stop
|
|
16
|
+
*
|
|
17
|
+
* Stop the current deployment for the linked app.
|
|
18
|
+
*/
|
|
19
|
+
export async function stopCommand() {
|
|
20
|
+
requireAuth();
|
|
21
|
+
const appId = await getLinkedAppId();
|
|
22
|
+
const spinner = ora("Stopping deployment...").start();
|
|
23
|
+
try {
|
|
24
|
+
await stopDeployment(appId);
|
|
25
|
+
spinner.succeed("Deployment stopped");
|
|
26
|
+
console.log();
|
|
27
|
+
console.log(chalk.gray("Use `funforge start` to restart the deployment"));
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
spinner.fail("Failed to stop deployment");
|
|
31
|
+
handleError(error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* funforge start
|
|
36
|
+
*
|
|
37
|
+
* Start a stopped deployment for the linked app.
|
|
38
|
+
*/
|
|
39
|
+
export async function startCommand() {
|
|
40
|
+
requireAuth();
|
|
41
|
+
const appId = await getLinkedAppId();
|
|
42
|
+
const spinner = ora("Starting deployment...").start();
|
|
43
|
+
try {
|
|
44
|
+
await startDeployment(appId);
|
|
45
|
+
spinner.succeed("Deployment started");
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
spinner.fail("Failed to start deployment");
|
|
49
|
+
handleError(error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* funforge cancel
|
|
54
|
+
*
|
|
55
|
+
* Cancel an in-progress deployment for the linked app.
|
|
56
|
+
*/
|
|
57
|
+
export async function cancelCommand() {
|
|
58
|
+
requireAuth();
|
|
59
|
+
const appId = await getLinkedAppId();
|
|
60
|
+
const spinner = ora("Canceling deployment...").start();
|
|
61
|
+
try {
|
|
62
|
+
await cancelDeployment(appId);
|
|
63
|
+
spinner.succeed("Deployment canceled");
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
spinner.fail("Failed to cancel deployment");
|
|
67
|
+
handleError(error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the linked app ID or exit
|
|
72
|
+
*/
|
|
73
|
+
async function getLinkedAppId() {
|
|
74
|
+
const config = await readConfig();
|
|
75
|
+
if (!config?.appId) {
|
|
76
|
+
console.log(chalk.red("Not linked to an app."));
|
|
77
|
+
console.log(chalk.gray("Run `funforge link <app-id>` first."));
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
return config.appId;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if user is authenticated, exit if not
|
|
84
|
+
*/
|
|
85
|
+
function requireAuth() {
|
|
86
|
+
if (!isAuthenticated()) {
|
|
87
|
+
console.log(chalk.red("Not authenticated."));
|
|
88
|
+
console.log(chalk.gray("Run `funforge login` first."));
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -99,7 +99,7 @@ export async function deployCommand(options = {}) {
|
|
|
99
99
|
console.log();
|
|
100
100
|
// 6. Watch logs if requested
|
|
101
101
|
if (options.watch !== false) {
|
|
102
|
-
await watchDeployment(deployResult.deployment.id);
|
|
102
|
+
await watchDeployment(deployResult.deployment.id, config.appSlug);
|
|
103
103
|
}
|
|
104
104
|
else {
|
|
105
105
|
console.log(chalk.gray("Run with --watch to follow logs"));
|
|
@@ -108,7 +108,7 @@ export async function deployCommand(options = {}) {
|
|
|
108
108
|
/**
|
|
109
109
|
* Watch deployment status until completion
|
|
110
110
|
*/
|
|
111
|
-
async function watchDeployment(deploymentId) {
|
|
111
|
+
async function watchDeployment(deploymentId, appSlug) {
|
|
112
112
|
console.log(chalk.gray("Watching deployment..."));
|
|
113
113
|
console.log();
|
|
114
114
|
const spinner = ora("Building...").start();
|
|
@@ -123,7 +123,12 @@ async function watchDeployment(deploymentId) {
|
|
|
123
123
|
if (deployment.status === "live") {
|
|
124
124
|
spinner.succeed(chalk.green("Deployment live!"));
|
|
125
125
|
console.log();
|
|
126
|
-
//
|
|
126
|
+
// Show deployment URL
|
|
127
|
+
if (appSlug) {
|
|
128
|
+
console.log(chalk.bold("Your app is live at:"));
|
|
129
|
+
console.log(` ${chalk.cyan(`https://sarana-${appSlug}.funforge.app`)}`);
|
|
130
|
+
console.log();
|
|
131
|
+
}
|
|
127
132
|
return;
|
|
128
133
|
}
|
|
129
134
|
if (deployment.status === "failed" || deployment.status === "canceled") {
|
package/dist/mcp.js
CHANGED
|
@@ -195,6 +195,98 @@ const TOOLS = [
|
|
|
195
195
|
required: ["domain"],
|
|
196
196
|
},
|
|
197
197
|
},
|
|
198
|
+
{
|
|
199
|
+
name: "funforge_domains_remove",
|
|
200
|
+
description: "Remove a custom domain from the linked app.",
|
|
201
|
+
inputSchema: {
|
|
202
|
+
type: "object",
|
|
203
|
+
properties: {
|
|
204
|
+
directory: {
|
|
205
|
+
type: "string",
|
|
206
|
+
description: "Directory with funforge.json (defaults to cwd)",
|
|
207
|
+
},
|
|
208
|
+
domain: {
|
|
209
|
+
type: "string",
|
|
210
|
+
description: "Domain name or domain ID to remove",
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
required: ["domain"],
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: "funforge_domains_verify",
|
|
218
|
+
description: "Verify DNS configuration and provision SSL for a custom domain.",
|
|
219
|
+
inputSchema: {
|
|
220
|
+
type: "object",
|
|
221
|
+
properties: {
|
|
222
|
+
directory: {
|
|
223
|
+
type: "string",
|
|
224
|
+
description: "Directory with funforge.json (defaults to cwd)",
|
|
225
|
+
},
|
|
226
|
+
domain: {
|
|
227
|
+
type: "string",
|
|
228
|
+
description: "Domain name or domain ID to verify",
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
required: ["domain"],
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "funforge_stop",
|
|
236
|
+
description: "Stop the current deployment for the linked app. The app will be scaled down to 0 replicas.",
|
|
237
|
+
inputSchema: {
|
|
238
|
+
type: "object",
|
|
239
|
+
properties: {
|
|
240
|
+
directory: {
|
|
241
|
+
type: "string",
|
|
242
|
+
description: "Directory with funforge.json (defaults to cwd)",
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
required: [],
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
name: "funforge_start",
|
|
250
|
+
description: "Start a stopped deployment for the linked app. Scales the app back up.",
|
|
251
|
+
inputSchema: {
|
|
252
|
+
type: "object",
|
|
253
|
+
properties: {
|
|
254
|
+
directory: {
|
|
255
|
+
type: "string",
|
|
256
|
+
description: "Directory with funforge.json (defaults to cwd)",
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
required: [],
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: "funforge_cancel",
|
|
264
|
+
description: "Cancel an in-progress deployment for the linked app. Use this to abort a build or deployment that is stuck.",
|
|
265
|
+
inputSchema: {
|
|
266
|
+
type: "object",
|
|
267
|
+
properties: {
|
|
268
|
+
directory: {
|
|
269
|
+
type: "string",
|
|
270
|
+
description: "Directory with funforge.json (defaults to cwd)",
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
required: [],
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: "funforge_apps_delete",
|
|
278
|
+
description: "Delete an app permanently. This will stop all deployments and remove all associated resources.",
|
|
279
|
+
inputSchema: {
|
|
280
|
+
type: "object",
|
|
281
|
+
properties: {
|
|
282
|
+
appId: {
|
|
283
|
+
type: "string",
|
|
284
|
+
description: "The app ID to delete",
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
required: ["appId"],
|
|
288
|
+
},
|
|
289
|
+
},
|
|
198
290
|
];
|
|
199
291
|
async function handleToolCall(name, args) {
|
|
200
292
|
try {
|
|
@@ -219,6 +311,18 @@ async function handleToolCall(name, args) {
|
|
|
219
311
|
return await handleDomainsList(args.directory);
|
|
220
312
|
case "funforge_domains_add":
|
|
221
313
|
return await handleDomainsAdd(args.directory, args.domain, args.verificationMethod);
|
|
314
|
+
case "funforge_domains_remove":
|
|
315
|
+
return await handleDomainsRemove(args.directory, args.domain);
|
|
316
|
+
case "funforge_domains_verify":
|
|
317
|
+
return await handleDomainsVerify(args.directory, args.domain);
|
|
318
|
+
case "funforge_stop":
|
|
319
|
+
return await handleStop(args.directory);
|
|
320
|
+
case "funforge_start":
|
|
321
|
+
return await handleStart(args.directory);
|
|
322
|
+
case "funforge_cancel":
|
|
323
|
+
return await handleCancel(args.directory);
|
|
324
|
+
case "funforge_apps_delete":
|
|
325
|
+
return await handleAppsDelete(args.appId);
|
|
222
326
|
default:
|
|
223
327
|
return errorResult(`Unknown tool: ${name}`);
|
|
224
328
|
}
|
|
@@ -427,6 +531,126 @@ async function handleDomainsAdd(directory, domain, verificationMethod) {
|
|
|
427
531
|
nextStep: "Add the DNS record above, then verify with funforge domains verify command",
|
|
428
532
|
});
|
|
429
533
|
}
|
|
534
|
+
async function handleDomainsRemove(directory, domain) {
|
|
535
|
+
requireAuth();
|
|
536
|
+
const dir = directory || process.cwd();
|
|
537
|
+
const appId = await getLinkedAppId(dir);
|
|
538
|
+
if (!appId) {
|
|
539
|
+
return errorResult(`No app linked in ${dir}.`);
|
|
540
|
+
}
|
|
541
|
+
const { domains } = await apiRequest(`/api/cli/apps/${appId}/domains`);
|
|
542
|
+
const cleanDomain = domain.toLowerCase();
|
|
543
|
+
const targetDomain = domains.find((d) => d.domain.toLowerCase() === cleanDomain || d.id === domain);
|
|
544
|
+
if (!targetDomain) {
|
|
545
|
+
return errorResult(`Domain not found: ${domain}. Use funforge_domains_list to see available domains.`);
|
|
546
|
+
}
|
|
547
|
+
await apiRequest(`/api/cli/apps/${appId}/domains/${targetDomain.id}`, {
|
|
548
|
+
method: "DELETE",
|
|
549
|
+
});
|
|
550
|
+
return successResult({
|
|
551
|
+
message: `Domain ${targetDomain.domain} removed`,
|
|
552
|
+
domainId: targetDomain.id,
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
async function handleDomainsVerify(directory, domain) {
|
|
556
|
+
requireAuth();
|
|
557
|
+
const dir = directory || process.cwd();
|
|
558
|
+
const appId = await getLinkedAppId(dir);
|
|
559
|
+
if (!appId) {
|
|
560
|
+
return errorResult(`No app linked in ${dir}.`);
|
|
561
|
+
}
|
|
562
|
+
const { domains } = await apiRequest(`/api/cli/apps/${appId}/domains`);
|
|
563
|
+
const cleanDomain = domain.toLowerCase();
|
|
564
|
+
const targetDomain = domains.find((d) => d.domain.toLowerCase() === cleanDomain || d.id === domain);
|
|
565
|
+
if (!targetDomain) {
|
|
566
|
+
return errorResult(`Domain not found: ${domain}. Use funforge_domains_list to see available domains.`);
|
|
567
|
+
}
|
|
568
|
+
if (targetDomain.verified) {
|
|
569
|
+
return successResult({
|
|
570
|
+
message: `Domain ${targetDomain.domain} is already verified`,
|
|
571
|
+
domain: targetDomain.domain,
|
|
572
|
+
verified: true,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
const result = await apiRequest(`/api/cli/apps/${appId}/domains/${targetDomain.id}/verify`, { method: "POST" });
|
|
576
|
+
if (result.verified) {
|
|
577
|
+
return successResult({
|
|
578
|
+
message: `Domain ${targetDomain.domain} verified successfully`,
|
|
579
|
+
domain: targetDomain.domain,
|
|
580
|
+
verified: true,
|
|
581
|
+
sslStatus: result.sslStatus,
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
return successResult({
|
|
585
|
+
message: result.message || "Domain verification failed",
|
|
586
|
+
domain: targetDomain.domain,
|
|
587
|
+
verified: false,
|
|
588
|
+
hint: "Make sure your DNS record is correctly configured. DNS changes can take up to 48 hours to propagate.",
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
async function handleStop(directory) {
|
|
592
|
+
requireAuth();
|
|
593
|
+
const dir = directory || process.cwd();
|
|
594
|
+
const appId = await getLinkedAppId(dir);
|
|
595
|
+
if (!appId) {
|
|
596
|
+
return errorResult(`No app linked in ${dir}.`);
|
|
597
|
+
}
|
|
598
|
+
await apiRequest(`/api/cli/apps/${appId}/stop`, {
|
|
599
|
+
method: "POST",
|
|
600
|
+
});
|
|
601
|
+
return successResult({
|
|
602
|
+
message: "Deployment stopped",
|
|
603
|
+
appId,
|
|
604
|
+
note: "Use funforge_start to restart the deployment",
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
async function handleStart(directory) {
|
|
608
|
+
requireAuth();
|
|
609
|
+
const dir = directory || process.cwd();
|
|
610
|
+
const appId = await getLinkedAppId(dir);
|
|
611
|
+
if (!appId) {
|
|
612
|
+
return errorResult(`No app linked in ${dir}.`);
|
|
613
|
+
}
|
|
614
|
+
await apiRequest(`/api/cli/apps/${appId}/start`, {
|
|
615
|
+
method: "POST",
|
|
616
|
+
});
|
|
617
|
+
return successResult({
|
|
618
|
+
message: "Deployment started",
|
|
619
|
+
appId,
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
async function handleCancel(directory) {
|
|
623
|
+
requireAuth();
|
|
624
|
+
const dir = directory || process.cwd();
|
|
625
|
+
const appId = await getLinkedAppId(dir);
|
|
626
|
+
if (!appId) {
|
|
627
|
+
return errorResult(`No app linked in ${dir}.`);
|
|
628
|
+
}
|
|
629
|
+
await apiRequest(`/api/cli/apps/${appId}/cancel`, {
|
|
630
|
+
method: "POST",
|
|
631
|
+
});
|
|
632
|
+
return successResult({
|
|
633
|
+
message: "Deployment canceled",
|
|
634
|
+
appId,
|
|
635
|
+
note: "The in-progress build or deployment has been canceled",
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
async function handleAppsDelete(appId) {
|
|
639
|
+
requireAuth();
|
|
640
|
+
const { app } = await apiRequest(`/api/cli/apps/${appId}`);
|
|
641
|
+
await apiRequest(`/api/cli/apps/${appId}`, {
|
|
642
|
+
method: "DELETE",
|
|
643
|
+
});
|
|
644
|
+
return successResult({
|
|
645
|
+
message: `App "${app.name}" deleted successfully`,
|
|
646
|
+
app: {
|
|
647
|
+
id: app.id,
|
|
648
|
+
name: app.name,
|
|
649
|
+
slug: app.slug,
|
|
650
|
+
},
|
|
651
|
+
note: "All deployments and resources have been removed",
|
|
652
|
+
});
|
|
653
|
+
}
|
|
430
654
|
// ============================================
|
|
431
655
|
// HELPERS
|
|
432
656
|
// ============================================
|
|
@@ -470,7 +694,7 @@ function formatError(error) {
|
|
|
470
694
|
async function main() {
|
|
471
695
|
const server = new Server({
|
|
472
696
|
name: "funforge",
|
|
473
|
-
version: "0.
|
|
697
|
+
version: "0.3.0",
|
|
474
698
|
}, {
|
|
475
699
|
capabilities: {
|
|
476
700
|
tools: {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byfungsi/funforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Deploy without git, without leaving your editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,10 +9,7 @@
|
|
|
9
9
|
"funforge": "./dist/cli.js",
|
|
10
10
|
"funforge-mcp": "./dist/mcp.js"
|
|
11
11
|
},
|
|
12
|
-
"files": [
|
|
13
|
-
"dist",
|
|
14
|
-
"README.md"
|
|
15
|
-
],
|
|
12
|
+
"files": ["dist", "README.md"],
|
|
16
13
|
"scripts": {
|
|
17
14
|
"build": "tsc",
|
|
18
15
|
"dev": "tsc --watch",
|
|
@@ -26,13 +23,7 @@
|
|
|
26
23
|
"release:publish": "pnpm run build && pnpm run test && npm publish --access public",
|
|
27
24
|
"release:dry": "pnpm run build && pnpm run test && npm publish --access public --dry-run"
|
|
28
25
|
},
|
|
29
|
-
"keywords": [
|
|
30
|
-
"cli",
|
|
31
|
-
"deploy",
|
|
32
|
-
"funforge",
|
|
33
|
-
"fungsi",
|
|
34
|
-
"mcp"
|
|
35
|
-
],
|
|
26
|
+
"keywords": ["cli", "deploy", "funforge", "fungsi", "mcp"],
|
|
36
27
|
"author": "Fungsi",
|
|
37
28
|
"license": "MIT",
|
|
38
29
|
"engines": {
|