@byfungsi/funforge 0.2.3 → 0.5.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 +42 -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/config.d.ts.map +1 -1
- package/dist/commands/config.js +15 -0
- 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/dist/project-config.d.ts +6 -0
- package/dist/project-config.d.ts.map +1 -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
|
@@ -60,6 +60,8 @@ export interface AppDetails extends App {
|
|
|
60
60
|
startCommand?: string | null;
|
|
61
61
|
/** Node.js version (18, 20, 22) */
|
|
62
62
|
nodeVersion?: string | null;
|
|
63
|
+
/** Root directory for monorepo builds (e.g., "apps/web") */
|
|
64
|
+
rootDirectory?: string | null;
|
|
63
65
|
}
|
|
64
66
|
export interface ListAppsResponse {
|
|
65
67
|
apps: App[];
|
|
@@ -92,6 +94,8 @@ export interface UpdateAppSettings {
|
|
|
92
94
|
startCommand?: string | null;
|
|
93
95
|
/** Node.js version (18, 20, 22) - null clears */
|
|
94
96
|
nodeVersion?: "18" | "20" | "22" | null;
|
|
97
|
+
/** Root directory for monorepo builds (e.g., "apps/web") - null clears */
|
|
98
|
+
rootDirectory?: string | null;
|
|
95
99
|
}
|
|
96
100
|
/**
|
|
97
101
|
* Update app settings (build commands, port, etc.)
|
|
@@ -154,5 +158,43 @@ export declare function getDeployment(deploymentId: string): Promise<{
|
|
|
154
158
|
* Stream deployment logs (returns EventSource URL)
|
|
155
159
|
*/
|
|
156
160
|
export declare function getDeploymentLogsUrl(deploymentId: string): string;
|
|
161
|
+
/**
|
|
162
|
+
* Stop the current deployment for an app
|
|
163
|
+
*/
|
|
164
|
+
export declare function stopDeployment(appId: string): Promise<{
|
|
165
|
+
success: boolean;
|
|
166
|
+
}>;
|
|
167
|
+
/**
|
|
168
|
+
* Start a stopped deployment for an app
|
|
169
|
+
*/
|
|
170
|
+
export declare function startDeployment(appId: string): Promise<{
|
|
171
|
+
success: boolean;
|
|
172
|
+
}>;
|
|
173
|
+
/**
|
|
174
|
+
* Cancel an in-progress deployment
|
|
175
|
+
*/
|
|
176
|
+
export declare function cancelDeployment(appId: string): Promise<{
|
|
177
|
+
success: boolean;
|
|
178
|
+
}>;
|
|
179
|
+
/**
|
|
180
|
+
* Delete an app
|
|
181
|
+
*/
|
|
182
|
+
export declare function deleteApp(appId: string): Promise<{
|
|
183
|
+
success: boolean;
|
|
184
|
+
}>;
|
|
185
|
+
/**
|
|
186
|
+
* Remove a custom domain from an app
|
|
187
|
+
*/
|
|
188
|
+
export declare function removeDomain(appId: string, domainId: string): Promise<{
|
|
189
|
+
success: boolean;
|
|
190
|
+
}>;
|
|
191
|
+
/**
|
|
192
|
+
* Verify DNS and provision SSL for a domain
|
|
193
|
+
*/
|
|
194
|
+
export declare function verifyDomain(appId: string, domainId: string): Promise<{
|
|
195
|
+
verified: boolean;
|
|
196
|
+
sslStatus?: string;
|
|
197
|
+
message?: string;
|
|
198
|
+
}>;
|
|
157
199
|
export {};
|
|
158
200
|
//# 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":"AAAA;;;;GAIG;AAKH,qBAAa,QAAS,SAAQ,KAAK;IAGxB,UAAU,EAAE,MAAM;IAClB,IAAI,CAAC,EAAE,OAAO;gBAFrB,OAAO,EAAE,MAAM,EACR,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,OAAO,YAAA;CAKxB;AAED,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACrD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,CAAC,CAAC,CAwCZ;AAMD,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,sBAAsB,CAAC,CA2BtE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,sBAAsB,CAAC,CAiEjC;AAMD,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAW,SAAQ,GAAG;IACrC,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6BAA6B;IAC7B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,2BAA2B;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mCAAmC;IACnC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
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
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAyEH;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkFvD;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkFvD;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmFvD"}
|
package/dist/commands/config.js
CHANGED
|
@@ -22,6 +22,10 @@ function extractBuildSettings(config) {
|
|
|
22
22
|
if (config.port !== undefined) {
|
|
23
23
|
settings.port = config.port;
|
|
24
24
|
}
|
|
25
|
+
// Root directory for monorepo builds
|
|
26
|
+
if (config.rootDirectory !== undefined) {
|
|
27
|
+
settings.rootDirectory = config.rootDirectory || null;
|
|
28
|
+
}
|
|
25
29
|
if (config.build) {
|
|
26
30
|
if (config.build.buildCommand !== undefined) {
|
|
27
31
|
settings.buildCommand = config.build.buildCommand || null;
|
|
@@ -102,6 +106,9 @@ export async function configPushCommand() {
|
|
|
102
106
|
if (settings.port !== undefined) {
|
|
103
107
|
console.log(` Port: ${formatValue(settings.port)}`);
|
|
104
108
|
}
|
|
109
|
+
if (settings.rootDirectory !== undefined) {
|
|
110
|
+
console.log(` Root directory: ${formatValue(settings.rootDirectory)}`);
|
|
111
|
+
}
|
|
105
112
|
if (settings.buildCommand !== undefined) {
|
|
106
113
|
console.log(` Build command: ${formatValue(settings.buildCommand)}`);
|
|
107
114
|
}
|
|
@@ -158,6 +165,10 @@ export async function configPullCommand() {
|
|
|
158
165
|
if (app.port !== undefined) {
|
|
159
166
|
updatedConfig.port = app.port;
|
|
160
167
|
}
|
|
168
|
+
// Sync root directory if set
|
|
169
|
+
if (app.rootDirectory) {
|
|
170
|
+
updatedConfig.rootDirectory = app.rootDirectory;
|
|
171
|
+
}
|
|
161
172
|
// Build build settings object
|
|
162
173
|
const build = {};
|
|
163
174
|
let hasBuildSettings = false;
|
|
@@ -183,6 +194,7 @@ export async function configPullCommand() {
|
|
|
183
194
|
// Show what will be written
|
|
184
195
|
console.log(chalk.gray("Settings from server:"));
|
|
185
196
|
console.log(` Port: ${formatValue(app.port)}`);
|
|
197
|
+
console.log(` Root directory: ${formatValue(app.rootDirectory)}`);
|
|
186
198
|
console.log(` Build command: ${formatValue(app.buildCommand)}`);
|
|
187
199
|
console.log(` Install command: ${formatValue(app.installCommand)}`);
|
|
188
200
|
console.log(` Start command: ${formatValue(app.startCommand)}`);
|
|
@@ -220,12 +232,14 @@ export async function configShowCommand() {
|
|
|
220
232
|
spinner.stop();
|
|
221
233
|
// Local values
|
|
222
234
|
const localPort = config.port;
|
|
235
|
+
const localRootDirectory = config.rootDirectory;
|
|
223
236
|
const localBuildCommand = config.build?.buildCommand;
|
|
224
237
|
const localInstallCommand = config.build?.installCommand;
|
|
225
238
|
const localStartCommand = config.build?.startCommand;
|
|
226
239
|
const localNodeVersion = config.build?.nodeVersion;
|
|
227
240
|
// Server values
|
|
228
241
|
const serverPort = app.port;
|
|
242
|
+
const serverRootDirectory = app.rootDirectory;
|
|
229
243
|
const serverBuildCommand = app.buildCommand;
|
|
230
244
|
const serverInstallCommand = app.installCommand;
|
|
231
245
|
const serverStartCommand = app.startCommand;
|
|
@@ -244,6 +258,7 @@ export async function configShowCommand() {
|
|
|
244
258
|
console.log(`${marker}${name.padEnd(19)}${localStr}${serverStr}`);
|
|
245
259
|
};
|
|
246
260
|
printRow("Port", localPort, serverPort);
|
|
261
|
+
printRow("Root directory", localRootDirectory, serverRootDirectory);
|
|
247
262
|
printRow("Build command", localBuildCommand, serverBuildCommand);
|
|
248
263
|
printRow("Install command", localInstallCommand, serverInstallCommand);
|
|
249
264
|
printRow("Start command", localStartCommand, serverStartCommand);
|
|
@@ -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/dist/project-config.d.ts
CHANGED
|
@@ -10,8 +10,14 @@ export interface FunForgeConfig {
|
|
|
10
10
|
appName?: string;
|
|
11
11
|
/** App slug (subdomain) */
|
|
12
12
|
appSlug?: string;
|
|
13
|
+
/** Root directory for monorepo builds (e.g., "apps/web") */
|
|
14
|
+
rootDirectory?: string;
|
|
13
15
|
/** Build settings */
|
|
14
16
|
build?: {
|
|
17
|
+
/** Build mode: 'auto' (default) | 'dockerfile' | 'railpack' */
|
|
18
|
+
mode?: "auto" | "dockerfile" | "railpack";
|
|
19
|
+
/** Path to Dockerfile (relative to root directory, default: 'Dockerfile') */
|
|
20
|
+
dockerfilePath?: string;
|
|
15
21
|
/** Custom build command */
|
|
16
22
|
buildCommand?: string;
|
|
17
23
|
/** Custom install command */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-config.d.ts","sourceRoot":"","sources":["../src/project-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,KAAK,CAAC,EAAE;QACN,2BAA2B;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,6BAA6B;QAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,2BAA2B;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,sBAAsB;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,GAAE,MAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAOtE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOhC;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,EAChC,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB"}
|
|
1
|
+
{"version":3,"file":"project-config.d.ts","sourceRoot":"","sources":["../src/project-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qBAAqB;IACrB,KAAK,CAAC,EAAE;QACN,+DAA+D;QAC/D,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,CAAC;QAC1C,6EAA6E;QAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,2BAA2B;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,6BAA6B;QAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,2BAA2B;QAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,sBAAsB;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAID;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,GAAE,MAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAOtE;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAOhC;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,EAChC,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,GAAE,MAAY,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byfungsi/funforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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": {
|