@studiometa/forge-cli 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/README.md +252 -0
  2. package/dist/audit.d.ts +3 -0
  3. package/dist/audit.d.ts.map +1 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +3567 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/backups/command.d.ts +2 -0
  9. package/dist/commands/backups/command.d.ts.map +1 -0
  10. package/dist/commands/backups/handlers.d.ts +6 -0
  11. package/dist/commands/backups/handlers.d.ts.map +1 -0
  12. package/dist/commands/backups/help.d.ts +2 -0
  13. package/dist/commands/backups/help.d.ts.map +1 -0
  14. package/dist/commands/backups/index.d.ts +3 -0
  15. package/dist/commands/backups/index.d.ts.map +1 -0
  16. package/dist/commands/certificates/command.d.ts +2 -0
  17. package/dist/commands/certificates/command.d.ts.map +1 -0
  18. package/dist/commands/certificates/handlers.d.ts +5 -0
  19. package/dist/commands/certificates/handlers.d.ts.map +1 -0
  20. package/dist/commands/certificates/help.d.ts +2 -0
  21. package/dist/commands/certificates/help.d.ts.map +1 -0
  22. package/dist/commands/certificates/index.d.ts +3 -0
  23. package/dist/commands/certificates/index.d.ts.map +1 -0
  24. package/dist/commands/commands/command.d.ts +2 -0
  25. package/dist/commands/commands/command.d.ts.map +1 -0
  26. package/dist/commands/commands/handlers.d.ts +5 -0
  27. package/dist/commands/commands/handlers.d.ts.map +1 -0
  28. package/dist/commands/commands/help.d.ts +2 -0
  29. package/dist/commands/commands/help.d.ts.map +1 -0
  30. package/dist/commands/commands/index.d.ts +3 -0
  31. package/dist/commands/commands/index.d.ts.map +1 -0
  32. package/dist/commands/completion.d.ts +6 -0
  33. package/dist/commands/completion.d.ts.map +1 -0
  34. package/dist/commands/config.d.ts +6 -0
  35. package/dist/commands/config.d.ts.map +1 -0
  36. package/dist/commands/daemons/command.d.ts +2 -0
  37. package/dist/commands/daemons/command.d.ts.map +1 -0
  38. package/dist/commands/daemons/handlers.d.ts +5 -0
  39. package/dist/commands/daemons/handlers.d.ts.map +1 -0
  40. package/dist/commands/daemons/help.d.ts +2 -0
  41. package/dist/commands/daemons/help.d.ts.map +1 -0
  42. package/dist/commands/daemons/index.d.ts +3 -0
  43. package/dist/commands/daemons/index.d.ts.map +1 -0
  44. package/dist/commands/database-users/command.d.ts +2 -0
  45. package/dist/commands/database-users/command.d.ts.map +1 -0
  46. package/dist/commands/database-users/handlers.d.ts +6 -0
  47. package/dist/commands/database-users/handlers.d.ts.map +1 -0
  48. package/dist/commands/database-users/help.d.ts +2 -0
  49. package/dist/commands/database-users/help.d.ts.map +1 -0
  50. package/dist/commands/database-users/index.d.ts +3 -0
  51. package/dist/commands/database-users/index.d.ts.map +1 -0
  52. package/dist/commands/databases/command.d.ts +2 -0
  53. package/dist/commands/databases/command.d.ts.map +1 -0
  54. package/dist/commands/databases/handlers.d.ts +4 -0
  55. package/dist/commands/databases/handlers.d.ts.map +1 -0
  56. package/dist/commands/databases/help.d.ts +2 -0
  57. package/dist/commands/databases/help.d.ts.map +1 -0
  58. package/dist/commands/databases/index.d.ts +3 -0
  59. package/dist/commands/databases/index.d.ts.map +1 -0
  60. package/dist/commands/deployments/command.d.ts +2 -0
  61. package/dist/commands/deployments/command.d.ts.map +1 -0
  62. package/dist/commands/deployments/handlers.d.ts +4 -0
  63. package/dist/commands/deployments/handlers.d.ts.map +1 -0
  64. package/dist/commands/deployments/help.d.ts +2 -0
  65. package/dist/commands/deployments/help.d.ts.map +1 -0
  66. package/dist/commands/deployments/index.d.ts +3 -0
  67. package/dist/commands/deployments/index.d.ts.map +1 -0
  68. package/dist/commands/env/command.d.ts +2 -0
  69. package/dist/commands/env/command.d.ts.map +1 -0
  70. package/dist/commands/env/handlers.d.ts +4 -0
  71. package/dist/commands/env/handlers.d.ts.map +1 -0
  72. package/dist/commands/env/help.d.ts +2 -0
  73. package/dist/commands/env/help.d.ts.map +1 -0
  74. package/dist/commands/env/index.d.ts +3 -0
  75. package/dist/commands/env/index.d.ts.map +1 -0
  76. package/dist/commands/firewall-rules/command.d.ts +2 -0
  77. package/dist/commands/firewall-rules/command.d.ts.map +1 -0
  78. package/dist/commands/firewall-rules/handlers.d.ts +4 -0
  79. package/dist/commands/firewall-rules/handlers.d.ts.map +1 -0
  80. package/dist/commands/firewall-rules/help.d.ts +2 -0
  81. package/dist/commands/firewall-rules/help.d.ts.map +1 -0
  82. package/dist/commands/firewall-rules/index.d.ts +3 -0
  83. package/dist/commands/firewall-rules/index.d.ts.map +1 -0
  84. package/dist/commands/monitors/command.d.ts +2 -0
  85. package/dist/commands/monitors/command.d.ts.map +1 -0
  86. package/dist/commands/monitors/handlers.d.ts +6 -0
  87. package/dist/commands/monitors/handlers.d.ts.map +1 -0
  88. package/dist/commands/monitors/help.d.ts +2 -0
  89. package/dist/commands/monitors/help.d.ts.map +1 -0
  90. package/dist/commands/monitors/index.d.ts +3 -0
  91. package/dist/commands/monitors/index.d.ts.map +1 -0
  92. package/dist/commands/nginx/command.d.ts +2 -0
  93. package/dist/commands/nginx/command.d.ts.map +1 -0
  94. package/dist/commands/nginx/handlers.d.ts +4 -0
  95. package/dist/commands/nginx/handlers.d.ts.map +1 -0
  96. package/dist/commands/nginx/help.d.ts +2 -0
  97. package/dist/commands/nginx/help.d.ts.map +1 -0
  98. package/dist/commands/nginx/index.d.ts +3 -0
  99. package/dist/commands/nginx/index.d.ts.map +1 -0
  100. package/dist/commands/nginx-templates/command.d.ts +2 -0
  101. package/dist/commands/nginx-templates/command.d.ts.map +1 -0
  102. package/dist/commands/nginx-templates/handlers.d.ts +7 -0
  103. package/dist/commands/nginx-templates/handlers.d.ts.map +1 -0
  104. package/dist/commands/nginx-templates/help.d.ts +2 -0
  105. package/dist/commands/nginx-templates/help.d.ts.map +1 -0
  106. package/dist/commands/nginx-templates/index.d.ts +3 -0
  107. package/dist/commands/nginx-templates/index.d.ts.map +1 -0
  108. package/dist/commands/recipes/command.d.ts +2 -0
  109. package/dist/commands/recipes/command.d.ts.map +1 -0
  110. package/dist/commands/recipes/handlers.d.ts +5 -0
  111. package/dist/commands/recipes/handlers.d.ts.map +1 -0
  112. package/dist/commands/recipes/help.d.ts +2 -0
  113. package/dist/commands/recipes/help.d.ts.map +1 -0
  114. package/dist/commands/recipes/index.d.ts +3 -0
  115. package/dist/commands/recipes/index.d.ts.map +1 -0
  116. package/dist/commands/redirect-rules/command.d.ts +2 -0
  117. package/dist/commands/redirect-rules/command.d.ts.map +1 -0
  118. package/dist/commands/redirect-rules/handlers.d.ts +6 -0
  119. package/dist/commands/redirect-rules/handlers.d.ts.map +1 -0
  120. package/dist/commands/redirect-rules/help.d.ts +2 -0
  121. package/dist/commands/redirect-rules/help.d.ts.map +1 -0
  122. package/dist/commands/redirect-rules/index.d.ts +3 -0
  123. package/dist/commands/redirect-rules/index.d.ts.map +1 -0
  124. package/dist/commands/scheduled-jobs/command.d.ts +2 -0
  125. package/dist/commands/scheduled-jobs/command.d.ts.map +1 -0
  126. package/dist/commands/scheduled-jobs/handlers.d.ts +6 -0
  127. package/dist/commands/scheduled-jobs/handlers.d.ts.map +1 -0
  128. package/dist/commands/scheduled-jobs/help.d.ts +2 -0
  129. package/dist/commands/scheduled-jobs/help.d.ts.map +1 -0
  130. package/dist/commands/scheduled-jobs/index.d.ts +3 -0
  131. package/dist/commands/scheduled-jobs/index.d.ts.map +1 -0
  132. package/dist/commands/security-rules/command.d.ts +2 -0
  133. package/dist/commands/security-rules/command.d.ts.map +1 -0
  134. package/dist/commands/security-rules/handlers.d.ts +6 -0
  135. package/dist/commands/security-rules/handlers.d.ts.map +1 -0
  136. package/dist/commands/security-rules/help.d.ts +2 -0
  137. package/dist/commands/security-rules/help.d.ts.map +1 -0
  138. package/dist/commands/security-rules/index.d.ts +3 -0
  139. package/dist/commands/security-rules/index.d.ts.map +1 -0
  140. package/dist/commands/servers/command.d.ts +2 -0
  141. package/dist/commands/servers/command.d.ts.map +1 -0
  142. package/dist/commands/servers/handlers.d.ts +18 -0
  143. package/dist/commands/servers/handlers.d.ts.map +1 -0
  144. package/dist/commands/servers/help.d.ts +2 -0
  145. package/dist/commands/servers/help.d.ts.map +1 -0
  146. package/dist/commands/servers/index.d.ts +3 -0
  147. package/dist/commands/servers/index.d.ts.map +1 -0
  148. package/dist/commands/sites/command.d.ts +2 -0
  149. package/dist/commands/sites/command.d.ts.map +1 -0
  150. package/dist/commands/sites/handlers.d.ts +4 -0
  151. package/dist/commands/sites/handlers.d.ts.map +1 -0
  152. package/dist/commands/sites/help.d.ts +2 -0
  153. package/dist/commands/sites/help.d.ts.map +1 -0
  154. package/dist/commands/sites/index.d.ts +3 -0
  155. package/dist/commands/sites/index.d.ts.map +1 -0
  156. package/dist/commands/ssh-keys/command.d.ts +2 -0
  157. package/dist/commands/ssh-keys/command.d.ts.map +1 -0
  158. package/dist/commands/ssh-keys/handlers.d.ts +4 -0
  159. package/dist/commands/ssh-keys/handlers.d.ts.map +1 -0
  160. package/dist/commands/ssh-keys/help.d.ts +2 -0
  161. package/dist/commands/ssh-keys/help.d.ts.map +1 -0
  162. package/dist/commands/ssh-keys/index.d.ts +3 -0
  163. package/dist/commands/ssh-keys/index.d.ts.map +1 -0
  164. package/dist/commands/user/command.d.ts +2 -0
  165. package/dist/commands/user/command.d.ts.map +1 -0
  166. package/dist/commands/user/handlers.d.ts +3 -0
  167. package/dist/commands/user/handlers.d.ts.map +1 -0
  168. package/dist/commands/user/help.d.ts +2 -0
  169. package/dist/commands/user/help.d.ts.map +1 -0
  170. package/dist/commands/user/index.d.ts +3 -0
  171. package/dist/commands/user/index.d.ts.map +1 -0
  172. package/dist/config.d.ts +18 -0
  173. package/dist/config.d.ts.map +1 -0
  174. package/dist/context.d.ts +50 -0
  175. package/dist/context.d.ts.map +1 -0
  176. package/dist/error-handler-BahHMt6t.js +396 -0
  177. package/dist/error-handler-BahHMt6t.js.map +1 -0
  178. package/dist/error-handler.d.ts +39 -0
  179. package/dist/error-handler.d.ts.map +1 -0
  180. package/dist/errors.d.ts +45 -0
  181. package/dist/errors.d.ts.map +1 -0
  182. package/dist/index.d.ts +8 -0
  183. package/dist/index.d.ts.map +1 -0
  184. package/dist/index.js +2 -0
  185. package/dist/output.d.ts +47 -0
  186. package/dist/output.d.ts.map +1 -0
  187. package/dist/types.d.ts +7 -0
  188. package/dist/types.d.ts.map +1 -0
  189. package/dist/utils/args.d.ts +14 -0
  190. package/dist/utils/args.d.ts.map +1 -0
  191. package/dist/utils/colors.d.ts +17 -0
  192. package/dist/utils/colors.d.ts.map +1 -0
  193. package/dist/utils/command-router.d.ts +52 -0
  194. package/dist/utils/command-router.d.ts.map +1 -0
  195. package/dist/utils/resolve.d.ts +25 -0
  196. package/dist/utils/resolve.d.ts.map +1 -0
  197. package/package.json +41 -1
package/dist/cli.js ADDED
@@ -0,0 +1,3567 @@
1
+ #!/usr/bin/env node
2
+ import { a as createContext, c as colors, d as deleteToken, i as runCommand, l as setColorEnabled, m as setToken, n as exitWithValidationError, p as getToken, s as OutputFormatter, u as createConfigStore, v as ValidationError } from "./error-handler-BahHMt6t.js";
3
+ import { activateCertificate, createAuditLogger, createBackupConfig, createCommand, createDatabaseUser, createMonitor, createNginxTemplate, createRedirectRule, createScheduledJob, createSecurityRule, deleteBackupConfig, deleteDatabaseUser, deleteMonitor, deleteNginxTemplate, deleteRedirectRule, deleteScheduledJob, deleteSecurityRule, deploySiteAndWait, getBackupConfig, getCertificate, getCommand, getDaemon, getDatabase, getDatabaseUser, getEnv, getFirewallRule, getMonitor, getNginxConfig, getNginxTemplate, getRecipe, getRedirectRule, getScheduledJob, getSecurityRule, getServer, getSite, getSshKey, getUser, listBackupConfigs, listCertificates, listCommands, listDaemons, listDatabaseUsers, listDatabases, listDeployments, listFirewallRules, listMonitors, listNginxTemplates, listRecipes, listRedirectRules, listScheduledJobs, listSecurityRules, listServers, listSites, listSshKeys, rebootServer, restartDaemon, runRecipe, updateEnv, updateNginxConfig, updateNginxTemplate } from "@studiometa/forge-core";
4
+ import { mkdirSync, writeFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ import { join } from "node:path";
7
+ /**
8
+ * Shared audit logger for CLI write operations.
9
+ * Lazily initialized on first use.
10
+ */
11
+ var _auditLogger = null;
12
+ function getCliAuditLogger() {
13
+ if (!_auditLogger) _auditLogger = createAuditLogger("cli");
14
+ return _auditLogger;
15
+ }
16
+ /**
17
+ * Creates a command router function that dispatches to the appropriate handler.
18
+ */
19
+ function createCommandRouter(config) {
20
+ return async function(subcommand, args, options) {
21
+ const formatter = new OutputFormatter(options.format ?? options.f ?? "human", options["no-color"] === true);
22
+ const ctx = createContext(options);
23
+ const handler = config.handlers[subcommand];
24
+ if (!handler) {
25
+ formatter.error(`Unknown ${config.resource} subcommand: ${subcommand}`);
26
+ process.exit(1);
27
+ return;
28
+ }
29
+ if (config.writeSubcommands?.includes(subcommand) ?? false) {
30
+ const { token: _token, ...safeOptions } = options;
31
+ try {
32
+ if (Array.isArray(handler)) await handler[0](args, ctx);
33
+ else await handler(ctx);
34
+ getCliAuditLogger().log({
35
+ source: "cli",
36
+ resource: config.resource,
37
+ action: subcommand,
38
+ args: safeOptions,
39
+ status: "success"
40
+ });
41
+ } catch (err) {
42
+ const errorMessage = err instanceof Error ? err.message : String(err);
43
+ getCliAuditLogger().log({
44
+ source: "cli",
45
+ resource: config.resource,
46
+ action: subcommand,
47
+ args: safeOptions,
48
+ status: "error",
49
+ error: errorMessage
50
+ });
51
+ throw err;
52
+ }
53
+ } else if (Array.isArray(handler)) await handler[0](args, ctx);
54
+ else await handler(ctx);
55
+ };
56
+ }
57
+ /**
58
+ * Smart resolution utilities for --server and --site options.
59
+ *
60
+ * Accepts numeric IDs (used as-is) or plain strings (resolved by name/partial match).
61
+ */
62
+ /**
63
+ * Resolve a --server value to a numeric server ID string.
64
+ *
65
+ * - Numeric string → returned as-is (no API call)
66
+ * - Plain string → fetch all servers, exact match first, then partial match
67
+ * - 0 matches → ValidationError listing available servers
68
+ * - 2+ matches → ValidationError listing ambiguous matches
69
+ */
70
+ async function resolveServerId(value, execCtx) {
71
+ if (/^\d+$/.test(value)) return value;
72
+ const servers = (await listServers({}, execCtx)).data;
73
+ const lower = value.toLowerCase();
74
+ const exact = servers.filter((s) => s.name.toLowerCase() === lower);
75
+ if (exact.length === 1) return String(exact[0].id);
76
+ const partial = servers.filter((s) => s.name.toLowerCase().includes(lower));
77
+ if (partial.length === 0) {
78
+ const available = servers.map((s) => ` ${s.name} (${s.id})`).join("\n");
79
+ throw new ValidationError(`No server found matching "${value}"`, "server", [`Available servers:\n${available}`]);
80
+ }
81
+ if (partial.length > 1) {
82
+ const matches = partial.map((s) => ` ${s.name} (${s.id})`).join("\n");
83
+ throw new ValidationError(`Ambiguous server name "${value}" — ${partial.length} matches found`, "server", [`Matching servers:\n${matches}`, "Use a more specific name or pass the numeric ID"]);
84
+ }
85
+ return String(partial[0].id);
86
+ }
87
+ /**
88
+ * Resolve a --site value to a numeric site ID string.
89
+ *
90
+ * - Numeric string → returned as-is (no API call)
91
+ * - Plain string → fetch all sites for the server, exact domain match first, then partial
92
+ * - 0 matches → ValidationError listing available sites
93
+ * - 2+ matches → ValidationError listing ambiguous matches
94
+ */
95
+ async function resolveSiteId(value, serverId, execCtx) {
96
+ if (/^\d+$/.test(value)) return value;
97
+ const sites = (await listSites({ server_id: serverId }, execCtx)).data;
98
+ const lower = value.toLowerCase();
99
+ const exact = sites.filter((s) => s.name.toLowerCase() === lower);
100
+ if (exact.length === 1) return String(exact[0].id);
101
+ const partial = sites.filter((s) => s.name.toLowerCase().includes(lower));
102
+ if (partial.length === 0) {
103
+ const available = sites.map((s) => ` ${s.name} (${s.id})`).join("\n");
104
+ throw new ValidationError(`No site found matching "${value}" on server ${serverId}`, "site", [`Available sites:\n${available}`]);
105
+ }
106
+ if (partial.length > 1) {
107
+ const matches = partial.map((s) => ` ${s.name} (${s.id})`).join("\n");
108
+ throw new ValidationError(`Ambiguous site name "${value}" — ${partial.length} matches found`, "site", [`Matching sites:\n${matches}`, "Use a more specific name or pass the numeric ID"]);
109
+ }
110
+ return String(partial[0].id);
111
+ }
112
+ async function backupsList(ctx) {
113
+ const server = String(ctx.options.server ?? "");
114
+ if (!server) exitWithValidationError("server_id", "forge-cli backups list --server <server_id>", ctx.formatter);
115
+ await runCommand(async () => {
116
+ const token = ctx.getToken();
117
+ const execCtx = ctx.createExecutorContext(token);
118
+ const result = await listBackupConfigs({ server_id: await resolveServerId(server, execCtx) }, execCtx);
119
+ ctx.formatter.outputList(result.data, [
120
+ "id",
121
+ "provider_name",
122
+ "frequency",
123
+ "status"
124
+ ], "No backup configurations found.", (b) => `${String(b.id).padEnd(8)} ${b.provider_name.padEnd(20)} ${b.frequency.padEnd(12)} ${b.status}`);
125
+ }, ctx.formatter);
126
+ }
127
+ async function backupsGet(args, ctx) {
128
+ const [id] = args;
129
+ const server = String(ctx.options.server ?? "");
130
+ if (!id) exitWithValidationError("backup_id", "forge-cli backups get <backup_id> --server <server_id>", ctx.formatter);
131
+ if (!server) exitWithValidationError("server_id", "forge-cli backups get <backup_id> --server <server_id>", ctx.formatter);
132
+ await runCommand(async () => {
133
+ const token = ctx.getToken();
134
+ const execCtx = ctx.createExecutorContext(token);
135
+ const result = await getBackupConfig({
136
+ server_id: await resolveServerId(server, execCtx),
137
+ id
138
+ }, execCtx);
139
+ ctx.formatter.outputOne(result.data, [
140
+ "id",
141
+ "provider",
142
+ "provider_name",
143
+ "frequency",
144
+ "retention",
145
+ "status",
146
+ "last_backup_time"
147
+ ]);
148
+ }, ctx.formatter);
149
+ }
150
+ async function backupsCreate(ctx) {
151
+ const server = String(ctx.options.server ?? "");
152
+ const provider = String(ctx.options.provider ?? "");
153
+ const frequency = String(ctx.options.frequency ?? "");
154
+ const databasesRaw = ctx.options.databases;
155
+ const databases = Array.isArray(databasesRaw) ? databasesRaw.map(Number) : databasesRaw ? [Number(databasesRaw)] : [];
156
+ if (!server) exitWithValidationError("server_id", "forge-cli backups create --server <server_id> --provider <provider> --frequency <frequency>", ctx.formatter);
157
+ if (!provider) exitWithValidationError("provider", "forge-cli backups create --server <server_id> --provider <provider> --frequency <frequency>", ctx.formatter);
158
+ if (!frequency) exitWithValidationError("frequency", "forge-cli backups create --server <server_id> --provider <provider> --frequency <frequency>", ctx.formatter);
159
+ await runCommand(async () => {
160
+ const token = ctx.getToken();
161
+ const execCtx = ctx.createExecutorContext(token);
162
+ const result = await createBackupConfig({
163
+ server_id: await resolveServerId(server, execCtx),
164
+ provider,
165
+ frequency,
166
+ credentials: {},
167
+ databases
168
+ }, execCtx);
169
+ ctx.formatter.outputOne(result.data, [
170
+ "id",
171
+ "provider",
172
+ "provider_name",
173
+ "frequency",
174
+ "retention",
175
+ "status"
176
+ ]);
177
+ }, ctx.formatter);
178
+ }
179
+ async function backupsDelete(args, ctx) {
180
+ const [id] = args;
181
+ const server = String(ctx.options.server ?? "");
182
+ if (!id) exitWithValidationError("backup_id", "forge-cli backups delete <backup_id> --server <server_id>", ctx.formatter);
183
+ if (!server) exitWithValidationError("server_id", "forge-cli backups delete <backup_id> --server <server_id>", ctx.formatter);
184
+ await runCommand(async () => {
185
+ const token = ctx.getToken();
186
+ const execCtx = ctx.createExecutorContext(token);
187
+ await deleteBackupConfig({
188
+ server_id: await resolveServerId(server, execCtx),
189
+ id
190
+ }, execCtx);
191
+ ctx.formatter.success(`Backup configuration ${id} deleted.`);
192
+ }, ctx.formatter);
193
+ }
194
+ const handleBackupsCommand = createCommandRouter({
195
+ resource: "backups",
196
+ handlers: {
197
+ list: backupsList,
198
+ ls: backupsList,
199
+ get: [backupsGet, "args"],
200
+ create: backupsCreate,
201
+ delete: [backupsDelete, "args"]
202
+ },
203
+ writeSubcommands: ["create", "delete"]
204
+ });
205
+ function showBackupsHelp(subcommand) {
206
+ if (subcommand === "list" || subcommand === "ls") console.log(`
207
+ ${colors.bold("forge-cli backups list")} - List backup configurations on a server
208
+
209
+ ${colors.bold("USAGE:")}
210
+ forge-cli backups list --server <server_id> [options]
211
+
212
+ ${colors.bold("OPTIONS:")}
213
+ --server <id> Server ID (required)
214
+ -f, --format <fmt> Output format: json, human, table
215
+ `);
216
+ else if (subcommand === "get") console.log(`
217
+ ${colors.bold("forge-cli backups get")} - Get backup configuration details
218
+
219
+ ${colors.bold("USAGE:")}
220
+ forge-cli backups get <backup_id> --server <server_id> [options]
221
+ `);
222
+ else if (subcommand === "create") console.log(`
223
+ ${colors.bold("forge-cli backups create")} - Create a new backup configuration
224
+
225
+ ${colors.bold("USAGE:")}
226
+ forge-cli backups create --server <server_id> --provider <provider> --frequency <frequency> [options]
227
+
228
+ ${colors.bold("OPTIONS:")}
229
+ --server <id> Server ID (required)
230
+ --provider <name> Backup provider (required)
231
+ --frequency <freq> Backup frequency (required)
232
+ --databases <ids> Comma-separated database IDs to back up (optional)
233
+ -f, --format <fmt> Output format: json, human, table
234
+ `);
235
+ else if (subcommand === "delete") console.log(`
236
+ ${colors.bold("forge-cli backups delete")} - Delete a backup configuration
237
+
238
+ ${colors.bold("USAGE:")}
239
+ forge-cli backups delete <backup_id> --server <server_id> [options]
240
+ `);
241
+ else console.log(`
242
+ ${colors.bold("forge-cli backups")} - Manage backup configurations
243
+
244
+ ${colors.bold("USAGE:")}
245
+ forge-cli backups <subcommand> [options]
246
+
247
+ ${colors.bold("SUBCOMMANDS:")}
248
+ list, ls List backup configurations
249
+ get <id> Get backup configuration details
250
+ create Create a new backup configuration
251
+ delete <id> Delete a backup configuration
252
+
253
+ ${colors.bold("OPTIONS:")}
254
+ --server <id> Server ID (required)
255
+ -f, --format <fmt> Output format: json, human, table
256
+
257
+ Run ${colors.cyan("forge-cli backups <subcommand> --help")} for details.
258
+ `);
259
+ }
260
+ /**
261
+ * Shell completion installation command
262
+ */
263
+ var BASH_COMPLETION = `#!/usr/bin/env bash
264
+
265
+ _forge_cli_completions() {
266
+ local cur prev commands subcommands options
267
+
268
+ COMPREPLY=()
269
+ cur="\${COMP_WORDS[COMP_CWORD]}"
270
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
271
+
272
+ # Main commands
273
+ commands="config servers s sites deployments d databases db database-users daemons env nginx certificates certs firewall-rules fw ssh-keys backups commands scheduled-jobs user monitors nginx-templates security-rules redirect-rules recipes completion help"
274
+
275
+ # Subcommands for each command
276
+ local config_cmds="set get delete"
277
+ local servers_cmds="list ls get reboot"
278
+ local sites_cmds="list ls get"
279
+ local deployments_cmds="list ls deploy"
280
+ local databases_cmds="list ls get"
281
+ local database_users_cmds="list ls get create delete"
282
+ local daemons_cmds="list ls get restart"
283
+ local env_cmds="get update"
284
+ local nginx_cmds="get update"
285
+ local certificates_cmds="list ls get activate"
286
+ local firewall_rules_cmds="list ls get"
287
+ local ssh_keys_cmds="list ls get"
288
+ local backups_cmds="list ls get create delete"
289
+ local commands_cmds="list ls get create"
290
+ local scheduled_jobs_cmds="list ls get create delete"
291
+ local user_cmds="get"
292
+ local monitors_cmds="list ls get create delete"
293
+ local nginx_templates_cmds="list ls get create update delete"
294
+ local security_rules_cmds="list ls get create delete"
295
+ local redirect_rules_cmds="list ls get create delete"
296
+ local recipes_cmds="list ls get run"
297
+ local completion_cmds="bash zsh fish"
298
+
299
+ # Global options
300
+ options="--token --server --site -f --format --no-color -h --help -v --version --name --command --content --from --to --provider --frequency --type --operator --threshold --minutes --key --port --ip-address --user --script --servers --domain --password --credential-id --region --size --project-type --directory"
301
+
302
+ # Format options
303
+ local formats="json human table"
304
+
305
+ # Completion logic
306
+ case "\${COMP_CWORD}" in
307
+ 1)
308
+ # Complete main commands
309
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
310
+ ;;
311
+ 2)
312
+ # Complete subcommands based on main command
313
+ case "\${prev}" in
314
+ config)
315
+ COMPREPLY=( $(compgen -W "\${config_cmds}" -- "\${cur}") )
316
+ ;;
317
+ servers|s)
318
+ COMPREPLY=( $(compgen -W "\${servers_cmds}" -- "\${cur}") )
319
+ ;;
320
+ sites)
321
+ COMPREPLY=( $(compgen -W "\${sites_cmds}" -- "\${cur}") )
322
+ ;;
323
+ deployments|d)
324
+ COMPREPLY=( $(compgen -W "\${deployments_cmds}" -- "\${cur}") )
325
+ ;;
326
+ databases|db)
327
+ COMPREPLY=( $(compgen -W "\${databases_cmds}" -- "\${cur}") )
328
+ ;;
329
+ database-users)
330
+ COMPREPLY=( $(compgen -W "\${database_users_cmds}" -- "\${cur}") )
331
+ ;;
332
+ daemons)
333
+ COMPREPLY=( $(compgen -W "\${daemons_cmds}" -- "\${cur}") )
334
+ ;;
335
+ env)
336
+ COMPREPLY=( $(compgen -W "\${env_cmds}" -- "\${cur}") )
337
+ ;;
338
+ nginx)
339
+ COMPREPLY=( $(compgen -W "\${nginx_cmds}" -- "\${cur}") )
340
+ ;;
341
+ certificates|certs)
342
+ COMPREPLY=( $(compgen -W "\${certificates_cmds}" -- "\${cur}") )
343
+ ;;
344
+ firewall-rules|fw)
345
+ COMPREPLY=( $(compgen -W "\${firewall_rules_cmds}" -- "\${cur}") )
346
+ ;;
347
+ ssh-keys)
348
+ COMPREPLY=( $(compgen -W "\${ssh_keys_cmds}" -- "\${cur}") )
349
+ ;;
350
+ backups)
351
+ COMPREPLY=( $(compgen -W "\${backups_cmds}" -- "\${cur}") )
352
+ ;;
353
+ commands)
354
+ COMPREPLY=( $(compgen -W "\${commands_cmds}" -- "\${cur}") )
355
+ ;;
356
+ scheduled-jobs)
357
+ COMPREPLY=( $(compgen -W "\${scheduled_jobs_cmds}" -- "\${cur}") )
358
+ ;;
359
+ user)
360
+ COMPREPLY=( $(compgen -W "\${user_cmds}" -- "\${cur}") )
361
+ ;;
362
+ monitors)
363
+ COMPREPLY=( $(compgen -W "\${monitors_cmds}" -- "\${cur}") )
364
+ ;;
365
+ nginx-templates)
366
+ COMPREPLY=( $(compgen -W "\${nginx_templates_cmds}" -- "\${cur}") )
367
+ ;;
368
+ security-rules)
369
+ COMPREPLY=( $(compgen -W "\${security_rules_cmds}" -- "\${cur}") )
370
+ ;;
371
+ redirect-rules)
372
+ COMPREPLY=( $(compgen -W "\${redirect_rules_cmds}" -- "\${cur}") )
373
+ ;;
374
+ recipes)
375
+ COMPREPLY=( $(compgen -W "\${recipes_cmds}" -- "\${cur}") )
376
+ ;;
377
+ completion)
378
+ COMPREPLY=( $(compgen -W "\${completion_cmds}" -- "\${cur}") )
379
+ ;;
380
+ *)
381
+ COMPREPLY=( $(compgen -W "\${options}" -- "\${cur}") )
382
+ ;;
383
+ esac
384
+ ;;
385
+ *)
386
+ # Complete options and their values
387
+ case "\${prev}" in
388
+ --format|-f)
389
+ COMPREPLY=( $(compgen -W "\${formats}" -- "\${cur}") )
390
+ ;;
391
+ --token|--server|--site|--name|--command|--content|--from|--to|--provider|--frequency|--type|--operator|--threshold|--minutes|--key|--port|--ip-address|--user|--script|--servers|--domain|--password|--credential-id|--region|--size|--project-type|--directory)
392
+ # No completion for values requiring arguments
393
+ COMPREPLY=()
394
+ ;;
395
+ *)
396
+ COMPREPLY=( $(compgen -W "\${options}" -- "\${cur}") )
397
+ ;;
398
+ esac
399
+ ;;
400
+ esac
401
+
402
+ return 0
403
+ }
404
+
405
+ complete -F _forge_cli_completions forge-cli
406
+ `;
407
+ var ZSH_COMPLETION = `#compdef forge-cli
408
+
409
+ _forge_cli() {
410
+ local line state
411
+
412
+ _arguments -C \\
413
+ '1: :->command' \\
414
+ '2: :->subcommand' \\
415
+ '*: :->args'
416
+
417
+ case $state in
418
+ command)
419
+ local -a commands
420
+ commands=(
421
+ 'config:Manage CLI configuration'
422
+ 'servers:Manage servers'
423
+ 's:Manage servers (alias)'
424
+ 'sites:Manage sites'
425
+ 'deployments:Manage deployments'
426
+ 'd:Manage deployments (alias)'
427
+ 'databases:Manage databases'
428
+ 'db:Manage databases (alias)'
429
+ 'database-users:Manage database users'
430
+ 'daemons:Manage daemons'
431
+ 'env:Manage environment variables'
432
+ 'nginx:Manage nginx configuration'
433
+ 'certificates:Manage SSL certificates'
434
+ 'certs:Manage SSL certificates (alias)'
435
+ 'firewall-rules:Manage firewall rules'
436
+ 'fw:Manage firewall rules (alias)'
437
+ 'ssh-keys:Manage SSH keys'
438
+ 'backups:Manage backup configurations'
439
+ 'commands:Manage site commands'
440
+ 'scheduled-jobs:Manage scheduled jobs'
441
+ 'user:Display authenticated user profile'
442
+ 'monitors:Manage server monitors'
443
+ 'nginx-templates:Manage Nginx templates'
444
+ 'security-rules:Manage site security rules'
445
+ 'redirect-rules:Manage site redirect rules'
446
+ 'recipes:Manage recipes'
447
+ 'completion:Generate shell completion script'
448
+ 'help:Show help'
449
+ )
450
+ _describe 'command' commands
451
+ ;;
452
+ subcommand)
453
+ case $line[1] in
454
+ config)
455
+ local -a config_cmds
456
+ config_cmds=(
457
+ 'set:Save API token'
458
+ 'get:Show current token'
459
+ 'delete:Delete stored token'
460
+ )
461
+ _describe 'config command' config_cmds
462
+ ;;
463
+ servers|s)
464
+ local -a servers_cmds
465
+ servers_cmds=(
466
+ 'list:List all servers'
467
+ 'ls:List all servers (alias)'
468
+ 'get:Get server details'
469
+ 'reboot:Reboot a server'
470
+ )
471
+ _describe 'servers command' servers_cmds
472
+ ;;
473
+ sites)
474
+ local -a sites_cmds
475
+ sites_cmds=(
476
+ 'list:List sites'
477
+ 'ls:List sites (alias)'
478
+ 'get:Get site details'
479
+ )
480
+ _describe 'sites command' sites_cmds
481
+ ;;
482
+ deployments|d)
483
+ local -a deployments_cmds
484
+ deployments_cmds=(
485
+ 'list:List deployments'
486
+ 'ls:List deployments (alias)'
487
+ 'deploy:Trigger a deployment'
488
+ )
489
+ _describe 'deployments command' deployments_cmds
490
+ ;;
491
+ databases|db)
492
+ local -a databases_cmds
493
+ databases_cmds=(
494
+ 'list:List databases'
495
+ 'ls:List databases (alias)'
496
+ 'get:Get database details'
497
+ )
498
+ _describe 'databases command' databases_cmds
499
+ ;;
500
+ database-users)
501
+ local -a database_users_cmds
502
+ database_users_cmds=(
503
+ 'list:List database users'
504
+ 'ls:List database users (alias)'
505
+ 'get:Get database user details'
506
+ 'create:Create a database user'
507
+ 'delete:Delete a database user'
508
+ )
509
+ _describe 'database-users command' database_users_cmds
510
+ ;;
511
+ daemons)
512
+ local -a daemons_cmds
513
+ daemons_cmds=(
514
+ 'list:List daemons'
515
+ 'ls:List daemons (alias)'
516
+ 'get:Get daemon details'
517
+ 'restart:Restart a daemon'
518
+ )
519
+ _describe 'daemons command' daemons_cmds
520
+ ;;
521
+ env)
522
+ local -a env_cmds
523
+ env_cmds=(
524
+ 'get:Get env variables'
525
+ 'update:Update env variables'
526
+ )
527
+ _describe 'env command' env_cmds
528
+ ;;
529
+ nginx)
530
+ local -a nginx_cmds
531
+ nginx_cmds=(
532
+ 'get:Get nginx config'
533
+ 'update:Update nginx config'
534
+ )
535
+ _describe 'nginx command' nginx_cmds
536
+ ;;
537
+ certificates|certs)
538
+ local -a certificates_cmds
539
+ certificates_cmds=(
540
+ 'list:List certificates'
541
+ 'ls:List certificates (alias)'
542
+ 'get:Get certificate details'
543
+ 'activate:Activate a certificate'
544
+ )
545
+ _describe 'certificates command' certificates_cmds
546
+ ;;
547
+ firewall-rules|fw)
548
+ local -a firewall_rules_cmds
549
+ firewall_rules_cmds=(
550
+ 'list:List firewall rules'
551
+ 'ls:List firewall rules (alias)'
552
+ 'get:Get firewall rule details'
553
+ )
554
+ _describe 'firewall-rules command' firewall_rules_cmds
555
+ ;;
556
+ ssh-keys)
557
+ local -a ssh_keys_cmds
558
+ ssh_keys_cmds=(
559
+ 'list:List SSH keys'
560
+ 'ls:List SSH keys (alias)'
561
+ 'get:Get SSH key details'
562
+ )
563
+ _describe 'ssh-keys command' ssh_keys_cmds
564
+ ;;
565
+ backups)
566
+ local -a backups_cmds
567
+ backups_cmds=(
568
+ 'list:List backup configurations'
569
+ 'ls:List backup configurations (alias)'
570
+ 'get:Get backup configuration details'
571
+ 'create:Create a backup configuration'
572
+ 'delete:Delete a backup configuration'
573
+ )
574
+ _describe 'backups command' backups_cmds
575
+ ;;
576
+ commands)
577
+ local -a commands_cmds
578
+ commands_cmds=(
579
+ 'list:List commands'
580
+ 'ls:List commands (alias)'
581
+ 'get:Get command details'
582
+ 'create:Execute a command'
583
+ )
584
+ _describe 'commands command' commands_cmds
585
+ ;;
586
+ scheduled-jobs)
587
+ local -a scheduled_jobs_cmds
588
+ scheduled_jobs_cmds=(
589
+ 'list:List scheduled jobs'
590
+ 'ls:List scheduled jobs (alias)'
591
+ 'get:Get scheduled job details'
592
+ 'create:Create a scheduled job'
593
+ 'delete:Delete a scheduled job'
594
+ )
595
+ _describe 'scheduled-jobs command' scheduled_jobs_cmds
596
+ ;;
597
+ user)
598
+ local -a user_cmds
599
+ user_cmds=(
600
+ 'get:Get the authenticated user profile'
601
+ )
602
+ _describe 'user command' user_cmds
603
+ ;;
604
+ monitors)
605
+ local -a monitors_cmds
606
+ monitors_cmds=(
607
+ 'list:List monitors'
608
+ 'ls:List monitors (alias)'
609
+ 'get:Get monitor details'
610
+ 'create:Create a monitor'
611
+ 'delete:Delete a monitor'
612
+ )
613
+ _describe 'monitors command' monitors_cmds
614
+ ;;
615
+ nginx-templates)
616
+ local -a nginx_templates_cmds
617
+ nginx_templates_cmds=(
618
+ 'list:List Nginx templates'
619
+ 'ls:List Nginx templates (alias)'
620
+ 'get:Get Nginx template details'
621
+ 'create:Create a Nginx template'
622
+ 'update:Update a Nginx template'
623
+ 'delete:Delete a Nginx template'
624
+ )
625
+ _describe 'nginx-templates command' nginx_templates_cmds
626
+ ;;
627
+ security-rules)
628
+ local -a security_rules_cmds
629
+ security_rules_cmds=(
630
+ 'list:List security rules'
631
+ 'ls:List security rules (alias)'
632
+ 'get:Get security rule details'
633
+ 'create:Create a security rule'
634
+ 'delete:Delete a security rule'
635
+ )
636
+ _describe 'security-rules command' security_rules_cmds
637
+ ;;
638
+ redirect-rules)
639
+ local -a redirect_rules_cmds
640
+ redirect_rules_cmds=(
641
+ 'list:List redirect rules'
642
+ 'ls:List redirect rules (alias)'
643
+ 'get:Get redirect rule details'
644
+ 'create:Create a redirect rule'
645
+ 'delete:Delete a redirect rule'
646
+ )
647
+ _describe 'redirect-rules command' redirect_rules_cmds
648
+ ;;
649
+ recipes)
650
+ local -a recipes_cmds
651
+ recipes_cmds=(
652
+ 'list:List all recipes'
653
+ 'ls:List all recipes (alias)'
654
+ 'get:Get recipe details'
655
+ 'run:Run a recipe'
656
+ )
657
+ _describe 'recipes command' recipes_cmds
658
+ ;;
659
+ completion)
660
+ local -a completion_cmds
661
+ completion_cmds=(
662
+ 'bash:Generate Bash completion script'
663
+ 'zsh:Generate Zsh completion script'
664
+ 'fish:Generate Fish completion script'
665
+ )
666
+ _describe 'completion shell' completion_cmds
667
+ ;;
668
+ esac
669
+ ;;
670
+ args)
671
+ _arguments \\
672
+ '--token[API token]:token:' \\
673
+ '--server[Server ID]:server id:' \\
674
+ '--site[Site ID]:site id:' \\
675
+ '(-f --format)'{-f,--format}'[Output format]:format:(json human table)' \\
676
+ '--no-color[Disable colored output]' \\
677
+ '(-h --help)'{-h,--help}'[Show help]' \\
678
+ '(-v --version)'{-v,--version}'[Show version]' \\
679
+ '--name[Name]:name:' \\
680
+ '--command[Command]:command:' \\
681
+ '--content[Content]:content:' \\
682
+ '--from[From]:from:' \\
683
+ '--to[To]:to:' \\
684
+ '--provider[Provider]:provider:' \\
685
+ '--frequency[Frequency]:frequency:' \\
686
+ '--type[Type]:type:' \\
687
+ '--operator[Operator]:operator:' \\
688
+ '--threshold[Threshold]:threshold:' \\
689
+ '--minutes[Minutes]:minutes:' \\
690
+ '--key[Key]:key:' \\
691
+ '--port[Port]:port:' \\
692
+ '--ip-address[IP address]:ip address:' \\
693
+ '--user[User]:user:' \\
694
+ '--script[Script]:script:' \\
695
+ '--servers[Servers]:servers:' \\
696
+ '--domain[Domain]:domain:' \\
697
+ '--password[Password]:password:' \\
698
+ '--credential-id[Credential ID]:credential id:' \\
699
+ '--region[Region]:region:' \\
700
+ '--size[Size]:size:' \\
701
+ '--project-type[Project type]:project type:' \\
702
+ '--directory[Directory]:directory:'
703
+ ;;
704
+ esac
705
+ }
706
+
707
+ _forge_cli "$@"
708
+ `;
709
+ var FISH_COMPLETION = `# Completions for forge-cli
710
+
711
+ # Main commands
712
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "config" -d "Manage CLI configuration"
713
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "servers" -d "Manage servers"
714
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "s" -d "Manage servers (alias)"
715
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "sites" -d "Manage sites"
716
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "deployments" -d "Manage deployments"
717
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "d" -d "Manage deployments (alias)"
718
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "databases" -d "Manage databases"
719
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "db" -d "Manage databases (alias)"
720
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "database-users" -d "Manage database users"
721
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "daemons" -d "Manage daemons"
722
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "env" -d "Manage environment variables"
723
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "nginx" -d "Manage nginx configuration"
724
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "certificates" -d "Manage SSL certificates"
725
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "certs" -d "Manage SSL certificates (alias)"
726
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "firewall-rules" -d "Manage firewall rules"
727
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "fw" -d "Manage firewall rules (alias)"
728
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "ssh-keys" -d "Manage SSH keys"
729
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "backups" -d "Manage backup configurations"
730
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "commands" -d "Manage site commands"
731
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "scheduled-jobs" -d "Manage scheduled jobs"
732
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "user" -d "Display authenticated user profile"
733
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "monitors" -d "Manage server monitors"
734
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "nginx-templates" -d "Manage Nginx templates"
735
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "security-rules" -d "Manage site security rules"
736
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "redirect-rules" -d "Manage site redirect rules"
737
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "recipes" -d "Manage recipes"
738
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "completion" -d "Generate shell completion script"
739
+ complete -c forge-cli -f -n "__fish_use_subcommand" -a "help" -d "Show help"
740
+
741
+ # config subcommands
742
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from config" -a "set" -d "Save API token"
743
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from config" -a "get" -d "Show current token"
744
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from config" -a "delete" -d "Delete stored token"
745
+
746
+ # servers subcommands
747
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from servers s" -a "list" -d "List all servers"
748
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from servers s" -a "ls" -d "List all servers (alias)"
749
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from servers s" -a "get" -d "Get server details"
750
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from servers s" -a "reboot" -d "Reboot a server"
751
+
752
+ # sites subcommands
753
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from sites" -a "list" -d "List sites"
754
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from sites" -a "ls" -d "List sites (alias)"
755
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from sites" -a "get" -d "Get site details"
756
+
757
+ # deployments subcommands
758
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from deployments d" -a "list" -d "List deployments"
759
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from deployments d" -a "ls" -d "List deployments (alias)"
760
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from deployments d" -a "deploy" -d "Trigger a deployment"
761
+
762
+ # databases subcommands
763
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from databases db" -a "list" -d "List databases"
764
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from databases db" -a "ls" -d "List databases (alias)"
765
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from databases db" -a "get" -d "Get database details"
766
+
767
+ # database-users subcommands
768
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from database-users" -a "list" -d "List database users"
769
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from database-users" -a "ls" -d "List database users (alias)"
770
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from database-users" -a "get" -d "Get database user details"
771
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from database-users" -a "create" -d "Create a database user"
772
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from database-users" -a "delete" -d "Delete a database user"
773
+
774
+ # daemons subcommands
775
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from daemons" -a "list" -d "List daemons"
776
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from daemons" -a "ls" -d "List daemons (alias)"
777
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from daemons" -a "get" -d "Get daemon details"
778
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from daemons" -a "restart" -d "Restart a daemon"
779
+
780
+ # env subcommands
781
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from env" -a "get" -d "Get env variables"
782
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from env" -a "update" -d "Update env variables"
783
+
784
+ # nginx subcommands
785
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx" -a "get" -d "Get nginx config"
786
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx" -a "update" -d "Update nginx config"
787
+
788
+ # certificates subcommands
789
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from certificates certs" -a "list" -d "List certificates"
790
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from certificates certs" -a "ls" -d "List certificates (alias)"
791
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from certificates certs" -a "get" -d "Get certificate details"
792
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from certificates certs" -a "activate" -d "Activate a certificate"
793
+
794
+ # firewall-rules subcommands
795
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from firewall-rules fw" -a "list" -d "List firewall rules"
796
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from firewall-rules fw" -a "ls" -d "List firewall rules (alias)"
797
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from firewall-rules fw" -a "get" -d "Get firewall rule details"
798
+
799
+ # ssh-keys subcommands
800
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from ssh-keys" -a "list" -d "List SSH keys"
801
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from ssh-keys" -a "ls" -d "List SSH keys (alias)"
802
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from ssh-keys" -a "get" -d "Get SSH key details"
803
+
804
+ # backups subcommands
805
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from backups" -a "list" -d "List backup configurations"
806
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from backups" -a "ls" -d "List backup configurations (alias)"
807
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from backups" -a "get" -d "Get backup configuration details"
808
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from backups" -a "create" -d "Create a backup configuration"
809
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from backups" -a "delete" -d "Delete a backup configuration"
810
+
811
+ # commands subcommands
812
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from commands" -a "list" -d "List commands"
813
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from commands" -a "ls" -d "List commands (alias)"
814
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from commands" -a "get" -d "Get command details"
815
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from commands" -a "create" -d "Execute a command"
816
+
817
+ # scheduled-jobs subcommands
818
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from scheduled-jobs" -a "list" -d "List scheduled jobs"
819
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from scheduled-jobs" -a "ls" -d "List scheduled jobs (alias)"
820
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from scheduled-jobs" -a "get" -d "Get scheduled job details"
821
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from scheduled-jobs" -a "create" -d "Create a scheduled job"
822
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from scheduled-jobs" -a "delete" -d "Delete a scheduled job"
823
+
824
+ # user subcommands
825
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from user" -a "get" -d "Get the authenticated user profile"
826
+
827
+ # monitors subcommands
828
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from monitors" -a "list" -d "List monitors"
829
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from monitors" -a "ls" -d "List monitors (alias)"
830
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from monitors" -a "get" -d "Get monitor details"
831
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from monitors" -a "create" -d "Create a monitor"
832
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from monitors" -a "delete" -d "Delete a monitor"
833
+
834
+ # nginx-templates subcommands
835
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx-templates" -a "list" -d "List Nginx templates"
836
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx-templates" -a "ls" -d "List Nginx templates (alias)"
837
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx-templates" -a "get" -d "Get Nginx template details"
838
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx-templates" -a "create" -d "Create a Nginx template"
839
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx-templates" -a "update" -d "Update a Nginx template"
840
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from nginx-templates" -a "delete" -d "Delete a Nginx template"
841
+
842
+ # security-rules subcommands
843
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from security-rules" -a "list" -d "List security rules"
844
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from security-rules" -a "ls" -d "List security rules (alias)"
845
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from security-rules" -a "get" -d "Get security rule details"
846
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from security-rules" -a "create" -d "Create a security rule"
847
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from security-rules" -a "delete" -d "Delete a security rule"
848
+
849
+ # redirect-rules subcommands
850
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from redirect-rules" -a "list" -d "List redirect rules"
851
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from redirect-rules" -a "ls" -d "List redirect rules (alias)"
852
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from redirect-rules" -a "get" -d "Get redirect rule details"
853
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from redirect-rules" -a "create" -d "Create a redirect rule"
854
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from redirect-rules" -a "delete" -d "Delete a redirect rule"
855
+
856
+ # recipes subcommands
857
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from recipes" -a "list" -d "List all recipes"
858
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from recipes" -a "ls" -d "List all recipes (alias)"
859
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from recipes" -a "get" -d "Get recipe details"
860
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from recipes" -a "run" -d "Run a recipe"
861
+
862
+ # completion subcommands
863
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from completion" -a "bash" -d "Install Bash completion"
864
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from completion" -a "zsh" -d "Install Zsh completion"
865
+ complete -c forge-cli -f -n "__fish_seen_subcommand_from completion" -a "fish" -d "Install Fish completion"
866
+
867
+ # Global options
868
+ complete -c forge-cli -l token -d "API token" -r
869
+ complete -c forge-cli -l server -d "Server ID" -r
870
+ complete -c forge-cli -l site -d "Site ID" -r
871
+ complete -c forge-cli -s f -l format -d "Output format" -xa "json human table"
872
+ complete -c forge-cli -l no-color -d "Disable colored output"
873
+ complete -c forge-cli -s h -l help -d "Show help"
874
+ complete -c forge-cli -s v -l version -d "Show version"
875
+ complete -c forge-cli -l name -d "Name" -r
876
+ complete -c forge-cli -l command -d "Command" -r
877
+ complete -c forge-cli -l content -d "Content" -r
878
+ complete -c forge-cli -l from -d "From" -r
879
+ complete -c forge-cli -l to -d "To" -r
880
+ complete -c forge-cli -l provider -d "Provider" -r
881
+ complete -c forge-cli -l frequency -d "Frequency" -r
882
+ complete -c forge-cli -l type -d "Type" -r
883
+ complete -c forge-cli -l operator -d "Operator" -r
884
+ complete -c forge-cli -l threshold -d "Threshold" -r
885
+ complete -c forge-cli -l minutes -d "Minutes" -r
886
+ complete -c forge-cli -l key -d "Key" -r
887
+ complete -c forge-cli -l port -d "Port" -r
888
+ complete -c forge-cli -l ip-address -d "IP address" -r
889
+ complete -c forge-cli -l user -d "User" -r
890
+ complete -c forge-cli -l script -d "Script" -r
891
+ complete -c forge-cli -l servers -d "Servers" -r
892
+ complete -c forge-cli -l domain -d "Domain" -r
893
+ complete -c forge-cli -l password -d "Password" -r
894
+ complete -c forge-cli -l credential-id -d "Credential ID" -r
895
+ complete -c forge-cli -l region -d "Region" -r
896
+ complete -c forge-cli -l size -d "Size" -r
897
+ complete -c forge-cli -l project-type -d "Project type" -r
898
+ complete -c forge-cli -l directory -d "Directory" -r
899
+ `;
900
+ /**
901
+ * Get the appropriate completion file path for the shell
902
+ */
903
+ function getCompletionPath(shell) {
904
+ const home = homedir();
905
+ switch (shell) {
906
+ case "bash": return join(home, ".local/share/bash-completion/completions/forge-cli");
907
+ case "zsh": return join(home, ".zfunc/_forge-cli");
908
+ case "fish": return join(process.env["XDG_CONFIG_HOME"] ?? join(home, ".config"), "fish/completions/forge-cli.fish");
909
+ default: throw new Error(`Unknown shell: ${shell}`);
910
+ }
911
+ }
912
+ function showCompletionHelp() {
913
+ console.log(`
914
+ ${colors.bold("forge-cli completion")} - Install shell completion
915
+
916
+ ${colors.bold("USAGE:")}
917
+ forge-cli completion <shell> [--print]
918
+
919
+ ${colors.bold("SHELLS:")}
920
+ bash Install Bash completion
921
+ zsh Install Zsh completion
922
+ fish Install Fish completion
923
+
924
+ ${colors.bold("OPTIONS:")}
925
+ --print Print completion script instead of installing
926
+
927
+ ${colors.bold("INSTALLATION:")}
928
+ The completion script is automatically installed to the appropriate
929
+ standard directory for your shell. After installation, restart your
930
+ shell to activate completions.
931
+
932
+ ${colors.bold("Bash:")}
933
+ forge-cli completion bash
934
+ # Installs to: ~/.local/share/bash-completion/completions/forge-cli
935
+ # Then run: exec bash
936
+
937
+ ${colors.bold("Zsh:")}
938
+ forge-cli completion zsh
939
+ # Installs to: ~/.zfunc/_forge-cli
940
+ # Ensure fpath includes ~/.zfunc (add to ~/.zshrc before compinit):
941
+ # fpath=(~/.zfunc $fpath)
942
+ # Then run: exec zsh
943
+
944
+ ${colors.bold("Fish:")}
945
+ forge-cli completion fish
946
+ # Installs to: ~/.config/fish/completions/forge-cli.fish
947
+ # Completions are loaded automatically
948
+
949
+ ${colors.bold("PRINT ONLY:")}
950
+ Use --print to output the script without installing:
951
+
952
+ forge-cli completion bash --print > my-completion.sh
953
+ forge-cli completion zsh --print | less
954
+ `);
955
+ }
956
+ function handleCompletionCommand(shell, options = {}) {
957
+ const shouldPrint = options["print"] !== void 0;
958
+ const shellLower = shell.toLowerCase();
959
+ let script;
960
+ switch (shellLower) {
961
+ case "bash":
962
+ script = BASH_COMPLETION;
963
+ break;
964
+ case "zsh":
965
+ script = ZSH_COMPLETION;
966
+ break;
967
+ case "fish":
968
+ script = FISH_COMPLETION;
969
+ break;
970
+ default:
971
+ console.error(`${colors.red("✗")} Unknown shell: ${shell}. Supported shells: bash, zsh, fish`);
972
+ console.error(`Run ${colors.cyan("forge-cli completion --help")} for usage information.`);
973
+ process.exit(1);
974
+ return;
975
+ }
976
+ if (shouldPrint) {
977
+ process.stdout.write(script);
978
+ return;
979
+ }
980
+ const installPath = getCompletionPath(shellLower);
981
+ const dir = installPath.substring(0, installPath.lastIndexOf("/"));
982
+ try {
983
+ mkdirSync(dir, { recursive: true });
984
+ writeFileSync(installPath, script, "utf8");
985
+ console.log(`${colors.green("✓")} Installed ${shell} completion to ${colors.cyan(installPath)}`);
986
+ console.log();
987
+ console.log(`${colors.bold("Next steps:")}`);
988
+ switch (shellLower) {
989
+ case "bash":
990
+ console.log(` 1. Restart your shell: ${colors.cyan("exec bash")}`);
991
+ console.log(` 2. Or source the file: ${colors.cyan(`source ${installPath}`)}`);
992
+ break;
993
+ case "zsh":
994
+ console.log(` 1. Ensure ${colors.cyan("~/.zfunc")} is in your $fpath (add to ~/.zshrc before compinit):`);
995
+ console.log(` ${colors.cyan("fpath=(~/.zfunc $fpath)")}`);
996
+ console.log(` 2. Restart your shell: ${colors.cyan("exec zsh")}`);
997
+ break;
998
+ case "fish":
999
+ console.log(` Completions are loaded automatically. Restart fish if needed.`);
1000
+ break;
1001
+ }
1002
+ } catch (error) {
1003
+ console.error(`${colors.red("✗")} Failed to install completion: ${error instanceof Error ? error.message : String(error)}`);
1004
+ process.exit(1);
1005
+ }
1006
+ }
1007
+ function requireServerAndSiteRaw$3(ctx, usage) {
1008
+ const server = String(ctx.options.server ?? "");
1009
+ const site = String(ctx.options.site ?? "");
1010
+ if (!server) exitWithValidationError("server_id", usage, ctx.formatter);
1011
+ if (!site) exitWithValidationError("site_id", usage, ctx.formatter);
1012
+ return {
1013
+ server,
1014
+ site
1015
+ };
1016
+ }
1017
+ async function certificatesList(ctx) {
1018
+ const { server, site } = requireServerAndSiteRaw$3(ctx, "forge-cli certificates list --server <server_id> --site <site_id>");
1019
+ await runCommand(async () => {
1020
+ const token = ctx.getToken();
1021
+ const execCtx = ctx.createExecutorContext(token);
1022
+ const server_id = await resolveServerId(server, execCtx);
1023
+ const result = await listCertificates({
1024
+ server_id,
1025
+ site_id: await resolveSiteId(site, server_id, execCtx)
1026
+ }, execCtx);
1027
+ ctx.formatter.outputList(result.data, [
1028
+ "id",
1029
+ "domain",
1030
+ "type",
1031
+ "status",
1032
+ "active"
1033
+ ], "No certificates found.", (c) => `${String(c.id).padEnd(8)} ${c.domain.padEnd(40)} ${c.type.padEnd(10)} ${c.status.padEnd(12)} ${c.active ? "active" : "—"}`);
1034
+ }, ctx.formatter);
1035
+ }
1036
+ async function certificatesGet(args, ctx) {
1037
+ const [id] = args;
1038
+ const usage = "forge-cli certificates get <cert_id> --server <server_id> --site <site_id>";
1039
+ if (!id) exitWithValidationError("certificate_id", usage, ctx.formatter);
1040
+ const { server, site } = requireServerAndSiteRaw$3(ctx, usage);
1041
+ await runCommand(async () => {
1042
+ const token = ctx.getToken();
1043
+ const execCtx = ctx.createExecutorContext(token);
1044
+ const server_id = await resolveServerId(server, execCtx);
1045
+ const result = await getCertificate({
1046
+ server_id,
1047
+ site_id: await resolveSiteId(site, server_id, execCtx),
1048
+ id
1049
+ }, execCtx);
1050
+ ctx.formatter.outputOne(result.data, [
1051
+ "id",
1052
+ "domain",
1053
+ "type",
1054
+ "status",
1055
+ "request_status",
1056
+ "active",
1057
+ "existing",
1058
+ "created_at"
1059
+ ]);
1060
+ }, ctx.formatter);
1061
+ }
1062
+ async function certificatesActivate(args, ctx) {
1063
+ const [id] = args;
1064
+ const usage = "forge-cli certificates activate <cert_id> --server <server_id> --site <site_id>";
1065
+ if (!id) exitWithValidationError("certificate_id", usage, ctx.formatter);
1066
+ const { server, site } = requireServerAndSiteRaw$3(ctx, usage);
1067
+ await runCommand(async () => {
1068
+ const token = ctx.getToken();
1069
+ const execCtx = ctx.createExecutorContext(token);
1070
+ const server_id = await resolveServerId(server, execCtx);
1071
+ await activateCertificate({
1072
+ server_id,
1073
+ site_id: await resolveSiteId(site, server_id, execCtx),
1074
+ id
1075
+ }, execCtx);
1076
+ ctx.formatter.success(`Certificate ${id} activated.`);
1077
+ }, ctx.formatter);
1078
+ }
1079
+ const handleCertificatesCommand = createCommandRouter({
1080
+ resource: "certificates",
1081
+ handlers: {
1082
+ list: certificatesList,
1083
+ ls: certificatesList,
1084
+ get: [certificatesGet, "args"],
1085
+ activate: [certificatesActivate, "args"]
1086
+ },
1087
+ writeSubcommands: ["activate"]
1088
+ });
1089
+ function showCertificatesHelp(subcommand) {
1090
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1091
+ ${colors.bold("forge-cli certificates list")} - List certificates for a site
1092
+
1093
+ ${colors.bold("USAGE:")}
1094
+ forge-cli certificates list --server <server_id> --site <site_id> [options]
1095
+ `);
1096
+ else if (subcommand === "get") console.log(`
1097
+ ${colors.bold("forge-cli certificates get")} - Get certificate details
1098
+
1099
+ ${colors.bold("USAGE:")}
1100
+ forge-cli certificates get <cert_id> --server <server_id> --site <site_id>
1101
+ `);
1102
+ else if (subcommand === "activate") console.log(`
1103
+ ${colors.bold("forge-cli certificates activate")} - Activate a certificate
1104
+
1105
+ ${colors.bold("USAGE:")}
1106
+ forge-cli certificates activate <cert_id> --server <server_id> --site <site_id>
1107
+ `);
1108
+ else console.log(`
1109
+ ${colors.bold("forge-cli certificates")} - Manage SSL certificates
1110
+
1111
+ ${colors.bold("USAGE:")}
1112
+ forge-cli certificates <subcommand> [options]
1113
+
1114
+ ${colors.bold("ALIASES:")}
1115
+ forge-cli certs
1116
+
1117
+ ${colors.bold("SUBCOMMANDS:")}
1118
+ list, ls List certificates
1119
+ get <id> Get certificate details
1120
+ activate <id> Activate a certificate
1121
+
1122
+ ${colors.bold("OPTIONS:")}
1123
+ --server <id> Server ID (required)
1124
+ --site <id> Site ID (required)
1125
+ -f, --format <fmt> Output format: json, human, table
1126
+
1127
+ Run ${colors.cyan("forge-cli certificates <subcommand> --help")} for details.
1128
+ `);
1129
+ }
1130
+ function requireServerAndSiteRaw$2(ctx, usage) {
1131
+ const server = String(ctx.options.server ?? "");
1132
+ const site = String(ctx.options.site ?? "");
1133
+ if (!server) exitWithValidationError("server_id", usage, ctx.formatter);
1134
+ if (!site) exitWithValidationError("site_id", usage, ctx.formatter);
1135
+ return {
1136
+ server,
1137
+ site
1138
+ };
1139
+ }
1140
+ async function commandsList(ctx) {
1141
+ const { server, site } = requireServerAndSiteRaw$2(ctx, "forge-cli commands list --server <server_id> --site <site_id>");
1142
+ await runCommand(async () => {
1143
+ const token = ctx.getToken();
1144
+ const execCtx = ctx.createExecutorContext(token);
1145
+ const server_id = await resolveServerId(server, execCtx);
1146
+ const result = await listCommands({
1147
+ server_id,
1148
+ site_id: await resolveSiteId(site, server_id, execCtx)
1149
+ }, execCtx);
1150
+ ctx.formatter.outputList(result.data, [
1151
+ "id",
1152
+ "command",
1153
+ "status",
1154
+ "created_at"
1155
+ ], "No commands found.", (c) => `${String(c.id).padEnd(8)} ${c.command.padEnd(50)} ${c.status.padEnd(12)} ${c.created_at}`);
1156
+ }, ctx.formatter);
1157
+ }
1158
+ async function commandsGet(args, ctx) {
1159
+ const [id] = args;
1160
+ const usage = "forge-cli commands get <command_id> --server <server_id> --site <site_id>";
1161
+ if (!id) exitWithValidationError("command_id", usage, ctx.formatter);
1162
+ const { server, site } = requireServerAndSiteRaw$2(ctx, usage);
1163
+ await runCommand(async () => {
1164
+ const token = ctx.getToken();
1165
+ const execCtx = ctx.createExecutorContext(token);
1166
+ const server_id = await resolveServerId(server, execCtx);
1167
+ const result = await getCommand({
1168
+ server_id,
1169
+ site_id: await resolveSiteId(site, server_id, execCtx),
1170
+ id
1171
+ }, execCtx);
1172
+ ctx.formatter.outputOne(result.data, [
1173
+ "id",
1174
+ "command",
1175
+ "status",
1176
+ "user_name",
1177
+ "created_at"
1178
+ ]);
1179
+ }, ctx.formatter);
1180
+ }
1181
+ async function commandsCreate(ctx) {
1182
+ const usage = "forge-cli commands create --server <server_id> --site <site_id> --command <command>";
1183
+ const { server, site } = requireServerAndSiteRaw$2(ctx, usage);
1184
+ const command = String(ctx.options.command ?? "");
1185
+ if (!command) exitWithValidationError("command", usage, ctx.formatter);
1186
+ await runCommand(async () => {
1187
+ const token = ctx.getToken();
1188
+ const execCtx = ctx.createExecutorContext(token);
1189
+ const server_id = await resolveServerId(server, execCtx);
1190
+ const result = await createCommand({
1191
+ server_id,
1192
+ site_id: await resolveSiteId(site, server_id, execCtx),
1193
+ command
1194
+ }, execCtx);
1195
+ ctx.formatter.outputOne(result.data, [
1196
+ "id",
1197
+ "command",
1198
+ "status",
1199
+ "created_at"
1200
+ ]);
1201
+ }, ctx.formatter);
1202
+ }
1203
+ const handleCommandsCommand = createCommandRouter({
1204
+ resource: "commands",
1205
+ handlers: {
1206
+ list: commandsList,
1207
+ ls: commandsList,
1208
+ get: [commandsGet, "args"],
1209
+ create: commandsCreate
1210
+ },
1211
+ writeSubcommands: ["create"]
1212
+ });
1213
+ function showCommandsHelp(subcommand) {
1214
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1215
+ ${colors.bold("forge-cli commands list")} - List commands executed on a site
1216
+
1217
+ ${colors.bold("USAGE:")}
1218
+ forge-cli commands list --server <server_id> --site <site_id> [options]
1219
+
1220
+ ${colors.bold("OPTIONS:")}
1221
+ --server <id> Server ID (required)
1222
+ --site <id> Site ID (required)
1223
+ -f, --format <fmt> Output format: json, human, table
1224
+ `);
1225
+ else if (subcommand === "get") console.log(`
1226
+ ${colors.bold("forge-cli commands get")} - Get command details
1227
+
1228
+ ${colors.bold("USAGE:")}
1229
+ forge-cli commands get <command_id> --server <server_id> --site <site_id> [options]
1230
+ `);
1231
+ else if (subcommand === "create") console.log(`
1232
+ ${colors.bold("forge-cli commands create")} - Execute a command on a site
1233
+
1234
+ ${colors.bold("USAGE:")}
1235
+ forge-cli commands create --server <server_id> --site <site_id> --command <command> [options]
1236
+
1237
+ ${colors.bold("OPTIONS:")}
1238
+ --server <id> Server ID (required)
1239
+ --site <id> Site ID (required)
1240
+ --command <cmd> Command to execute (required)
1241
+ -f, --format <fmt> Output format: json, human, table
1242
+ `);
1243
+ else console.log(`
1244
+ ${colors.bold("forge-cli commands")} - Manage site commands
1245
+
1246
+ ${colors.bold("USAGE:")}
1247
+ forge-cli commands <subcommand> [options]
1248
+
1249
+ ${colors.bold("SUBCOMMANDS:")}
1250
+ list, ls List commands
1251
+ get <id> Get command details
1252
+ create Execute a command on a site
1253
+
1254
+ ${colors.bold("OPTIONS:")}
1255
+ --server <id> Server ID (required)
1256
+ --site <id> Site ID (required)
1257
+ -f, --format <fmt> Output format: json, human, table
1258
+
1259
+ Run ${colors.cyan("forge-cli commands <subcommand> --help")} for details.
1260
+ `);
1261
+ }
1262
+ /**
1263
+ * Config command — manage forge-cli configuration
1264
+ */
1265
+ function showConfigHelp() {
1266
+ console.log(`
1267
+ ${colors.bold("forge-cli config")} - Manage CLI configuration
1268
+
1269
+ ${colors.bold("USAGE:")}
1270
+ forge-cli config <subcommand> [options]
1271
+
1272
+ ${colors.bold("SUBCOMMANDS:")}
1273
+ set <token> Save API token to config file
1274
+ get Show current API token (masked)
1275
+ delete Delete stored API token
1276
+
1277
+ ${colors.bold("EXAMPLES:")}
1278
+ forge-cli config set YOUR_FORGE_TOKEN
1279
+ forge-cli config get
1280
+ forge-cli config delete
1281
+ `);
1282
+ }
1283
+ function handleConfigCommand(subcommand, args, options) {
1284
+ const format = String(options.format ?? options.f ?? "human");
1285
+ const formatter = new OutputFormatter(format, options["no-color"] === true);
1286
+ const store = createConfigStore();
1287
+ switch (subcommand) {
1288
+ case "set": {
1289
+ const [token] = args;
1290
+ if (!token) {
1291
+ formatter.error("Token is required. Usage: forge-cli config set <token>");
1292
+ process.exit(1);
1293
+ return;
1294
+ }
1295
+ setToken(token, store);
1296
+ formatter.success("API token saved.");
1297
+ break;
1298
+ }
1299
+ case "get": {
1300
+ const token = getToken(store);
1301
+ if (!token) {
1302
+ formatter.warning("No API token configured.");
1303
+ formatter.info("Run: forge-cli config set <token>");
1304
+ } else {
1305
+ const masked = token.length > 8 ? `${token.slice(0, 4)}${"*".repeat(token.length - 8)}${token.slice(-4)}` : "****";
1306
+ if (format === "json") formatter.output({ apiToken: masked });
1307
+ else console.log(`apiToken: ${masked}`);
1308
+ }
1309
+ break;
1310
+ }
1311
+ case "delete":
1312
+ deleteToken(store);
1313
+ formatter.success("API token deleted.");
1314
+ break;
1315
+ default:
1316
+ showConfigHelp();
1317
+ break;
1318
+ }
1319
+ }
1320
+ async function daemonsList(ctx) {
1321
+ const server = String(ctx.options.server ?? "");
1322
+ if (!server) exitWithValidationError("server_id", "forge-cli daemons list --server <server_id>", ctx.formatter);
1323
+ await runCommand(async () => {
1324
+ const token = ctx.getToken();
1325
+ const execCtx = ctx.createExecutorContext(token);
1326
+ const result = await listDaemons({ server_id: await resolveServerId(server, execCtx) }, execCtx);
1327
+ ctx.formatter.outputList(result.data, [
1328
+ "id",
1329
+ "command",
1330
+ "user",
1331
+ "status"
1332
+ ], "No daemons found.", (d) => `${String(d.id).padEnd(8)} ${d.command.padEnd(50)} ${d.user.padEnd(16)} ${d.status}`);
1333
+ }, ctx.formatter);
1334
+ }
1335
+ async function daemonsGet(args, ctx) {
1336
+ const [id] = args;
1337
+ const server = String(ctx.options.server ?? "");
1338
+ if (!id) exitWithValidationError("daemon_id", "forge-cli daemons get <daemon_id> --server <server_id>", ctx.formatter);
1339
+ if (!server) exitWithValidationError("server_id", "forge-cli daemons get <daemon_id> --server <server_id>", ctx.formatter);
1340
+ await runCommand(async () => {
1341
+ const token = ctx.getToken();
1342
+ const execCtx = ctx.createExecutorContext(token);
1343
+ const result = await getDaemon({
1344
+ server_id: await resolveServerId(server, execCtx),
1345
+ id
1346
+ }, execCtx);
1347
+ ctx.formatter.outputOne(result.data, [
1348
+ "id",
1349
+ "command",
1350
+ "user",
1351
+ "directory",
1352
+ "processes",
1353
+ "status",
1354
+ "created_at"
1355
+ ]);
1356
+ }, ctx.formatter);
1357
+ }
1358
+ async function daemonsRestart(args, ctx) {
1359
+ const [id] = args;
1360
+ const server = String(ctx.options.server ?? "");
1361
+ if (!id) exitWithValidationError("daemon_id", "forge-cli daemons restart <daemon_id> --server <server_id>", ctx.formatter);
1362
+ if (!server) exitWithValidationError("server_id", "forge-cli daemons restart <daemon_id> --server <server_id>", ctx.formatter);
1363
+ await runCommand(async () => {
1364
+ const token = ctx.getToken();
1365
+ const execCtx = ctx.createExecutorContext(token);
1366
+ await restartDaemon({
1367
+ server_id: await resolveServerId(server, execCtx),
1368
+ id
1369
+ }, execCtx);
1370
+ ctx.formatter.success(`Daemon ${id} restarted.`);
1371
+ }, ctx.formatter);
1372
+ }
1373
+ const handleDaemonsCommand = createCommandRouter({
1374
+ resource: "daemons",
1375
+ handlers: {
1376
+ list: daemonsList,
1377
+ ls: daemonsList,
1378
+ get: [daemonsGet, "args"],
1379
+ restart: [daemonsRestart, "args"]
1380
+ },
1381
+ writeSubcommands: ["restart"]
1382
+ });
1383
+ function showDaemonsHelp(subcommand) {
1384
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1385
+ ${colors.bold("forge-cli daemons list")} - List daemons on a server
1386
+
1387
+ ${colors.bold("USAGE:")}
1388
+ forge-cli daemons list --server <server_id> [options]
1389
+ `);
1390
+ else if (subcommand === "get") console.log(`
1391
+ ${colors.bold("forge-cli daemons get")} - Get daemon details
1392
+
1393
+ ${colors.bold("USAGE:")}
1394
+ forge-cli daemons get <daemon_id> --server <server_id>
1395
+ `);
1396
+ else if (subcommand === "restart") console.log(`
1397
+ ${colors.bold("forge-cli daemons restart")} - Restart a daemon
1398
+
1399
+ ${colors.bold("USAGE:")}
1400
+ forge-cli daemons restart <daemon_id> --server <server_id>
1401
+ `);
1402
+ else console.log(`
1403
+ ${colors.bold("forge-cli daemons")} - Manage daemons
1404
+
1405
+ ${colors.bold("USAGE:")}
1406
+ forge-cli daemons <subcommand> [options]
1407
+
1408
+ ${colors.bold("SUBCOMMANDS:")}
1409
+ list, ls List daemons
1410
+ get <id> Get daemon details
1411
+ restart <id> Restart a daemon
1412
+
1413
+ ${colors.bold("OPTIONS:")}
1414
+ --server <id> Server ID (required)
1415
+ -f, --format <fmt> Output format: json, human, table
1416
+
1417
+ Run ${colors.cyan("forge-cli daemons <subcommand> --help")} for details.
1418
+ `);
1419
+ }
1420
+ async function databasesList(ctx) {
1421
+ const server = String(ctx.options.server ?? "");
1422
+ if (!server) exitWithValidationError("server_id", "forge-cli databases list --server <server_id>", ctx.formatter);
1423
+ await runCommand(async () => {
1424
+ const token = ctx.getToken();
1425
+ const execCtx = ctx.createExecutorContext(token);
1426
+ const result = await listDatabases({ server_id: await resolveServerId(server, execCtx) }, execCtx);
1427
+ ctx.formatter.outputList(result.data, [
1428
+ "id",
1429
+ "name",
1430
+ "status"
1431
+ ], "No databases found.", (db) => `${String(db.id).padEnd(8)} ${db.name.padEnd(30)} ${db.status}`);
1432
+ }, ctx.formatter);
1433
+ }
1434
+ async function databasesGet(args, ctx) {
1435
+ const [id] = args;
1436
+ const server = String(ctx.options.server ?? "");
1437
+ if (!id) exitWithValidationError("database_id", "forge-cli databases get <database_id> --server <server_id>", ctx.formatter);
1438
+ if (!server) exitWithValidationError("server_id", "forge-cli databases get <database_id> --server <server_id>", ctx.formatter);
1439
+ await runCommand(async () => {
1440
+ const token = ctx.getToken();
1441
+ const execCtx = ctx.createExecutorContext(token);
1442
+ const result = await getDatabase({
1443
+ server_id: await resolveServerId(server, execCtx),
1444
+ id
1445
+ }, execCtx);
1446
+ ctx.formatter.outputOne(result.data, [
1447
+ "id",
1448
+ "name",
1449
+ "status",
1450
+ "created_at"
1451
+ ]);
1452
+ }, ctx.formatter);
1453
+ }
1454
+ const handleDatabasesCommand = createCommandRouter({
1455
+ resource: "databases",
1456
+ handlers: {
1457
+ list: databasesList,
1458
+ ls: databasesList,
1459
+ get: [databasesGet, "args"]
1460
+ }
1461
+ });
1462
+ function showDatabasesHelp(subcommand) {
1463
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1464
+ ${colors.bold("forge-cli databases list")} - List databases on a server
1465
+
1466
+ ${colors.bold("USAGE:")}
1467
+ forge-cli databases list --server <server_id> [options]
1468
+
1469
+ ${colors.bold("OPTIONS:")}
1470
+ --server <id> Server ID (required)
1471
+ -f, --format <fmt> Output format: json, human, table
1472
+ `);
1473
+ else if (subcommand === "get") console.log(`
1474
+ ${colors.bold("forge-cli databases get")} - Get database details
1475
+
1476
+ ${colors.bold("USAGE:")}
1477
+ forge-cli databases get <database_id> --server <server_id> [options]
1478
+ `);
1479
+ else console.log(`
1480
+ ${colors.bold("forge-cli databases")} - Manage databases
1481
+
1482
+ ${colors.bold("USAGE:")}
1483
+ forge-cli databases <subcommand> [options]
1484
+
1485
+ ${colors.bold("ALIASES:")}
1486
+ forge-cli db
1487
+
1488
+ ${colors.bold("SUBCOMMANDS:")}
1489
+ list, ls List databases
1490
+ get <id> Get database details
1491
+
1492
+ ${colors.bold("OPTIONS:")}
1493
+ --server <id> Server ID (required)
1494
+ -f, --format <fmt> Output format: json, human, table
1495
+
1496
+ Run ${colors.cyan("forge-cli databases <subcommand> --help")} for details.
1497
+ `);
1498
+ }
1499
+ async function databaseUsersList(ctx) {
1500
+ const server = String(ctx.options.server ?? "");
1501
+ if (!server) exitWithValidationError("server_id", "forge-cli database-users list --server <server_id>", ctx.formatter);
1502
+ await runCommand(async () => {
1503
+ const token = ctx.getToken();
1504
+ const execCtx = ctx.createExecutorContext(token);
1505
+ const result = await listDatabaseUsers({ server_id: await resolveServerId(server, execCtx) }, execCtx);
1506
+ ctx.formatter.outputList(result.data, [
1507
+ "id",
1508
+ "name",
1509
+ "status"
1510
+ ], "No database users found.", (u) => `${String(u.id).padEnd(8)} ${u.name.padEnd(30)} ${u.status}`);
1511
+ }, ctx.formatter);
1512
+ }
1513
+ async function databaseUsersGet(args, ctx) {
1514
+ const [id] = args;
1515
+ const server = String(ctx.options.server ?? "");
1516
+ if (!id) exitWithValidationError("user_id", "forge-cli database-users get <user_id> --server <server_id>", ctx.formatter);
1517
+ if (!server) exitWithValidationError("server_id", "forge-cli database-users get <user_id> --server <server_id>", ctx.formatter);
1518
+ await runCommand(async () => {
1519
+ const token = ctx.getToken();
1520
+ const execCtx = ctx.createExecutorContext(token);
1521
+ const result = await getDatabaseUser({
1522
+ server_id: await resolveServerId(server, execCtx),
1523
+ id
1524
+ }, execCtx);
1525
+ ctx.formatter.outputOne(result.data, [
1526
+ "id",
1527
+ "name",
1528
+ "status",
1529
+ "databases",
1530
+ "created_at"
1531
+ ]);
1532
+ }, ctx.formatter);
1533
+ }
1534
+ async function databaseUsersCreate(ctx) {
1535
+ const server = String(ctx.options.server ?? "");
1536
+ const name = String(ctx.options.name ?? "");
1537
+ const password = String(ctx.options.password ?? "");
1538
+ const databasesRaw = ctx.options.databases;
1539
+ const databases = Array.isArray(databasesRaw) ? databasesRaw.map(Number) : databasesRaw ? [Number(databasesRaw)] : void 0;
1540
+ if (!server) exitWithValidationError("server_id", "forge-cli database-users create --server <server_id> --name <name> --password <password>", ctx.formatter);
1541
+ if (!name) exitWithValidationError("name", "forge-cli database-users create --server <server_id> --name <name> --password <password>", ctx.formatter);
1542
+ if (!password) exitWithValidationError("password", "forge-cli database-users create --server <server_id> --name <name> --password <password>", ctx.formatter);
1543
+ await runCommand(async () => {
1544
+ const token = ctx.getToken();
1545
+ const execCtx = ctx.createExecutorContext(token);
1546
+ const result = await createDatabaseUser({
1547
+ server_id: await resolveServerId(server, execCtx),
1548
+ name,
1549
+ password,
1550
+ ...databases ? { databases } : {}
1551
+ }, execCtx);
1552
+ ctx.formatter.outputOne(result.data, [
1553
+ "id",
1554
+ "name",
1555
+ "status",
1556
+ "databases",
1557
+ "created_at"
1558
+ ]);
1559
+ }, ctx.formatter);
1560
+ }
1561
+ async function databaseUsersDelete(args, ctx) {
1562
+ const [id] = args;
1563
+ const server = String(ctx.options.server ?? "");
1564
+ if (!id) exitWithValidationError("user_id", "forge-cli database-users delete <user_id> --server <server_id>", ctx.formatter);
1565
+ if (!server) exitWithValidationError("server_id", "forge-cli database-users delete <user_id> --server <server_id>", ctx.formatter);
1566
+ await runCommand(async () => {
1567
+ const token = ctx.getToken();
1568
+ const execCtx = ctx.createExecutorContext(token);
1569
+ await deleteDatabaseUser({
1570
+ server_id: await resolveServerId(server, execCtx),
1571
+ id
1572
+ }, execCtx);
1573
+ ctx.formatter.success(`Database user ${id} deleted.`);
1574
+ }, ctx.formatter);
1575
+ }
1576
+ const handleDatabaseUsersCommand = createCommandRouter({
1577
+ resource: "database-users",
1578
+ handlers: {
1579
+ list: databaseUsersList,
1580
+ ls: databaseUsersList,
1581
+ get: [databaseUsersGet, "args"],
1582
+ create: databaseUsersCreate,
1583
+ delete: [databaseUsersDelete, "args"]
1584
+ },
1585
+ writeSubcommands: ["create", "delete"]
1586
+ });
1587
+ function showDatabaseUsersHelp(subcommand) {
1588
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1589
+ ${colors.bold("forge-cli database-users list")} - List database users on a server
1590
+
1591
+ ${colors.bold("USAGE:")}
1592
+ forge-cli database-users list --server <server_id> [options]
1593
+
1594
+ ${colors.bold("OPTIONS:")}
1595
+ --server <id> Server ID (required)
1596
+ -f, --format <fmt> Output format: json, human, table
1597
+ `);
1598
+ else if (subcommand === "get") console.log(`
1599
+ ${colors.bold("forge-cli database-users get")} - Get database user details
1600
+
1601
+ ${colors.bold("USAGE:")}
1602
+ forge-cli database-users get <user_id> --server <server_id> [options]
1603
+ `);
1604
+ else if (subcommand === "create") console.log(`
1605
+ ${colors.bold("forge-cli database-users create")} - Create a new database user
1606
+
1607
+ ${colors.bold("USAGE:")}
1608
+ forge-cli database-users create --server <server_id> --name <name> --password <password> [options]
1609
+
1610
+ ${colors.bold("OPTIONS:")}
1611
+ --server <id> Server ID (required)
1612
+ --name <name> Database user name (required)
1613
+ --password <pass> User password (required)
1614
+ --databases <ids> Comma-separated database IDs to grant access to (optional)
1615
+ -f, --format <fmt> Output format: json, human, table
1616
+ `);
1617
+ else if (subcommand === "delete") console.log(`
1618
+ ${colors.bold("forge-cli database-users delete")} - Delete a database user
1619
+
1620
+ ${colors.bold("USAGE:")}
1621
+ forge-cli database-users delete <user_id> --server <server_id> [options]
1622
+ `);
1623
+ else console.log(`
1624
+ ${colors.bold("forge-cli database-users")} - Manage database users
1625
+
1626
+ ${colors.bold("USAGE:")}
1627
+ forge-cli database-users <subcommand> [options]
1628
+
1629
+ ${colors.bold("SUBCOMMANDS:")}
1630
+ list, ls List database users
1631
+ get <id> Get database user details
1632
+ create Create a new database user
1633
+ delete <id> Delete a database user
1634
+
1635
+ ${colors.bold("OPTIONS:")}
1636
+ --server <id> Server ID (required)
1637
+ -f, --format <fmt> Output format: json, human, table
1638
+
1639
+ Run ${colors.cyan("forge-cli database-users <subcommand> --help")} for details.
1640
+ `);
1641
+ }
1642
+ async function deploymentsList(ctx) {
1643
+ const server = String(ctx.options.server ?? "");
1644
+ const site = String(ctx.options.site ?? "");
1645
+ if (!server) exitWithValidationError("server_id", "forge-cli deployments list --server <server_id> --site <site_id>", ctx.formatter);
1646
+ if (!site) exitWithValidationError("site_id", "forge-cli deployments list --server <server_id> --site <site_id>", ctx.formatter);
1647
+ await runCommand(async () => {
1648
+ const token = ctx.getToken();
1649
+ const execCtx = ctx.createExecutorContext(token);
1650
+ const server_id = await resolveServerId(server, execCtx);
1651
+ const result = await listDeployments({
1652
+ server_id,
1653
+ site_id: await resolveSiteId(site, server_id, execCtx)
1654
+ }, execCtx);
1655
+ ctx.formatter.outputList(result.data, [
1656
+ "id",
1657
+ "status",
1658
+ "commit_hash",
1659
+ "started_at"
1660
+ ], "No deployments found.", (d) => `${String(d.id).padEnd(8)} ${d.status.padEnd(12)} ${(d.commit_hash ?? "—").padEnd(10)} ${d.started_at}`);
1661
+ }, ctx.formatter);
1662
+ }
1663
+ async function deploymentsDeploy(ctx) {
1664
+ const server = String(ctx.options.server ?? "");
1665
+ const site = String(ctx.options.site ?? "");
1666
+ if (!server) exitWithValidationError("server_id", "forge-cli deployments deploy --server <server_id> --site <site_id>", ctx.formatter);
1667
+ if (!site) exitWithValidationError("site_id", "forge-cli deployments deploy --server <server_id> --site <site_id>", ctx.formatter);
1668
+ await runCommand(async () => {
1669
+ const token = ctx.getToken();
1670
+ const execCtx = ctx.createExecutorContext(token);
1671
+ const server_id = await resolveServerId(server, execCtx);
1672
+ const site_id = await resolveSiteId(site, server_id, execCtx);
1673
+ const result = await deploySiteAndWait({
1674
+ server_id,
1675
+ site_id,
1676
+ onProgress: ({ status, elapsed_ms }) => {
1677
+ process.stderr.write(`\rDeploying… ${status} (${(elapsed_ms / 1e3).toFixed(1)}s)`);
1678
+ }
1679
+ }, execCtx);
1680
+ process.stderr.write("\n");
1681
+ const elapsedSec = (result.data.elapsed_ms / 1e3).toFixed(1);
1682
+ if (result.data.status === "success") ctx.formatter.success(`Deployment succeeded for site ${site_id} (${elapsedSec}s).`);
1683
+ else ctx.formatter.success(`Deployment failed for site ${site_id} (${elapsedSec}s).`);
1684
+ if (result.data.log) ctx.formatter.output(result.data.log);
1685
+ }, ctx.formatter);
1686
+ }
1687
+ const handleDeploymentsCommand = createCommandRouter({
1688
+ resource: "deployments",
1689
+ handlers: {
1690
+ list: deploymentsList,
1691
+ ls: deploymentsList,
1692
+ deploy: deploymentsDeploy
1693
+ },
1694
+ writeSubcommands: ["deploy"]
1695
+ });
1696
+ function showDeploymentsHelp(subcommand) {
1697
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1698
+ ${colors.bold("forge-cli deployments list")} - List deployments for a site
1699
+
1700
+ ${colors.bold("USAGE:")}
1701
+ forge-cli deployments list --server <server_id> --site <site_id> [options]
1702
+
1703
+ ${colors.bold("OPTIONS:")}
1704
+ --server <id> Server ID (required)
1705
+ --site <id> Site ID (required)
1706
+ -f, --format <fmt> Output format: json, human, table
1707
+ `);
1708
+ else if (subcommand === "deploy") console.log(`
1709
+ ${colors.bold("forge-cli deployments deploy")} - Trigger a deployment
1710
+
1711
+ ${colors.bold("USAGE:")}
1712
+ forge-cli deployments deploy --server <server_id> --site <site_id>
1713
+ `);
1714
+ else console.log(`
1715
+ ${colors.bold("forge-cli deployments")} - Manage deployments
1716
+
1717
+ ${colors.bold("USAGE:")}
1718
+ forge-cli deployments <subcommand> [options]
1719
+
1720
+ ${colors.bold("ALIASES:")}
1721
+ forge-cli d
1722
+
1723
+ ${colors.bold("SUBCOMMANDS:")}
1724
+ list, ls List deployments for a site
1725
+ deploy Trigger a deployment
1726
+
1727
+ ${colors.bold("OPTIONS:")}
1728
+ --server <id> Server ID (required)
1729
+ --site <id> Site ID (required)
1730
+ -f, --format <fmt> Output format: json, human, table
1731
+
1732
+ Run ${colors.cyan("forge-cli deployments <subcommand> --help")} for details.
1733
+ `);
1734
+ }
1735
+ async function envGet(ctx) {
1736
+ const server = String(ctx.options.server ?? "");
1737
+ const site = String(ctx.options.site ?? "");
1738
+ if (!server) exitWithValidationError("server_id", "forge-cli env get --server <server_id> --site <site_id>", ctx.formatter);
1739
+ if (!site) exitWithValidationError("site_id", "forge-cli env get --server <server_id> --site <site_id>", ctx.formatter);
1740
+ await runCommand(async () => {
1741
+ const token = ctx.getToken();
1742
+ const execCtx = ctx.createExecutorContext(token);
1743
+ const server_id = await resolveServerId(server, execCtx);
1744
+ const result = await getEnv({
1745
+ server_id,
1746
+ site_id: await resolveSiteId(site, server_id, execCtx)
1747
+ }, execCtx);
1748
+ if (ctx.formatter.isJson()) console.log(JSON.stringify({ content: result.data }));
1749
+ else console.log(result.data);
1750
+ }, ctx.formatter);
1751
+ }
1752
+ async function envUpdate(ctx) {
1753
+ const server = String(ctx.options.server ?? "");
1754
+ const site = String(ctx.options.site ?? "");
1755
+ const content = String(ctx.options.content ?? "");
1756
+ if (!server) exitWithValidationError("server_id", "forge-cli env update --server <server_id> --site <site_id> --content <content>", ctx.formatter);
1757
+ if (!site) exitWithValidationError("site_id", "forge-cli env update --server <server_id> --site <site_id> --content <content>", ctx.formatter);
1758
+ if (!content) exitWithValidationError("content", "forge-cli env update --server <server_id> --site <site_id> --content <content>", ctx.formatter);
1759
+ await runCommand(async () => {
1760
+ const token = ctx.getToken();
1761
+ const execCtx = ctx.createExecutorContext(token);
1762
+ const server_id = await resolveServerId(server, execCtx);
1763
+ await updateEnv({
1764
+ server_id,
1765
+ site_id: await resolveSiteId(site, server_id, execCtx),
1766
+ content
1767
+ }, execCtx);
1768
+ ctx.formatter.success("Environment variables updated.");
1769
+ }, ctx.formatter);
1770
+ }
1771
+ const handleEnvCommand = createCommandRouter({
1772
+ resource: "env",
1773
+ handlers: {
1774
+ get: envGet,
1775
+ update: envUpdate
1776
+ },
1777
+ writeSubcommands: ["update"]
1778
+ });
1779
+ function showEnvHelp(subcommand) {
1780
+ if (subcommand === "get") console.log(`
1781
+ ${colors.bold("forge-cli env get")} - Get environment variables
1782
+
1783
+ ${colors.bold("USAGE:")}
1784
+ forge-cli env get --server <server_id> --site <site_id>
1785
+ `);
1786
+ else if (subcommand === "update") console.log(`
1787
+ ${colors.bold("forge-cli env update")} - Update environment variables
1788
+
1789
+ ${colors.bold("USAGE:")}
1790
+ forge-cli env update --server <server_id> --site <site_id> --content <env_content>
1791
+ `);
1792
+ else console.log(`
1793
+ ${colors.bold("forge-cli env")} - Manage environment variables
1794
+
1795
+ ${colors.bold("USAGE:")}
1796
+ forge-cli env <subcommand> [options]
1797
+
1798
+ ${colors.bold("SUBCOMMANDS:")}
1799
+ get Get environment variables
1800
+ update Update environment variables
1801
+
1802
+ ${colors.bold("OPTIONS:")}
1803
+ --server <id> Server ID (required)
1804
+ --site <id> Site ID (required)
1805
+ --content <str> New env content (for update)
1806
+ -f, --format <fmt> Output format: json, human
1807
+
1808
+ Run ${colors.cyan("forge-cli env <subcommand> --help")} for details.
1809
+ `);
1810
+ }
1811
+ async function firewallRulesList(ctx) {
1812
+ const server = String(ctx.options.server ?? "");
1813
+ if (!server) exitWithValidationError("server_id", "forge-cli firewall-rules list --server <server_id>", ctx.formatter);
1814
+ await runCommand(async () => {
1815
+ const token = ctx.getToken();
1816
+ const execCtx = ctx.createExecutorContext(token);
1817
+ const result = await listFirewallRules({ server_id: await resolveServerId(server, execCtx) }, execCtx);
1818
+ ctx.formatter.outputList(result.data, [
1819
+ "id",
1820
+ "name",
1821
+ "port",
1822
+ "type",
1823
+ "ip_address",
1824
+ "status"
1825
+ ], "No firewall rules found.", (r) => `${String(r.id).padEnd(8)} ${r.name.padEnd(20)} ${String(r.port).padEnd(8)} ${r.type.padEnd(8)} ${(r.ip_address ?? "any").padEnd(16)} ${r.status}`);
1826
+ }, ctx.formatter);
1827
+ }
1828
+ async function firewallRulesGet(args, ctx) {
1829
+ const [id] = args;
1830
+ const server = String(ctx.options.server ?? "");
1831
+ if (!id) exitWithValidationError("firewall_rule_id", "forge-cli firewall-rules get <rule_id> --server <server_id>", ctx.formatter);
1832
+ if (!server) exitWithValidationError("server_id", "forge-cli firewall-rules get <rule_id> --server <server_id>", ctx.formatter);
1833
+ await runCommand(async () => {
1834
+ const token = ctx.getToken();
1835
+ const execCtx = ctx.createExecutorContext(token);
1836
+ const result = await getFirewallRule({
1837
+ server_id: await resolveServerId(server, execCtx),
1838
+ id
1839
+ }, execCtx);
1840
+ ctx.formatter.outputOne(result.data, [
1841
+ "id",
1842
+ "name",
1843
+ "port",
1844
+ "type",
1845
+ "ip_address",
1846
+ "status",
1847
+ "created_at"
1848
+ ]);
1849
+ }, ctx.formatter);
1850
+ }
1851
+ const handleFirewallRulesCommand = createCommandRouter({
1852
+ resource: "firewall-rules",
1853
+ handlers: {
1854
+ list: firewallRulesList,
1855
+ ls: firewallRulesList,
1856
+ get: [firewallRulesGet, "args"]
1857
+ }
1858
+ });
1859
+ function showFirewallRulesHelp(subcommand) {
1860
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1861
+ ${colors.bold("forge-cli firewall-rules list")} - List firewall rules on a server
1862
+
1863
+ ${colors.bold("USAGE:")}
1864
+ forge-cli firewall-rules list --server <server_id> [options]
1865
+ `);
1866
+ else if (subcommand === "get") console.log(`
1867
+ ${colors.bold("forge-cli firewall-rules get")} - Get firewall rule details
1868
+
1869
+ ${colors.bold("USAGE:")}
1870
+ forge-cli firewall-rules get <rule_id> --server <server_id>
1871
+ `);
1872
+ else console.log(`
1873
+ ${colors.bold("forge-cli firewall-rules")} - Manage firewall rules
1874
+
1875
+ ${colors.bold("USAGE:")}
1876
+ forge-cli firewall-rules <subcommand> [options]
1877
+
1878
+ ${colors.bold("ALIASES:")}
1879
+ forge-cli fw
1880
+
1881
+ ${colors.bold("SUBCOMMANDS:")}
1882
+ list, ls List firewall rules
1883
+ get <id> Get firewall rule details
1884
+
1885
+ ${colors.bold("OPTIONS:")}
1886
+ --server <id> Server ID (required)
1887
+ -f, --format <fmt> Output format: json, human, table
1888
+
1889
+ Run ${colors.cyan("forge-cli firewall-rules <subcommand> --help")} for details.
1890
+ `);
1891
+ }
1892
+ async function monitorsList(ctx) {
1893
+ const server = String(ctx.options.server ?? "");
1894
+ if (!server) exitWithValidationError("server_id", "forge-cli monitors list --server <server_id>", ctx.formatter);
1895
+ await runCommand(async () => {
1896
+ const token = ctx.getToken();
1897
+ const execCtx = ctx.createExecutorContext(token);
1898
+ const result = await listMonitors({ server_id: await resolveServerId(server, execCtx) }, execCtx);
1899
+ ctx.formatter.outputList(result.data, [
1900
+ "id",
1901
+ "type",
1902
+ "operator",
1903
+ "threshold",
1904
+ "state"
1905
+ ], "No monitors found.", (m) => `${String(m.id).padEnd(8)} ${m.type.padEnd(20)} ${m.operator.padEnd(8)} ${String(m.threshold).padEnd(6)} ${m.state}`);
1906
+ }, ctx.formatter);
1907
+ }
1908
+ async function monitorsGet(args, ctx) {
1909
+ const [id] = args;
1910
+ const server = String(ctx.options.server ?? "");
1911
+ if (!id) exitWithValidationError("monitor_id", "forge-cli monitors get <monitor_id> --server <server_id>", ctx.formatter);
1912
+ if (!server) exitWithValidationError("server_id", "forge-cli monitors get <monitor_id> --server <server_id>", ctx.formatter);
1913
+ await runCommand(async () => {
1914
+ const token = ctx.getToken();
1915
+ const execCtx = ctx.createExecutorContext(token);
1916
+ const result = await getMonitor({
1917
+ server_id: await resolveServerId(server, execCtx),
1918
+ id
1919
+ }, execCtx);
1920
+ ctx.formatter.outputOne(result.data, [
1921
+ "id",
1922
+ "type",
1923
+ "operator",
1924
+ "threshold",
1925
+ "minutes",
1926
+ "state",
1927
+ "state_changed_at"
1928
+ ]);
1929
+ }, ctx.formatter);
1930
+ }
1931
+ async function monitorsCreate(ctx) {
1932
+ const server = String(ctx.options.server ?? "");
1933
+ const type = String(ctx.options.type ?? "");
1934
+ const operator = String(ctx.options.operator ?? "");
1935
+ const threshold = Number(ctx.options.threshold ?? 0);
1936
+ const minutes = Number(ctx.options.minutes ?? 0);
1937
+ if (!server) exitWithValidationError("server_id", "forge-cli monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>", ctx.formatter);
1938
+ if (!type) exitWithValidationError("type", "forge-cli monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>", ctx.formatter);
1939
+ if (!operator) exitWithValidationError("operator", "forge-cli monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes>", ctx.formatter);
1940
+ await runCommand(async () => {
1941
+ const token = ctx.getToken();
1942
+ const execCtx = ctx.createExecutorContext(token);
1943
+ const result = await createMonitor({
1944
+ server_id: await resolveServerId(server, execCtx),
1945
+ type,
1946
+ operator,
1947
+ threshold,
1948
+ minutes
1949
+ }, execCtx);
1950
+ ctx.formatter.outputOne(result.data, [
1951
+ "id",
1952
+ "type",
1953
+ "operator",
1954
+ "threshold",
1955
+ "minutes",
1956
+ "state"
1957
+ ]);
1958
+ }, ctx.formatter);
1959
+ }
1960
+ async function monitorsDelete(args, ctx) {
1961
+ const [id] = args;
1962
+ const server = String(ctx.options.server ?? "");
1963
+ if (!id) exitWithValidationError("monitor_id", "forge-cli monitors delete <monitor_id> --server <server_id>", ctx.formatter);
1964
+ if (!server) exitWithValidationError("server_id", "forge-cli monitors delete <monitor_id> --server <server_id>", ctx.formatter);
1965
+ await runCommand(async () => {
1966
+ const token = ctx.getToken();
1967
+ const execCtx = ctx.createExecutorContext(token);
1968
+ await deleteMonitor({
1969
+ server_id: await resolveServerId(server, execCtx),
1970
+ id
1971
+ }, execCtx);
1972
+ ctx.formatter.success(`Monitor ${id} deleted.`);
1973
+ }, ctx.formatter);
1974
+ }
1975
+ const handleMonitorsCommand = createCommandRouter({
1976
+ resource: "monitors",
1977
+ handlers: {
1978
+ list: monitorsList,
1979
+ ls: monitorsList,
1980
+ get: [monitorsGet, "args"],
1981
+ create: monitorsCreate,
1982
+ delete: [monitorsDelete, "args"]
1983
+ },
1984
+ writeSubcommands: ["create", "delete"]
1985
+ });
1986
+ function showMonitorsHelp(subcommand) {
1987
+ if (subcommand === "list" || subcommand === "ls") console.log(`
1988
+ ${colors.bold("forge-cli monitors list")} - List monitors on a server
1989
+
1990
+ ${colors.bold("USAGE:")}
1991
+ forge-cli monitors list --server <server_id> [options]
1992
+
1993
+ ${colors.bold("OPTIONS:")}
1994
+ --server <id> Server ID (required)
1995
+ -f, --format <fmt> Output format: json, human, table
1996
+ `);
1997
+ else if (subcommand === "get") console.log(`
1998
+ ${colors.bold("forge-cli monitors get")} - Get monitor details
1999
+
2000
+ ${colors.bold("USAGE:")}
2001
+ forge-cli monitors get <monitor_id> --server <server_id> [options]
2002
+ `);
2003
+ else if (subcommand === "create") console.log(`
2004
+ ${colors.bold("forge-cli monitors create")} - Create a new monitor
2005
+
2006
+ ${colors.bold("USAGE:")}
2007
+ forge-cli monitors create --server <server_id> --type <type> --operator <operator> --threshold <threshold> --minutes <minutes> [options]
2008
+
2009
+ ${colors.bold("OPTIONS:")}
2010
+ --server <id> Server ID (required)
2011
+ --type <type> Monitor type (required)
2012
+ --operator <op> Comparison operator (required)
2013
+ --threshold <num> Alert threshold value (required)
2014
+ --minutes <num> Duration in minutes (required)
2015
+ -f, --format <fmt> Output format: json, human, table
2016
+ `);
2017
+ else if (subcommand === "delete") console.log(`
2018
+ ${colors.bold("forge-cli monitors delete")} - Delete a monitor
2019
+
2020
+ ${colors.bold("USAGE:")}
2021
+ forge-cli monitors delete <monitor_id> --server <server_id> [options]
2022
+ `);
2023
+ else console.log(`
2024
+ ${colors.bold("forge-cli monitors")} - Manage server monitors
2025
+
2026
+ ${colors.bold("USAGE:")}
2027
+ forge-cli monitors <subcommand> [options]
2028
+
2029
+ ${colors.bold("SUBCOMMANDS:")}
2030
+ list, ls List monitors
2031
+ get <id> Get monitor details
2032
+ create Create a new monitor
2033
+ delete <id> Delete a monitor
2034
+
2035
+ ${colors.bold("OPTIONS:")}
2036
+ --server <id> Server ID (required)
2037
+ -f, --format <fmt> Output format: json, human, table
2038
+
2039
+ Run ${colors.cyan("forge-cli monitors <subcommand> --help")} for details.
2040
+ `);
2041
+ }
2042
+ async function nginxGet(ctx) {
2043
+ const server = String(ctx.options.server ?? "");
2044
+ const site = String(ctx.options.site ?? "");
2045
+ if (!server) exitWithValidationError("server_id", "forge-cli nginx get --server <server_id> --site <site_id>", ctx.formatter);
2046
+ if (!site) exitWithValidationError("site_id", "forge-cli nginx get --server <server_id> --site <site_id>", ctx.formatter);
2047
+ await runCommand(async () => {
2048
+ const token = ctx.getToken();
2049
+ const execCtx = ctx.createExecutorContext(token);
2050
+ const server_id = await resolveServerId(server, execCtx);
2051
+ const result = await getNginxConfig({
2052
+ server_id,
2053
+ site_id: await resolveSiteId(site, server_id, execCtx)
2054
+ }, execCtx);
2055
+ if (ctx.formatter.isJson()) console.log(JSON.stringify({ content: result.data }));
2056
+ else console.log(result.data);
2057
+ }, ctx.formatter);
2058
+ }
2059
+ async function nginxUpdate(ctx) {
2060
+ const server = String(ctx.options.server ?? "");
2061
+ const site = String(ctx.options.site ?? "");
2062
+ const content = String(ctx.options.content ?? "");
2063
+ if (!server) exitWithValidationError("server_id", "forge-cli nginx update --server <server_id> --site <site_id> --content <content>", ctx.formatter);
2064
+ if (!site) exitWithValidationError("site_id", "forge-cli nginx update --server <server_id> --site <site_id> --content <content>", ctx.formatter);
2065
+ if (!content) exitWithValidationError("content", "forge-cli nginx update --server <server_id> --site <site_id> --content <content>", ctx.formatter);
2066
+ await runCommand(async () => {
2067
+ const token = ctx.getToken();
2068
+ const execCtx = ctx.createExecutorContext(token);
2069
+ const server_id = await resolveServerId(server, execCtx);
2070
+ await updateNginxConfig({
2071
+ server_id,
2072
+ site_id: await resolveSiteId(site, server_id, execCtx),
2073
+ content
2074
+ }, execCtx);
2075
+ ctx.formatter.success("Nginx configuration updated.");
2076
+ }, ctx.formatter);
2077
+ }
2078
+ const handleNginxCommand = createCommandRouter({
2079
+ resource: "nginx",
2080
+ handlers: {
2081
+ get: nginxGet,
2082
+ update: nginxUpdate
2083
+ },
2084
+ writeSubcommands: ["update"]
2085
+ });
2086
+ function showNginxHelp(subcommand) {
2087
+ if (subcommand === "get") console.log(`
2088
+ ${colors.bold("forge-cli nginx get")} - Get nginx configuration
2089
+
2090
+ ${colors.bold("USAGE:")}
2091
+ forge-cli nginx get --server <server_id> --site <site_id>
2092
+ `);
2093
+ else if (subcommand === "update") console.log(`
2094
+ ${colors.bold("forge-cli nginx update")} - Update nginx configuration
2095
+
2096
+ ${colors.bold("USAGE:")}
2097
+ forge-cli nginx update --server <server_id> --site <site_id> --content <nginx_config>
2098
+ `);
2099
+ else console.log(`
2100
+ ${colors.bold("forge-cli nginx")} - Manage nginx configuration
2101
+
2102
+ ${colors.bold("USAGE:")}
2103
+ forge-cli nginx <subcommand> [options]
2104
+
2105
+ ${colors.bold("SUBCOMMANDS:")}
2106
+ get Get nginx configuration
2107
+ update Update nginx configuration
2108
+
2109
+ ${colors.bold("OPTIONS:")}
2110
+ --server <id> Server ID (required)
2111
+ --site <id> Site ID (required)
2112
+ --content <str> New nginx config (for update)
2113
+
2114
+ Run ${colors.cyan("forge-cli nginx <subcommand> --help")} for details.
2115
+ `);
2116
+ }
2117
+ async function nginxTemplatesList(ctx) {
2118
+ const server = String(ctx.options.server ?? "");
2119
+ if (!server) exitWithValidationError("server_id", "forge-cli nginx-templates list --server <server_id>", ctx.formatter);
2120
+ await runCommand(async () => {
2121
+ const token = ctx.getToken();
2122
+ const execCtx = ctx.createExecutorContext(token);
2123
+ const result = await listNginxTemplates({ server_id: await resolveServerId(server, execCtx) }, execCtx);
2124
+ ctx.formatter.outputList(result.data, [
2125
+ "id",
2126
+ "name",
2127
+ "created_at"
2128
+ ], "No Nginx templates found.", (t) => `${String(t.id).padEnd(8)} ${t.name.padEnd(40)} ${t.created_at}`);
2129
+ }, ctx.formatter);
2130
+ }
2131
+ async function nginxTemplatesGet(args, ctx) {
2132
+ const [id] = args;
2133
+ const server = String(ctx.options.server ?? "");
2134
+ if (!id) exitWithValidationError("template_id", "forge-cli nginx-templates get <template_id> --server <server_id>", ctx.formatter);
2135
+ if (!server) exitWithValidationError("server_id", "forge-cli nginx-templates get <template_id> --server <server_id>", ctx.formatter);
2136
+ await runCommand(async () => {
2137
+ const token = ctx.getToken();
2138
+ const execCtx = ctx.createExecutorContext(token);
2139
+ const result = await getNginxTemplate({
2140
+ server_id: await resolveServerId(server, execCtx),
2141
+ id
2142
+ }, execCtx);
2143
+ ctx.formatter.outputOne(result.data, [
2144
+ "id",
2145
+ "name",
2146
+ "created_at",
2147
+ "content"
2148
+ ]);
2149
+ }, ctx.formatter);
2150
+ }
2151
+ async function nginxTemplatesCreate(ctx) {
2152
+ const server = String(ctx.options.server ?? "");
2153
+ const name = String(ctx.options.name ?? "");
2154
+ const content = String(ctx.options.content ?? "");
2155
+ if (!server) exitWithValidationError("server_id", "forge-cli nginx-templates create --server <server_id> --name <name> --content <content>", ctx.formatter);
2156
+ if (!name) exitWithValidationError("name", "forge-cli nginx-templates create --server <server_id> --name <name> --content <content>", ctx.formatter);
2157
+ if (!content) exitWithValidationError("content", "forge-cli nginx-templates create --server <server_id> --name <name> --content <content>", ctx.formatter);
2158
+ await runCommand(async () => {
2159
+ const token = ctx.getToken();
2160
+ const execCtx = ctx.createExecutorContext(token);
2161
+ const result = await createNginxTemplate({
2162
+ server_id: await resolveServerId(server, execCtx),
2163
+ name,
2164
+ content
2165
+ }, execCtx);
2166
+ ctx.formatter.outputOne(result.data, [
2167
+ "id",
2168
+ "name",
2169
+ "created_at"
2170
+ ]);
2171
+ }, ctx.formatter);
2172
+ }
2173
+ async function nginxTemplatesUpdate(args, ctx) {
2174
+ const [id] = args;
2175
+ const server = String(ctx.options.server ?? "");
2176
+ if (!id) exitWithValidationError("template_id", "forge-cli nginx-templates update <template_id> --server <server_id>", ctx.formatter);
2177
+ if (!server) exitWithValidationError("server_id", "forge-cli nginx-templates update <template_id> --server <server_id>", ctx.formatter);
2178
+ await runCommand(async () => {
2179
+ const token = ctx.getToken();
2180
+ const execCtx = ctx.createExecutorContext(token);
2181
+ const result = await updateNginxTemplate({
2182
+ server_id: await resolveServerId(server, execCtx),
2183
+ id,
2184
+ name: ctx.options.name ? String(ctx.options.name) : void 0,
2185
+ content: ctx.options.content ? String(ctx.options.content) : void 0
2186
+ }, execCtx);
2187
+ ctx.formatter.outputOne(result.data, [
2188
+ "id",
2189
+ "name",
2190
+ "created_at"
2191
+ ]);
2192
+ }, ctx.formatter);
2193
+ }
2194
+ async function nginxTemplatesDelete(args, ctx) {
2195
+ const [id] = args;
2196
+ const server = String(ctx.options.server ?? "");
2197
+ if (!id) exitWithValidationError("template_id", "forge-cli nginx-templates delete <template_id> --server <server_id>", ctx.formatter);
2198
+ if (!server) exitWithValidationError("server_id", "forge-cli nginx-templates delete <template_id> --server <server_id>", ctx.formatter);
2199
+ await runCommand(async () => {
2200
+ const token = ctx.getToken();
2201
+ const execCtx = ctx.createExecutorContext(token);
2202
+ await deleteNginxTemplate({
2203
+ server_id: await resolveServerId(server, execCtx),
2204
+ id
2205
+ }, execCtx);
2206
+ ctx.formatter.success(`Nginx template ${id} deleted.`);
2207
+ }, ctx.formatter);
2208
+ }
2209
+ const handleNginxTemplatesCommand = createCommandRouter({
2210
+ resource: "nginx-templates",
2211
+ handlers: {
2212
+ list: nginxTemplatesList,
2213
+ ls: nginxTemplatesList,
2214
+ get: [nginxTemplatesGet, "args"],
2215
+ create: nginxTemplatesCreate,
2216
+ update: [nginxTemplatesUpdate, "args"],
2217
+ delete: [nginxTemplatesDelete, "args"]
2218
+ },
2219
+ writeSubcommands: [
2220
+ "create",
2221
+ "update",
2222
+ "delete"
2223
+ ]
2224
+ });
2225
+ function showNginxTemplatesHelp(subcommand) {
2226
+ if (subcommand === "list" || subcommand === "ls") console.log(`
2227
+ ${colors.bold("forge-cli nginx-templates list")} - List Nginx templates on a server
2228
+
2229
+ ${colors.bold("USAGE:")}
2230
+ forge-cli nginx-templates list --server <server_id> [options]
2231
+
2232
+ ${colors.bold("OPTIONS:")}
2233
+ --server <id> Server ID (required)
2234
+ -f, --format <fmt> Output format: json, human, table
2235
+ `);
2236
+ else if (subcommand === "get") console.log(`
2237
+ ${colors.bold("forge-cli nginx-templates get")} - Get Nginx template details
2238
+
2239
+ ${colors.bold("USAGE:")}
2240
+ forge-cli nginx-templates get <template_id> --server <server_id> [options]
2241
+ `);
2242
+ else if (subcommand === "create") console.log(`
2243
+ ${colors.bold("forge-cli nginx-templates create")} - Create a new Nginx template
2244
+
2245
+ ${colors.bold("USAGE:")}
2246
+ forge-cli nginx-templates create --server <server_id> --name <name> --content <content> [options]
2247
+
2248
+ ${colors.bold("OPTIONS:")}
2249
+ --server <id> Server ID (required)
2250
+ --name <name> Template name (required)
2251
+ --content <text> Template content (required)
2252
+ -f, --format <fmt> Output format: json, human, table
2253
+ `);
2254
+ else if (subcommand === "update") console.log(`
2255
+ ${colors.bold("forge-cli nginx-templates update")} - Update an Nginx template
2256
+
2257
+ ${colors.bold("USAGE:")}
2258
+ forge-cli nginx-templates update <template_id> --server <server_id> [options]
2259
+
2260
+ ${colors.bold("OPTIONS:")}
2261
+ --server <id> Server ID (required)
2262
+ --name <name> New template name (optional)
2263
+ --content <text> New template content (optional)
2264
+ -f, --format <fmt> Output format: json, human, table
2265
+ `);
2266
+ else if (subcommand === "delete") console.log(`
2267
+ ${colors.bold("forge-cli nginx-templates delete")} - Delete an Nginx template
2268
+
2269
+ ${colors.bold("USAGE:")}
2270
+ forge-cli nginx-templates delete <template_id> --server <server_id> [options]
2271
+ `);
2272
+ else console.log(`
2273
+ ${colors.bold("forge-cli nginx-templates")} - Manage Nginx templates
2274
+
2275
+ ${colors.bold("USAGE:")}
2276
+ forge-cli nginx-templates <subcommand> [options]
2277
+
2278
+ ${colors.bold("SUBCOMMANDS:")}
2279
+ list, ls List Nginx templates
2280
+ get <id> Get Nginx template details
2281
+ create Create a new Nginx template
2282
+ update <id> Update an Nginx template
2283
+ delete <id> Delete an Nginx template
2284
+
2285
+ ${colors.bold("OPTIONS:")}
2286
+ --server <id> Server ID (required)
2287
+ -f, --format <fmt> Output format: json, human, table
2288
+
2289
+ Run ${colors.cyan("forge-cli nginx-templates <subcommand> --help")} for details.
2290
+ `);
2291
+ }
2292
+ async function recipesList(ctx) {
2293
+ await runCommand(async () => {
2294
+ const token = ctx.getToken();
2295
+ const result = await listRecipes({}, ctx.createExecutorContext(token));
2296
+ ctx.formatter.outputList(result.data, [
2297
+ "id",
2298
+ "name",
2299
+ "user",
2300
+ "created_at"
2301
+ ], "No recipes found.", (r) => `${String(r.id).padEnd(8)} ${r.name.padEnd(40)} ${r.user.padEnd(16)} ${r.created_at}`);
2302
+ }, ctx.formatter);
2303
+ }
2304
+ async function recipesGet(args, ctx) {
2305
+ const [id] = args;
2306
+ if (!id) exitWithValidationError("id", "forge-cli recipes get <recipe_id>", ctx.formatter);
2307
+ await runCommand(async () => {
2308
+ const token = ctx.getToken();
2309
+ const execCtx = ctx.createExecutorContext(token);
2310
+ const result = await getRecipe({ id }, execCtx);
2311
+ ctx.formatter.outputOne(result.data, [
2312
+ "id",
2313
+ "name",
2314
+ "user",
2315
+ "created_at",
2316
+ "script"
2317
+ ]);
2318
+ }, ctx.formatter);
2319
+ }
2320
+ async function recipesRun(args, ctx) {
2321
+ const [id] = args;
2322
+ const serversRaw = String(ctx.options.servers ?? "");
2323
+ if (!id) exitWithValidationError("id", "forge-cli recipes run <recipe_id> --servers <ids>", ctx.formatter);
2324
+ if (!serversRaw) exitWithValidationError("servers", "forge-cli recipes run <recipe_id> --servers <server_id1,server_id2,...>", ctx.formatter);
2325
+ const servers = serversRaw.split(",").map((s) => Number(s.trim())).filter((n) => !isNaN(n));
2326
+ await runCommand(async () => {
2327
+ const token = ctx.getToken();
2328
+ const execCtx = ctx.createExecutorContext(token);
2329
+ await runRecipe({
2330
+ id,
2331
+ servers
2332
+ }, execCtx);
2333
+ ctx.formatter.success(`Recipe ${id} dispatched to ${servers.length} server(s).`);
2334
+ }, ctx.formatter);
2335
+ }
2336
+ const handleRecipesCommand = createCommandRouter({
2337
+ resource: "recipes",
2338
+ handlers: {
2339
+ list: recipesList,
2340
+ ls: recipesList,
2341
+ get: [recipesGet, "args"],
2342
+ run: [recipesRun, "args"]
2343
+ },
2344
+ writeSubcommands: ["run"]
2345
+ });
2346
+ function showRecipesHelp(subcommand) {
2347
+ if (subcommand === "list" || subcommand === "ls") console.log(`
2348
+ ${colors.bold("forge-cli recipes list")} - List all recipes
2349
+
2350
+ ${colors.bold("USAGE:")}
2351
+ forge-cli recipes list [options]
2352
+ `);
2353
+ else if (subcommand === "get") console.log(`
2354
+ ${colors.bold("forge-cli recipes get")} - Get recipe details
2355
+
2356
+ ${colors.bold("USAGE:")}
2357
+ forge-cli recipes get <recipe_id>
2358
+ `);
2359
+ else if (subcommand === "run") console.log(`
2360
+ ${colors.bold("forge-cli recipes run")} - Run a recipe on servers
2361
+
2362
+ ${colors.bold("USAGE:")}
2363
+ forge-cli recipes run <recipe_id> --servers <server_id1,server_id2,...>
2364
+
2365
+ ${colors.bold("OPTIONS:")}
2366
+ --servers <ids> Comma-separated server IDs to run recipe on
2367
+ `);
2368
+ else console.log(`
2369
+ ${colors.bold("forge-cli recipes")} - Manage recipes
2370
+
2371
+ ${colors.bold("USAGE:")}
2372
+ forge-cli recipes <subcommand> [options]
2373
+
2374
+ ${colors.bold("SUBCOMMANDS:")}
2375
+ list, ls List all recipes
2376
+ get <id> Get recipe details
2377
+ run <id> Run a recipe on servers
2378
+
2379
+ ${colors.bold("OPTIONS:")}
2380
+ -f, --format <fmt> Output format: json, human, table
2381
+
2382
+ Run ${colors.cyan("forge-cli recipes <subcommand> --help")} for details.
2383
+ `);
2384
+ }
2385
+ function requireServerAndSiteRaw$1(ctx, usage) {
2386
+ const server = String(ctx.options.server ?? "");
2387
+ const site = String(ctx.options.site ?? "");
2388
+ if (!server) exitWithValidationError("server_id", usage, ctx.formatter);
2389
+ if (!site) exitWithValidationError("site_id", usage, ctx.formatter);
2390
+ return {
2391
+ server,
2392
+ site
2393
+ };
2394
+ }
2395
+ async function redirectRulesList(ctx) {
2396
+ const { server, site } = requireServerAndSiteRaw$1(ctx, "forge-cli redirect-rules list --server <server_id> --site <site_id>");
2397
+ await runCommand(async () => {
2398
+ const token = ctx.getToken();
2399
+ const execCtx = ctx.createExecutorContext(token);
2400
+ const server_id = await resolveServerId(server, execCtx);
2401
+ const result = await listRedirectRules({
2402
+ server_id,
2403
+ site_id: await resolveSiteId(site, server_id, execCtx)
2404
+ }, execCtx);
2405
+ ctx.formatter.outputList(result.data, [
2406
+ "id",
2407
+ "from",
2408
+ "to",
2409
+ "type"
2410
+ ], "No redirect rules found.", (r) => `${String(r.id).padEnd(8)} ${r.from.padEnd(30)} ${r.to.padEnd(30)} ${r.type}`);
2411
+ }, ctx.formatter);
2412
+ }
2413
+ async function redirectRulesGet(args, ctx) {
2414
+ const [id] = args;
2415
+ const usage = "forge-cli redirect-rules get <rule_id> --server <server_id> --site <site_id>";
2416
+ if (!id) exitWithValidationError("rule_id", usage, ctx.formatter);
2417
+ const { server, site } = requireServerAndSiteRaw$1(ctx, usage);
2418
+ await runCommand(async () => {
2419
+ const token = ctx.getToken();
2420
+ const execCtx = ctx.createExecutorContext(token);
2421
+ const server_id = await resolveServerId(server, execCtx);
2422
+ const result = await getRedirectRule({
2423
+ server_id,
2424
+ site_id: await resolveSiteId(site, server_id, execCtx),
2425
+ id
2426
+ }, execCtx);
2427
+ ctx.formatter.outputOne(result.data, [
2428
+ "id",
2429
+ "from",
2430
+ "to",
2431
+ "type",
2432
+ "created_at"
2433
+ ]);
2434
+ }, ctx.formatter);
2435
+ }
2436
+ async function redirectRulesCreate(ctx) {
2437
+ const usage = "forge-cli redirect-rules create --server <server_id> --site <site_id> --from <from> --to <to>";
2438
+ const { server, site } = requireServerAndSiteRaw$1(ctx, usage);
2439
+ const from = String(ctx.options.from ?? "");
2440
+ const to = String(ctx.options.to ?? "");
2441
+ if (!from) exitWithValidationError("from", usage, ctx.formatter);
2442
+ if (!to) exitWithValidationError("to", usage, ctx.formatter);
2443
+ await runCommand(async () => {
2444
+ const token = ctx.getToken();
2445
+ const execCtx = ctx.createExecutorContext(token);
2446
+ const server_id = await resolveServerId(server, execCtx);
2447
+ const result = await createRedirectRule({
2448
+ server_id,
2449
+ site_id: await resolveSiteId(site, server_id, execCtx),
2450
+ from,
2451
+ to
2452
+ }, execCtx);
2453
+ ctx.formatter.outputOne(result.data, [
2454
+ "id",
2455
+ "from",
2456
+ "to",
2457
+ "type",
2458
+ "created_at"
2459
+ ]);
2460
+ }, ctx.formatter);
2461
+ }
2462
+ async function redirectRulesDelete(args, ctx) {
2463
+ const [id] = args;
2464
+ const usage = "forge-cli redirect-rules delete <rule_id> --server <server_id> --site <site_id>";
2465
+ if (!id) exitWithValidationError("rule_id", usage, ctx.formatter);
2466
+ const { server, site } = requireServerAndSiteRaw$1(ctx, usage);
2467
+ await runCommand(async () => {
2468
+ const token = ctx.getToken();
2469
+ const execCtx = ctx.createExecutorContext(token);
2470
+ const server_id = await resolveServerId(server, execCtx);
2471
+ await deleteRedirectRule({
2472
+ server_id,
2473
+ site_id: await resolveSiteId(site, server_id, execCtx),
2474
+ id
2475
+ }, execCtx);
2476
+ ctx.formatter.success(`Redirect rule ${id} deleted.`);
2477
+ }, ctx.formatter);
2478
+ }
2479
+ const handleRedirectRulesCommand = createCommandRouter({
2480
+ resource: "redirect-rules",
2481
+ handlers: {
2482
+ list: redirectRulesList,
2483
+ ls: redirectRulesList,
2484
+ get: [redirectRulesGet, "args"],
2485
+ create: redirectRulesCreate,
2486
+ delete: [redirectRulesDelete, "args"]
2487
+ },
2488
+ writeSubcommands: ["create", "delete"]
2489
+ });
2490
+ function showRedirectRulesHelp(subcommand) {
2491
+ if (subcommand === "list" || subcommand === "ls") console.log(`
2492
+ ${colors.bold("forge-cli redirect-rules list")} - List redirect rules for a site
2493
+
2494
+ ${colors.bold("USAGE:")}
2495
+ forge-cli redirect-rules list --server <server_id> --site <site_id> [options]
2496
+
2497
+ ${colors.bold("OPTIONS:")}
2498
+ --server <id> Server ID (required)
2499
+ --site <id> Site ID (required)
2500
+ -f, --format <fmt> Output format: json, human, table
2501
+ `);
2502
+ else if (subcommand === "get") console.log(`
2503
+ ${colors.bold("forge-cli redirect-rules get")} - Get redirect rule details
2504
+
2505
+ ${colors.bold("USAGE:")}
2506
+ forge-cli redirect-rules get <rule_id> --server <server_id> --site <site_id> [options]
2507
+ `);
2508
+ else if (subcommand === "create") console.log(`
2509
+ ${colors.bold("forge-cli redirect-rules create")} - Create a new redirect rule
2510
+
2511
+ ${colors.bold("USAGE:")}
2512
+ forge-cli redirect-rules create --server <server_id> --site <site_id> --from <from> --to <to> [options]
2513
+
2514
+ ${colors.bold("OPTIONS:")}
2515
+ --server <id> Server ID (required)
2516
+ --site <id> Site ID (required)
2517
+ --from <path> Source path to redirect from (required)
2518
+ --to <path> Destination path to redirect to (required)
2519
+ -f, --format <fmt> Output format: json, human, table
2520
+ `);
2521
+ else if (subcommand === "delete") console.log(`
2522
+ ${colors.bold("forge-cli redirect-rules delete")} - Delete a redirect rule
2523
+
2524
+ ${colors.bold("USAGE:")}
2525
+ forge-cli redirect-rules delete <rule_id> --server <server_id> --site <site_id> [options]
2526
+ `);
2527
+ else console.log(`
2528
+ ${colors.bold("forge-cli redirect-rules")} - Manage site redirect rules
2529
+
2530
+ ${colors.bold("USAGE:")}
2531
+ forge-cli redirect-rules <subcommand> [options]
2532
+
2533
+ ${colors.bold("SUBCOMMANDS:")}
2534
+ list, ls List redirect rules
2535
+ get <id> Get redirect rule details
2536
+ create Create a new redirect rule
2537
+ delete <id> Delete a redirect rule
2538
+
2539
+ ${colors.bold("OPTIONS:")}
2540
+ --server <id> Server ID (required)
2541
+ --site <id> Site ID (required)
2542
+ -f, --format <fmt> Output format: json, human, table
2543
+
2544
+ Run ${colors.cyan("forge-cli redirect-rules <subcommand> --help")} for details.
2545
+ `);
2546
+ }
2547
+ async function scheduledJobsList(ctx) {
2548
+ const server = String(ctx.options.server ?? "");
2549
+ if (!server) exitWithValidationError("server_id", "forge-cli scheduled-jobs list --server <server_id>", ctx.formatter);
2550
+ await runCommand(async () => {
2551
+ const token = ctx.getToken();
2552
+ const execCtx = ctx.createExecutorContext(token);
2553
+ const result = await listScheduledJobs({ server_id: await resolveServerId(server, execCtx) }, execCtx);
2554
+ ctx.formatter.outputList(result.data, [
2555
+ "id",
2556
+ "command",
2557
+ "frequency",
2558
+ "status"
2559
+ ], "No scheduled jobs found.", (j) => `${String(j.id).padEnd(8)} ${j.command.padEnd(50)} ${j.frequency.padEnd(12)} ${j.status}`);
2560
+ }, ctx.formatter);
2561
+ }
2562
+ async function scheduledJobsGet(args, ctx) {
2563
+ const [id] = args;
2564
+ const server = String(ctx.options.server ?? "");
2565
+ if (!id) exitWithValidationError("job_id", "forge-cli scheduled-jobs get <job_id> --server <server_id>", ctx.formatter);
2566
+ if (!server) exitWithValidationError("server_id", "forge-cli scheduled-jobs get <job_id> --server <server_id>", ctx.formatter);
2567
+ await runCommand(async () => {
2568
+ const token = ctx.getToken();
2569
+ const execCtx = ctx.createExecutorContext(token);
2570
+ const result = await getScheduledJob({
2571
+ server_id: await resolveServerId(server, execCtx),
2572
+ id
2573
+ }, execCtx);
2574
+ ctx.formatter.outputOne(result.data, [
2575
+ "id",
2576
+ "command",
2577
+ "user",
2578
+ "frequency",
2579
+ "cron",
2580
+ "status",
2581
+ "created_at"
2582
+ ]);
2583
+ }, ctx.formatter);
2584
+ }
2585
+ async function scheduledJobsCreate(ctx) {
2586
+ const server = String(ctx.options.server ?? "");
2587
+ const command = String(ctx.options.command ?? "");
2588
+ if (!server) exitWithValidationError("server_id", "forge-cli scheduled-jobs create --server <server_id> --command <command>", ctx.formatter);
2589
+ if (!command) exitWithValidationError("command", "forge-cli scheduled-jobs create --server <server_id> --command <command>", ctx.formatter);
2590
+ await runCommand(async () => {
2591
+ const token = ctx.getToken();
2592
+ const execCtx = ctx.createExecutorContext(token);
2593
+ const result = await createScheduledJob({
2594
+ server_id: await resolveServerId(server, execCtx),
2595
+ command
2596
+ }, execCtx);
2597
+ ctx.formatter.outputOne(result.data, [
2598
+ "id",
2599
+ "command",
2600
+ "user",
2601
+ "frequency",
2602
+ "cron",
2603
+ "status",
2604
+ "created_at"
2605
+ ]);
2606
+ }, ctx.formatter);
2607
+ }
2608
+ async function scheduledJobsDelete(args, ctx) {
2609
+ const [id] = args;
2610
+ const server = String(ctx.options.server ?? "");
2611
+ if (!id) exitWithValidationError("job_id", "forge-cli scheduled-jobs delete <job_id> --server <server_id>", ctx.formatter);
2612
+ if (!server) exitWithValidationError("server_id", "forge-cli scheduled-jobs delete <job_id> --server <server_id>", ctx.formatter);
2613
+ await runCommand(async () => {
2614
+ const token = ctx.getToken();
2615
+ const execCtx = ctx.createExecutorContext(token);
2616
+ await deleteScheduledJob({
2617
+ server_id: await resolveServerId(server, execCtx),
2618
+ id
2619
+ }, execCtx);
2620
+ ctx.formatter.success(`Scheduled job ${id} deleted.`);
2621
+ }, ctx.formatter);
2622
+ }
2623
+ const handleScheduledJobsCommand = createCommandRouter({
2624
+ resource: "scheduled-jobs",
2625
+ handlers: {
2626
+ list: scheduledJobsList,
2627
+ ls: scheduledJobsList,
2628
+ get: [scheduledJobsGet, "args"],
2629
+ create: scheduledJobsCreate,
2630
+ delete: [scheduledJobsDelete, "args"]
2631
+ },
2632
+ writeSubcommands: ["create", "delete"]
2633
+ });
2634
+ function showScheduledJobsHelp(subcommand) {
2635
+ if (subcommand === "list" || subcommand === "ls") console.log(`
2636
+ ${colors.bold("forge-cli scheduled-jobs list")} - List scheduled jobs on a server
2637
+
2638
+ ${colors.bold("USAGE:")}
2639
+ forge-cli scheduled-jobs list --server <server_id> [options]
2640
+
2641
+ ${colors.bold("OPTIONS:")}
2642
+ --server <id> Server ID (required)
2643
+ -f, --format <fmt> Output format: json, human, table
2644
+ `);
2645
+ else if (subcommand === "get") console.log(`
2646
+ ${colors.bold("forge-cli scheduled-jobs get")} - Get scheduled job details
2647
+
2648
+ ${colors.bold("USAGE:")}
2649
+ forge-cli scheduled-jobs get <job_id> --server <server_id> [options]
2650
+ `);
2651
+ else if (subcommand === "create") console.log(`
2652
+ ${colors.bold("forge-cli scheduled-jobs create")} - Create a new scheduled job
2653
+
2654
+ ${colors.bold("USAGE:")}
2655
+ forge-cli scheduled-jobs create --server <server_id> --command <command> [options]
2656
+
2657
+ ${colors.bold("OPTIONS:")}
2658
+ --server <id> Server ID (required)
2659
+ --command <cmd> Command to run (required)
2660
+ -f, --format <fmt> Output format: json, human, table
2661
+ `);
2662
+ else if (subcommand === "delete") console.log(`
2663
+ ${colors.bold("forge-cli scheduled-jobs delete")} - Delete a scheduled job
2664
+
2665
+ ${colors.bold("USAGE:")}
2666
+ forge-cli scheduled-jobs delete <job_id> --server <server_id> [options]
2667
+ `);
2668
+ else console.log(`
2669
+ ${colors.bold("forge-cli scheduled-jobs")} - Manage scheduled jobs (cron)
2670
+
2671
+ ${colors.bold("USAGE:")}
2672
+ forge-cli scheduled-jobs <subcommand> [options]
2673
+
2674
+ ${colors.bold("SUBCOMMANDS:")}
2675
+ list, ls List scheduled jobs
2676
+ get <id> Get scheduled job details
2677
+ create Create a new scheduled job
2678
+ delete <id> Delete a scheduled job
2679
+
2680
+ ${colors.bold("OPTIONS:")}
2681
+ --server <id> Server ID (required)
2682
+ -f, --format <fmt> Output format: json, human, table
2683
+
2684
+ Run ${colors.cyan("forge-cli scheduled-jobs <subcommand> --help")} for details.
2685
+ `);
2686
+ }
2687
+ function requireServerAndSiteRaw(ctx, usage) {
2688
+ const server = String(ctx.options.server ?? "");
2689
+ const site = String(ctx.options.site ?? "");
2690
+ if (!server) exitWithValidationError("server_id", usage, ctx.formatter);
2691
+ if (!site) exitWithValidationError("site_id", usage, ctx.formatter);
2692
+ return {
2693
+ server,
2694
+ site
2695
+ };
2696
+ }
2697
+ async function securityRulesList(ctx) {
2698
+ const { server, site } = requireServerAndSiteRaw(ctx, "forge-cli security-rules list --server <server_id> --site <site_id>");
2699
+ await runCommand(async () => {
2700
+ const token = ctx.getToken();
2701
+ const execCtx = ctx.createExecutorContext(token);
2702
+ const server_id = await resolveServerId(server, execCtx);
2703
+ const result = await listSecurityRules({
2704
+ server_id,
2705
+ site_id: await resolveSiteId(site, server_id, execCtx)
2706
+ }, execCtx);
2707
+ ctx.formatter.outputList(result.data, [
2708
+ "id",
2709
+ "name",
2710
+ "path"
2711
+ ], "No security rules found.", (r) => `${String(r.id).padEnd(8)} ${r.name.padEnd(30)} ${r.path ?? "—"}`);
2712
+ }, ctx.formatter);
2713
+ }
2714
+ async function securityRulesGet(args, ctx) {
2715
+ const [id] = args;
2716
+ const usage = "forge-cli security-rules get <rule_id> --server <server_id> --site <site_id>";
2717
+ if (!id) exitWithValidationError("rule_id", usage, ctx.formatter);
2718
+ const { server, site } = requireServerAndSiteRaw(ctx, usage);
2719
+ await runCommand(async () => {
2720
+ const token = ctx.getToken();
2721
+ const execCtx = ctx.createExecutorContext(token);
2722
+ const server_id = await resolveServerId(server, execCtx);
2723
+ const result = await getSecurityRule({
2724
+ server_id,
2725
+ site_id: await resolveSiteId(site, server_id, execCtx),
2726
+ id
2727
+ }, execCtx);
2728
+ ctx.formatter.outputOne(result.data, [
2729
+ "id",
2730
+ "name",
2731
+ "path",
2732
+ "credentials",
2733
+ "created_at"
2734
+ ]);
2735
+ }, ctx.formatter);
2736
+ }
2737
+ async function securityRulesCreate(ctx) {
2738
+ const usage = "forge-cli security-rules create --server <server_id> --site <site_id> --name <name>";
2739
+ const { server, site } = requireServerAndSiteRaw(ctx, usage);
2740
+ const name = String(ctx.options.name ?? "");
2741
+ if (!name) exitWithValidationError("name", usage, ctx.formatter);
2742
+ await runCommand(async () => {
2743
+ const token = ctx.getToken();
2744
+ const execCtx = ctx.createExecutorContext(token);
2745
+ const server_id = await resolveServerId(server, execCtx);
2746
+ const result = await createSecurityRule({
2747
+ server_id,
2748
+ site_id: await resolveSiteId(site, server_id, execCtx),
2749
+ name,
2750
+ credentials: []
2751
+ }, execCtx);
2752
+ ctx.formatter.outputOne(result.data, [
2753
+ "id",
2754
+ "name",
2755
+ "path",
2756
+ "created_at"
2757
+ ]);
2758
+ }, ctx.formatter);
2759
+ }
2760
+ async function securityRulesDelete(args, ctx) {
2761
+ const [id] = args;
2762
+ const usage = "forge-cli security-rules delete <rule_id> --server <server_id> --site <site_id>";
2763
+ if (!id) exitWithValidationError("rule_id", usage, ctx.formatter);
2764
+ const { server, site } = requireServerAndSiteRaw(ctx, usage);
2765
+ await runCommand(async () => {
2766
+ const token = ctx.getToken();
2767
+ const execCtx = ctx.createExecutorContext(token);
2768
+ const server_id = await resolveServerId(server, execCtx);
2769
+ await deleteSecurityRule({
2770
+ server_id,
2771
+ site_id: await resolveSiteId(site, server_id, execCtx),
2772
+ id
2773
+ }, execCtx);
2774
+ ctx.formatter.success(`Security rule ${id} deleted.`);
2775
+ }, ctx.formatter);
2776
+ }
2777
+ const handleSecurityRulesCommand = createCommandRouter({
2778
+ resource: "security-rules",
2779
+ handlers: {
2780
+ list: securityRulesList,
2781
+ ls: securityRulesList,
2782
+ get: [securityRulesGet, "args"],
2783
+ create: securityRulesCreate,
2784
+ delete: [securityRulesDelete, "args"]
2785
+ },
2786
+ writeSubcommands: ["create", "delete"]
2787
+ });
2788
+ function showSecurityRulesHelp(subcommand) {
2789
+ if (subcommand === "list" || subcommand === "ls") console.log(`
2790
+ ${colors.bold("forge-cli security-rules list")} - List security rules for a site
2791
+
2792
+ ${colors.bold("USAGE:")}
2793
+ forge-cli security-rules list --server <server_id> --site <site_id> [options]
2794
+
2795
+ ${colors.bold("OPTIONS:")}
2796
+ --server <id> Server ID (required)
2797
+ --site <id> Site ID (required)
2798
+ -f, --format <fmt> Output format: json, human, table
2799
+ `);
2800
+ else if (subcommand === "get") console.log(`
2801
+ ${colors.bold("forge-cli security-rules get")} - Get security rule details
2802
+
2803
+ ${colors.bold("USAGE:")}
2804
+ forge-cli security-rules get <rule_id> --server <server_id> --site <site_id> [options]
2805
+ `);
2806
+ else if (subcommand === "create") console.log(`
2807
+ ${colors.bold("forge-cli security-rules create")} - Create a new security rule
2808
+
2809
+ ${colors.bold("USAGE:")}
2810
+ forge-cli security-rules create --server <server_id> --site <site_id> --name <name> [options]
2811
+
2812
+ ${colors.bold("OPTIONS:")}
2813
+ --server <id> Server ID (required)
2814
+ --site <id> Site ID (required)
2815
+ --name <name> Security rule name (required)
2816
+ -f, --format <fmt> Output format: json, human, table
2817
+ `);
2818
+ else if (subcommand === "delete") console.log(`
2819
+ ${colors.bold("forge-cli security-rules delete")} - Delete a security rule
2820
+
2821
+ ${colors.bold("USAGE:")}
2822
+ forge-cli security-rules delete <rule_id> --server <server_id> --site <site_id> [options]
2823
+ `);
2824
+ else console.log(`
2825
+ ${colors.bold("forge-cli security-rules")} - Manage site security rules
2826
+
2827
+ ${colors.bold("USAGE:")}
2828
+ forge-cli security-rules <subcommand> [options]
2829
+
2830
+ ${colors.bold("SUBCOMMANDS:")}
2831
+ list, ls List security rules
2832
+ get <id> Get security rule details
2833
+ create Create a new security rule
2834
+ delete <id> Delete a security rule
2835
+
2836
+ ${colors.bold("OPTIONS:")}
2837
+ --server <id> Server ID (required)
2838
+ --site <id> Site ID (required)
2839
+ -f, --format <fmt> Output format: json, human, table
2840
+
2841
+ Run ${colors.cyan("forge-cli security-rules <subcommand> --help")} for details.
2842
+ `);
2843
+ }
2844
+ /**
2845
+ * CLI handlers for servers commands.
2846
+ * Delegates all HTTP logic to forge-core executors.
2847
+ */
2848
+ /**
2849
+ * List all servers.
2850
+ */
2851
+ async function serversList(ctx) {
2852
+ await runCommand(async () => {
2853
+ const token = ctx.getToken();
2854
+ const result = await listServers({}, ctx.createExecutorContext(token));
2855
+ const format = String(ctx.options.format ?? ctx.options.f ?? "human");
2856
+ if (format === "table" || format === "json") ctx.formatter.output(result.data);
2857
+ else {
2858
+ if (result.data.length === 0) {
2859
+ ctx.formatter.info("No servers found.");
2860
+ return;
2861
+ }
2862
+ for (const server of result.data) console.log(`${String(server.id).padEnd(8)} ${server.name.padEnd(30)} ${server.ip_address.padEnd(16)} ${server.is_ready ? "ready" : "provisioning"}`);
2863
+ }
2864
+ }, ctx.formatter);
2865
+ }
2866
+ /**
2867
+ * Get a single server by ID or name.
2868
+ */
2869
+ async function serversGet(args, ctx) {
2870
+ const [server] = args;
2871
+ if (!server) exitWithValidationError("server_id", "forge-cli servers get <server_id>", ctx.formatter);
2872
+ await runCommand(async () => {
2873
+ const token = ctx.getToken();
2874
+ const execCtx = ctx.createExecutorContext(token);
2875
+ const result = await getServer({ server_id: await resolveServerId(server, execCtx) }, execCtx);
2876
+ ctx.formatter.output(result.data);
2877
+ }, ctx.formatter);
2878
+ }
2879
+ /**
2880
+ * Reboot a server by ID or name.
2881
+ */
2882
+ async function serversReboot(args, ctx) {
2883
+ const [server] = args;
2884
+ if (!server) exitWithValidationError("server_id", "forge-cli servers reboot <server_id>", ctx.formatter);
2885
+ await runCommand(async () => {
2886
+ const token = ctx.getToken();
2887
+ const execCtx = ctx.createExecutorContext(token);
2888
+ const server_id = await resolveServerId(server, execCtx);
2889
+ await rebootServer({ server_id }, execCtx);
2890
+ ctx.formatter.success(`Server ${server_id} reboot initiated.`);
2891
+ }, ctx.formatter);
2892
+ }
2893
+ const handleServersCommand = createCommandRouter({
2894
+ resource: "servers",
2895
+ handlers: {
2896
+ list: serversList,
2897
+ ls: serversList,
2898
+ get: [serversGet, "args"],
2899
+ reboot: [serversReboot, "args"]
2900
+ },
2901
+ writeSubcommands: ["reboot"]
2902
+ });
2903
+ function showServersHelp(subcommand) {
2904
+ if (subcommand === "list" || subcommand === "ls") console.log(`
2905
+ ${colors.bold("forge-cli servers list")} - List all servers
2906
+
2907
+ ${colors.bold("USAGE:")}
2908
+ forge-cli servers list [options]
2909
+
2910
+ ${colors.bold("OPTIONS:")}
2911
+ --token <token> Forge API token
2912
+ -f, --format <fmt> Output format: json, human, table (default: human)
2913
+ --no-color Disable colored output
2914
+ -h, --help Show this help
2915
+
2916
+ ${colors.bold("EXAMPLES:")}
2917
+ forge-cli servers list
2918
+ forge-cli servers list --format json
2919
+ `);
2920
+ else if (subcommand === "get") console.log(`
2921
+ ${colors.bold("forge-cli servers get")} - Get server details
2922
+
2923
+ ${colors.bold("USAGE:")}
2924
+ forge-cli servers get <server_id> [options]
2925
+
2926
+ ${colors.bold("ARGUMENTS:")}
2927
+ <server_id> Server ID (required)
2928
+
2929
+ ${colors.bold("OPTIONS:")}
2930
+ -f, --format <fmt> Output format: json, human, table
2931
+
2932
+ ${colors.bold("EXAMPLES:")}
2933
+ forge-cli servers get 123
2934
+ forge-cli servers get 123 --format json
2935
+ `);
2936
+ else if (subcommand === "reboot") console.log(`
2937
+ ${colors.bold("forge-cli servers reboot")} - Reboot a server
2938
+
2939
+ ${colors.bold("USAGE:")}
2940
+ forge-cli servers reboot <server_id> [options]
2941
+
2942
+ ${colors.bold("ARGUMENTS:")}
2943
+ <server_id> Server ID (required)
2944
+
2945
+ ${colors.bold("EXAMPLES:")}
2946
+ forge-cli servers reboot 123
2947
+ `);
2948
+ else console.log(`
2949
+ ${colors.bold("forge-cli servers")} - Manage servers
2950
+
2951
+ ${colors.bold("USAGE:")}
2952
+ forge-cli servers <subcommand> [options]
2953
+
2954
+ ${colors.bold("ALIASES:")}
2955
+ forge-cli s
2956
+
2957
+ ${colors.bold("SUBCOMMANDS:")}
2958
+ list, ls List all servers
2959
+ get <id> Get server details
2960
+ reboot <id> Reboot a server
2961
+
2962
+ ${colors.bold("OPTIONS:")}
2963
+ -f, --format <fmt> Output format: json, human, table
2964
+ -h, --help Show help for a subcommand
2965
+
2966
+ ${colors.bold("EXAMPLES:")}
2967
+ forge-cli servers list
2968
+ forge-cli servers get 123
2969
+
2970
+ Run ${colors.cyan("forge-cli servers <subcommand> --help")} for subcommand details.
2971
+ `);
2972
+ }
2973
+ async function sitesList(ctx) {
2974
+ const server = String(ctx.options.server ?? "");
2975
+ if (!server) exitWithValidationError("server_id", "forge-cli sites list --server <server_id>", ctx.formatter);
2976
+ await runCommand(async () => {
2977
+ const token = ctx.getToken();
2978
+ const execCtx = ctx.createExecutorContext(token);
2979
+ const result = await listSites({ server_id: await resolveServerId(server, execCtx) }, execCtx);
2980
+ ctx.formatter.outputList(result.data, [
2981
+ "id",
2982
+ "name",
2983
+ "status",
2984
+ "php_version"
2985
+ ], "No sites found.", (s) => `${String(s.id).padEnd(8)} ${s.name.padEnd(40)} ${s.status.padEnd(12)} ${s.php_version}`);
2986
+ }, ctx.formatter);
2987
+ }
2988
+ async function sitesGet(args, ctx) {
2989
+ const [site_id] = args;
2990
+ const server = String(ctx.options.server ?? "");
2991
+ if (!site_id) exitWithValidationError("site_id", "forge-cli sites get <site_id> --server <server_id>", ctx.formatter);
2992
+ if (!server) exitWithValidationError("server_id", "forge-cli sites get <site_id> --server <server_id>", ctx.formatter);
2993
+ await runCommand(async () => {
2994
+ const token = ctx.getToken();
2995
+ const execCtx = ctx.createExecutorContext(token);
2996
+ const result = await getSite({
2997
+ server_id: await resolveServerId(server, execCtx),
2998
+ site_id
2999
+ }, execCtx);
3000
+ ctx.formatter.outputOne(result.data, [
3001
+ "id",
3002
+ "name",
3003
+ "status",
3004
+ "php_version",
3005
+ "project_type",
3006
+ "repository",
3007
+ "repository_branch",
3008
+ "quick_deploy",
3009
+ "deployment_status",
3010
+ "is_secured",
3011
+ "created_at"
3012
+ ]);
3013
+ }, ctx.formatter);
3014
+ }
3015
+ const handleSitesCommand = createCommandRouter({
3016
+ resource: "sites",
3017
+ handlers: {
3018
+ list: sitesList,
3019
+ ls: sitesList,
3020
+ get: [sitesGet, "args"]
3021
+ }
3022
+ });
3023
+ function showSitesHelp(subcommand) {
3024
+ if (subcommand === "list" || subcommand === "ls") console.log(`
3025
+ ${colors.bold("forge-cli sites list")} - List sites on a server
3026
+
3027
+ ${colors.bold("USAGE:")}
3028
+ forge-cli sites list --server <server_id> [options]
3029
+
3030
+ ${colors.bold("OPTIONS:")}
3031
+ --server <id> Server ID (required)
3032
+ -f, --format <fmt> Output format: json, human, table
3033
+
3034
+ ${colors.bold("EXAMPLES:")}
3035
+ forge-cli sites list --server 123
3036
+ forge-cli sites list --server 123 --format json
3037
+ `);
3038
+ else if (subcommand === "get") console.log(`
3039
+ ${colors.bold("forge-cli sites get")} - Get site details
3040
+
3041
+ ${colors.bold("USAGE:")}
3042
+ forge-cli sites get <site_id> --server <server_id> [options]
3043
+
3044
+ ${colors.bold("ARGUMENTS:")}
3045
+ <site_id> Site ID (required)
3046
+
3047
+ ${colors.bold("OPTIONS:")}
3048
+ --server <id> Server ID (required)
3049
+ -f, --format <fmt> Output format: json, human, table
3050
+ `);
3051
+ else console.log(`
3052
+ ${colors.bold("forge-cli sites")} - Manage sites
3053
+
3054
+ ${colors.bold("USAGE:")}
3055
+ forge-cli sites <subcommand> [options]
3056
+
3057
+ ${colors.bold("SUBCOMMANDS:")}
3058
+ list, ls List sites on a server
3059
+ get <id> Get site details
3060
+
3061
+ ${colors.bold("OPTIONS:")}
3062
+ --server <id> Server ID (required for most commands)
3063
+ -f, --format <fmt> Output format: json, human, table
3064
+ -h, --help Show help for a subcommand
3065
+
3066
+ ${colors.bold("EXAMPLES:")}
3067
+ forge-cli sites list --server 123
3068
+ forge-cli sites get 456 --server 123
3069
+
3070
+ Run ${colors.cyan("forge-cli sites <subcommand> --help")} for subcommand details.
3071
+ `);
3072
+ }
3073
+ async function sshKeysList(ctx) {
3074
+ const server = String(ctx.options.server ?? "");
3075
+ if (!server) exitWithValidationError("server_id", "forge-cli ssh-keys list --server <server_id>", ctx.formatter);
3076
+ await runCommand(async () => {
3077
+ const token = ctx.getToken();
3078
+ const execCtx = ctx.createExecutorContext(token);
3079
+ const result = await listSshKeys({ server_id: await resolveServerId(server, execCtx) }, execCtx);
3080
+ ctx.formatter.outputList(result.data, [
3081
+ "id",
3082
+ "name",
3083
+ "status"
3084
+ ], "No SSH keys found.", (k) => `${String(k.id).padEnd(8)} ${k.name.padEnd(30)} ${k.status}`);
3085
+ }, ctx.formatter);
3086
+ }
3087
+ async function sshKeysGet(args, ctx) {
3088
+ const [id] = args;
3089
+ const server = String(ctx.options.server ?? "");
3090
+ if (!id) exitWithValidationError("ssh_key_id", "forge-cli ssh-keys get <key_id> --server <server_id>", ctx.formatter);
3091
+ if (!server) exitWithValidationError("server_id", "forge-cli ssh-keys get <key_id> --server <server_id>", ctx.formatter);
3092
+ await runCommand(async () => {
3093
+ const token = ctx.getToken();
3094
+ const execCtx = ctx.createExecutorContext(token);
3095
+ const result = await getSshKey({
3096
+ server_id: await resolveServerId(server, execCtx),
3097
+ id
3098
+ }, execCtx);
3099
+ ctx.formatter.outputOne(result.data, [
3100
+ "id",
3101
+ "name",
3102
+ "status",
3103
+ "created_at"
3104
+ ]);
3105
+ }, ctx.formatter);
3106
+ }
3107
+ const handleSshKeysCommand = createCommandRouter({
3108
+ resource: "ssh-keys",
3109
+ handlers: {
3110
+ list: sshKeysList,
3111
+ ls: sshKeysList,
3112
+ get: [sshKeysGet, "args"]
3113
+ }
3114
+ });
3115
+ function showSshKeysHelp(subcommand) {
3116
+ if (subcommand === "list" || subcommand === "ls") console.log(`
3117
+ ${colors.bold("forge-cli ssh-keys list")} - List SSH keys on a server
3118
+
3119
+ ${colors.bold("USAGE:")}
3120
+ forge-cli ssh-keys list --server <server_id> [options]
3121
+ `);
3122
+ else if (subcommand === "get") console.log(`
3123
+ ${colors.bold("forge-cli ssh-keys get")} - Get SSH key details
3124
+
3125
+ ${colors.bold("USAGE:")}
3126
+ forge-cli ssh-keys get <key_id> --server <server_id>
3127
+ `);
3128
+ else console.log(`
3129
+ ${colors.bold("forge-cli ssh-keys")} - Manage SSH keys
3130
+
3131
+ ${colors.bold("USAGE:")}
3132
+ forge-cli ssh-keys <subcommand> [options]
3133
+
3134
+ ${colors.bold("SUBCOMMANDS:")}
3135
+ list, ls List SSH keys
3136
+ get <id> Get SSH key details
3137
+
3138
+ ${colors.bold("OPTIONS:")}
3139
+ --server <id> Server ID (required)
3140
+ -f, --format <fmt> Output format: json, human, table
3141
+
3142
+ Run ${colors.cyan("forge-cli ssh-keys <subcommand> --help")} for details.
3143
+ `);
3144
+ }
3145
+ async function userGet(ctx) {
3146
+ await runCommand(async () => {
3147
+ const token = ctx.getToken();
3148
+ const result = await getUser({}, ctx.createExecutorContext(token));
3149
+ ctx.formatter.output(result.data);
3150
+ }, ctx.formatter);
3151
+ }
3152
+ const handleUserCommand = createCommandRouter({
3153
+ resource: "user",
3154
+ handlers: { get: userGet }
3155
+ });
3156
+ function showUserHelp(subcommand) {
3157
+ if (subcommand === "get") console.log(`
3158
+ ${colors.bold("forge-cli user get")} - Get the authenticated user profile
3159
+
3160
+ ${colors.bold("USAGE:")}
3161
+ forge-cli user get [options]
3162
+
3163
+ ${colors.bold("OPTIONS:")}
3164
+ -f, --format <fmt> Output format: json, human, table
3165
+ `);
3166
+ else console.log(`
3167
+ ${colors.bold("forge-cli user")} - Display authenticated user profile
3168
+
3169
+ ${colors.bold("USAGE:")}
3170
+ forge-cli user [subcommand] [options]
3171
+
3172
+ ${colors.bold("SUBCOMMANDS:")}
3173
+ get Get the authenticated user profile
3174
+
3175
+ ${colors.bold("OPTIONS:")}
3176
+ -f, --format <fmt> Output format: json, human, table
3177
+
3178
+ Run ${colors.cyan("forge-cli user <subcommand> --help")} for details.
3179
+ `);
3180
+ }
3181
+ function parseArgs(argv = process.argv.slice(2)) {
3182
+ const options = {};
3183
+ const positional = [];
3184
+ const command = [];
3185
+ for (let i = 0; i < argv.length; i++) {
3186
+ const arg = argv[i];
3187
+ if (arg.startsWith("--")) {
3188
+ const equalIndex = arg.indexOf("=");
3189
+ if (equalIndex > -1) {
3190
+ const key = arg.slice(2, equalIndex);
3191
+ options[key] = arg.slice(equalIndex + 1);
3192
+ } else {
3193
+ const key = arg.slice(2);
3194
+ const nextArg = argv[i + 1];
3195
+ if (nextArg !== void 0 && !nextArg.startsWith("-")) {
3196
+ options[key] = nextArg;
3197
+ i++;
3198
+ } else options[key] = true;
3199
+ }
3200
+ } else if (arg.startsWith("-") && arg.length > 1) if (arg.length === 2) {
3201
+ const key = arg[1];
3202
+ const nextArg = argv[i + 1];
3203
+ if (nextArg !== void 0 && !nextArg.startsWith("-")) {
3204
+ options[key] = nextArg;
3205
+ i++;
3206
+ } else options[key] = true;
3207
+ } else for (let j = 1; j < arg.length; j++) options[arg[j]] = true;
3208
+ else if (command.length < 2) command.push(arg);
3209
+ else positional.push(arg);
3210
+ }
3211
+ return {
3212
+ command,
3213
+ options,
3214
+ positional
3215
+ };
3216
+ }
3217
+ var VERSION = "0.2.0";
3218
+ function showHelp() {
3219
+ console.log(`
3220
+ ${colors.bold("forge-cli")} v${VERSION}
3221
+
3222
+ ${colors.bold("USAGE:")}
3223
+ forge-cli <command> [subcommand] [options]
3224
+
3225
+ ${colors.bold("COMMANDS:")}
3226
+ config Manage CLI configuration
3227
+ set <token> Save API token
3228
+ get Show current token (masked)
3229
+ delete Delete stored token
3230
+
3231
+ servers, s Manage servers
3232
+ list, ls List all servers
3233
+ get <id> Get server details
3234
+ reboot <id> Reboot a server
3235
+
3236
+ sites Manage sites
3237
+ list, ls List sites (requires --server)
3238
+ get <id> Get site details (requires --server)
3239
+
3240
+ deployments, d Manage deployments
3241
+ list, ls List deployments (requires --server --site)
3242
+ deploy Trigger a deployment (requires --server --site)
3243
+
3244
+ databases, db Manage databases
3245
+ list, ls List databases (requires --server)
3246
+ get <id> Get database details (requires --server)
3247
+
3248
+ database-users Manage database users
3249
+ list, ls List database users (requires --server)
3250
+ get <id> Get database user details (requires --server)
3251
+ create Create a database user (requires --server --name --password)
3252
+ delete <id> Delete a database user (requires --server)
3253
+
3254
+ daemons Manage daemons
3255
+ list, ls List daemons (requires --server)
3256
+ get <id> Get daemon details (requires --server)
3257
+ restart <id> Restart a daemon (requires --server)
3258
+
3259
+ env Manage environment variables
3260
+ get Get env variables (requires --server --site)
3261
+ update Update env variables (requires --server --site --content)
3262
+
3263
+ nginx Manage nginx configuration
3264
+ get Get nginx config (requires --server --site)
3265
+ update Update nginx config (requires --server --site --content)
3266
+
3267
+ certificates, certs Manage SSL certificates
3268
+ list, ls List certificates (requires --server --site)
3269
+ get <id> Get certificate details (requires --server --site)
3270
+ activate <id> Activate a certificate (requires --server --site)
3271
+
3272
+ firewall-rules, fw Manage firewall rules
3273
+ list, ls List firewall rules (requires --server)
3274
+ get <id> Get firewall rule details (requires --server)
3275
+
3276
+ ssh-keys Manage SSH keys
3277
+ list, ls List SSH keys (requires --server)
3278
+ get <id> Get SSH key details (requires --server)
3279
+
3280
+ backups Manage backup configurations
3281
+ list, ls List backup configurations (requires --server)
3282
+ get <id> Get backup configuration details (requires --server)
3283
+ create Create a backup configuration (requires --server --provider --frequency)
3284
+ delete <id> Delete a backup configuration (requires --server)
3285
+
3286
+ commands Manage site commands
3287
+ list, ls List commands (requires --server --site)
3288
+ get <id> Get command details (requires --server --site)
3289
+ create Execute a command (requires --server --site --command)
3290
+
3291
+ scheduled-jobs Manage scheduled jobs (cron)
3292
+ list, ls List scheduled jobs (requires --server)
3293
+ get <id> Get scheduled job details (requires --server)
3294
+ create Create a scheduled job (requires --server --command)
3295
+ delete <id> Delete a scheduled job (requires --server)
3296
+
3297
+ user Display authenticated user profile
3298
+ get Get the authenticated user profile
3299
+
3300
+ monitors Manage server monitors
3301
+ list, ls List monitors (requires --server)
3302
+ get <id> Get monitor details (requires --server)
3303
+ create Create a monitor (requires --server --type --operator --threshold --minutes)
3304
+ delete <id> Delete a monitor (requires --server)
3305
+
3306
+ nginx-templates Manage Nginx templates
3307
+ list, ls List Nginx templates (requires --server)
3308
+ get <id> Get Nginx template details (requires --server)
3309
+ create Create a Nginx template (requires --server --name --content)
3310
+ update <id> Update a Nginx template (requires --server)
3311
+ delete <id> Delete a Nginx template (requires --server)
3312
+
3313
+ security-rules Manage site security rules
3314
+ list, ls List security rules (requires --server --site)
3315
+ get <id> Get security rule details (requires --server --site)
3316
+ create Create a security rule (requires --server --site --name)
3317
+ delete <id> Delete a security rule (requires --server --site)
3318
+
3319
+ redirect-rules Manage site redirect rules
3320
+ list, ls List redirect rules (requires --server --site)
3321
+ get <id> Get redirect rule details (requires --server --site)
3322
+ create Create a redirect rule (requires --server --site --from --to)
3323
+ delete <id> Delete a redirect rule (requires --server --site)
3324
+
3325
+ recipes Manage recipes
3326
+ list, ls List all recipes
3327
+ get <id> Get recipe details
3328
+ run <id> Run a recipe (requires --servers)
3329
+
3330
+ completion Generate shell completion script
3331
+ bash Install Bash completion
3332
+ zsh Install Zsh completion
3333
+ fish Install Fish completion
3334
+
3335
+ ${colors.bold("OPTIONS:")}
3336
+ --token <token> Forge API token (overrides config and env)
3337
+ --server <id> Server ID (required for server-scoped commands)
3338
+ --site <id> Site ID (required for site-scoped commands)
3339
+ -f, --format <fmt> Output format: json, human, table (default: human)
3340
+ --no-color Disable colored output
3341
+ -h, --help Show help
3342
+ -v, --version Show version
3343
+
3344
+ ${colors.bold("EXAMPLES:")}
3345
+ # Configure API token
3346
+ forge-cli config set YOUR_TOKEN
3347
+
3348
+ # Or pass token directly
3349
+ forge-cli servers list --token YOUR_TOKEN
3350
+
3351
+ # List all servers
3352
+ forge-cli servers list
3353
+
3354
+ # List sites on a server
3355
+ forge-cli sites list --server 123
3356
+
3357
+ # Deploy a site
3358
+ forge-cli deployments deploy --server 123 --site 456
3359
+
3360
+ # Get JSON output (for AI agents)
3361
+ forge-cli servers list --format json
3362
+
3363
+ ${colors.bold("CREDENTIAL PRIORITY:")}
3364
+ 1. CLI argument (--token)
3365
+ 2. Environment variable (FORGE_API_TOKEN)
3366
+ 3. Config file (~/.config/forge-tools/config.json)
3367
+
3368
+ ${colors.bold("ENVIRONMENT VARIABLES:")}
3369
+ FORGE_API_TOKEN API token
3370
+ NO_COLOR Disable colors
3371
+ XDG_CONFIG_HOME Config directory (respects XDG spec)
3372
+ `);
3373
+ }
3374
+ async function main() {
3375
+ const { command, options, positional } = parseArgs();
3376
+ const [mainCommand, subcommand] = command;
3377
+ const wantsHelp = options.help !== void 0 || options.h !== void 0;
3378
+ if (wantsHelp && !mainCommand) {
3379
+ showHelp();
3380
+ process.exit(0);
3381
+ }
3382
+ if (options.version || options.v) {
3383
+ console.log(VERSION);
3384
+ process.exit(0);
3385
+ }
3386
+ if (options["no-color"]) setColorEnabled(false);
3387
+ if (!mainCommand) {
3388
+ showHelp();
3389
+ process.exit(0);
3390
+ }
3391
+ try {
3392
+ switch (mainCommand) {
3393
+ case "config":
3394
+ if (wantsHelp) {
3395
+ showConfigHelp();
3396
+ process.exit(0);
3397
+ }
3398
+ handleConfigCommand(subcommand ?? "get", positional, options);
3399
+ break;
3400
+ case "servers":
3401
+ case "s":
3402
+ if (wantsHelp) {
3403
+ showServersHelp(subcommand);
3404
+ process.exit(0);
3405
+ }
3406
+ await handleServersCommand(subcommand ?? "list", positional, options);
3407
+ break;
3408
+ case "sites":
3409
+ if (wantsHelp) {
3410
+ showSitesHelp(subcommand);
3411
+ process.exit(0);
3412
+ }
3413
+ await handleSitesCommand(subcommand ?? "list", positional, options);
3414
+ break;
3415
+ case "deployments":
3416
+ case "d":
3417
+ if (wantsHelp) {
3418
+ showDeploymentsHelp(subcommand);
3419
+ process.exit(0);
3420
+ }
3421
+ await handleDeploymentsCommand(subcommand ?? "list", positional, options);
3422
+ break;
3423
+ case "databases":
3424
+ case "db":
3425
+ if (wantsHelp) {
3426
+ showDatabasesHelp(subcommand);
3427
+ process.exit(0);
3428
+ }
3429
+ await handleDatabasesCommand(subcommand ?? "list", positional, options);
3430
+ break;
3431
+ case "database-users":
3432
+ if (wantsHelp) {
3433
+ showDatabaseUsersHelp(subcommand);
3434
+ process.exit(0);
3435
+ }
3436
+ await handleDatabaseUsersCommand(subcommand ?? "list", positional, options);
3437
+ break;
3438
+ case "daemons":
3439
+ if (wantsHelp) {
3440
+ showDaemonsHelp(subcommand);
3441
+ process.exit(0);
3442
+ }
3443
+ await handleDaemonsCommand(subcommand ?? "list", positional, options);
3444
+ break;
3445
+ case "env":
3446
+ if (wantsHelp) {
3447
+ showEnvHelp(subcommand);
3448
+ process.exit(0);
3449
+ }
3450
+ await handleEnvCommand(subcommand ?? "get", positional, options);
3451
+ break;
3452
+ case "nginx":
3453
+ if (wantsHelp) {
3454
+ showNginxHelp(subcommand);
3455
+ process.exit(0);
3456
+ }
3457
+ await handleNginxCommand(subcommand ?? "get", positional, options);
3458
+ break;
3459
+ case "certificates":
3460
+ case "certs":
3461
+ if (wantsHelp) {
3462
+ showCertificatesHelp(subcommand);
3463
+ process.exit(0);
3464
+ }
3465
+ await handleCertificatesCommand(subcommand ?? "list", positional, options);
3466
+ break;
3467
+ case "firewall-rules":
3468
+ case "fw":
3469
+ if (wantsHelp) {
3470
+ showFirewallRulesHelp(subcommand);
3471
+ process.exit(0);
3472
+ }
3473
+ await handleFirewallRulesCommand(subcommand ?? "list", positional, options);
3474
+ break;
3475
+ case "ssh-keys":
3476
+ if (wantsHelp) {
3477
+ showSshKeysHelp(subcommand);
3478
+ process.exit(0);
3479
+ }
3480
+ await handleSshKeysCommand(subcommand ?? "list", positional, options);
3481
+ break;
3482
+ case "backups":
3483
+ if (wantsHelp) {
3484
+ showBackupsHelp(subcommand);
3485
+ process.exit(0);
3486
+ }
3487
+ await handleBackupsCommand(subcommand ?? "list", positional, options);
3488
+ break;
3489
+ case "commands":
3490
+ if (wantsHelp) {
3491
+ showCommandsHelp(subcommand);
3492
+ process.exit(0);
3493
+ }
3494
+ await handleCommandsCommand(subcommand ?? "list", positional, options);
3495
+ break;
3496
+ case "scheduled-jobs":
3497
+ if (wantsHelp) {
3498
+ showScheduledJobsHelp(subcommand);
3499
+ process.exit(0);
3500
+ }
3501
+ await handleScheduledJobsCommand(subcommand ?? "list", positional, options);
3502
+ break;
3503
+ case "user":
3504
+ if (wantsHelp) {
3505
+ showUserHelp(subcommand);
3506
+ process.exit(0);
3507
+ }
3508
+ await handleUserCommand(subcommand ?? "get", positional, options);
3509
+ break;
3510
+ case "monitors":
3511
+ if (wantsHelp) {
3512
+ showMonitorsHelp(subcommand);
3513
+ process.exit(0);
3514
+ }
3515
+ await handleMonitorsCommand(subcommand ?? "list", positional, options);
3516
+ break;
3517
+ case "nginx-templates":
3518
+ if (wantsHelp) {
3519
+ showNginxTemplatesHelp(subcommand);
3520
+ process.exit(0);
3521
+ }
3522
+ await handleNginxTemplatesCommand(subcommand ?? "list", positional, options);
3523
+ break;
3524
+ case "security-rules":
3525
+ if (wantsHelp) {
3526
+ showSecurityRulesHelp(subcommand);
3527
+ process.exit(0);
3528
+ }
3529
+ await handleSecurityRulesCommand(subcommand ?? "list", positional, options);
3530
+ break;
3531
+ case "redirect-rules":
3532
+ if (wantsHelp) {
3533
+ showRedirectRulesHelp(subcommand);
3534
+ process.exit(0);
3535
+ }
3536
+ await handleRedirectRulesCommand(subcommand ?? "list", positional, options);
3537
+ break;
3538
+ case "recipes":
3539
+ if (wantsHelp) {
3540
+ showRecipesHelp(subcommand);
3541
+ process.exit(0);
3542
+ }
3543
+ await handleRecipesCommand(subcommand ?? "list", positional, options);
3544
+ break;
3545
+ case "completion":
3546
+ if (wantsHelp || !subcommand) {
3547
+ showCompletionHelp();
3548
+ process.exit(0);
3549
+ }
3550
+ handleCompletionCommand(subcommand, options);
3551
+ break;
3552
+ default:
3553
+ console.error(colors.red(`Unknown command: ${mainCommand}`));
3554
+ console.log(`Run ${colors.cyan("forge-cli --help")} for usage information`);
3555
+ process.exit(1);
3556
+ }
3557
+ } catch (error) {
3558
+ console.error(colors.red("Fatal error:"), error);
3559
+ process.exit(1);
3560
+ }
3561
+ }
3562
+ main().catch((error) => {
3563
+ console.error(colors.red("Unhandled error:"), error);
3564
+ process.exit(1);
3565
+ });
3566
+
3567
+ //# sourceMappingURL=cli.js.map