@studiometa/forge-mcp 0.4.5 → 0.4.7

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.
@@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { HttpClient, isForgeApiError } from "@studiometa/forge-api";
5
- import { RESOURCES, activateCertificate, createAuditLogger, createBackupConfig, createCertificate, createCommand, createDaemon, createDatabase, createDatabaseUser, createFirewallRule, createMonitor, createNginxTemplate, createRecipe, createRedirectRule, createScheduledJob, createSecurityRule, createServer, createSite, createSshKey, deleteBackupConfig, deleteCertificate, deleteDaemon, deleteDatabase, deleteDatabaseUser, deleteFirewallRule, deleteMonitor, deleteNginxTemplate, deleteRecipe, deleteRedirectRule, deleteScheduledJob, deleteSecurityRule, deleteServer, deleteSite, deleteSshKey, deploySiteAndWait, getBackupConfig, getCertificate, getCommand, getDaemon, getDatabase, getDatabaseUser, getDeploymentLog, getDeploymentScript, getEnv, getFirewallRule, getMonitor, getNginxConfig, getNginxTemplate, getRecipe, getRedirectRule, getScheduledJob, getSecurityRule, getServer, getSite, getSshKey, getUser, listBackupConfigs, listCommands, listDaemons, listDatabaseUsers, listDatabases, listDeployments, listFirewallRules, listMonitors, listNginxTemplates, listRecipes, listRedirectRules, listScheduledJobs, listSecurityRules, listServers, listSites, listSshKeys, rebootServer, resolveServers, resolveSites, restartDaemon, runRecipe, updateBackupConfig, updateDaemon, updateDatabaseUser, updateDeploymentScript, updateEnv, updateNginxConfig, updateNginxTemplate, updateRecipe, updateSecurityRule, updateSite } from "@studiometa/forge-core";
5
+ import { PHP_CONFIG_TYPES, RESOURCES, activateCertificate, createAuditLogger, createBackupConfig, createCertificate, createCommand, createDaemon, createDatabase, createDatabaseUser, createFirewallRule, createMonitor, createNginxTemplate, createRecipe, createRedirectRule, createScheduledJob, createSecurityRule, createServer, createSite, createSshKey, deleteBackupConfig, deleteCertificate, deleteDaemon, deleteDatabase, deleteDatabaseUser, deleteFirewallRule, deleteMonitor, deleteNginxTemplate, deleteRecipe, deleteRedirectRule, deleteScheduledJob, deleteSecurityRule, deleteServer, deleteSite, deleteSshKey, deploySiteAndWait, disablePhpOpcache, enablePhpOpcache, getBackupConfig, getCertificate, getCommand, getDaemon, getDaemonLog, getDatabase, getDatabaseUser, getDeploymentLog, getDeploymentScript, getEnv, getFirewallRule, getMonitor, getNginxConfig, getNginxTemplate, getPhpConfig, getPhpMaxExecutionTime, getPhpMaxUploadSize, getPhpOpcache, getPhpVersion, getRecipe, getRedirectRule, getScheduledJob, getSecurityRule, getServer, getSite, getSshKey, getUser, listBackupConfigs, listCommands, listDaemons, listDatabaseUsers, listDatabases, listDeployments, listFirewallRules, listMonitors, listNginxTemplates, listPhpVersions, listRecipes, listRedirectRules, listScheduledJobs, listSecurityRules, listServers, listServices, listSites, listSshKeys, rebootServer, resolveServers, resolveSites, restartDaemon, restartService, runRecipe, updateBackupConfig, updateDaemon, updateDatabaseUser, updateDeploymentScript, updateEnv, updateNginxConfig, updateNginxTemplate, updatePhpConfig, updatePhpMaxExecutionTime, updatePhpMaxUploadSize, updateRecipe, updateSecurityRule, updateSite } from "@studiometa/forge-core";
6
6
  //#region src/instructions.ts
7
7
  /**
8
8
  * MCP Server Instructions
@@ -153,6 +153,54 @@ function _getStandardProps(context) {
153
153
  };
154
154
  }
155
155
  /**
156
+ * Joins multiple `expects` values with the given separator.
157
+ *
158
+ * @param values The `expects` values.
159
+ * @param separator The separator.
160
+ *
161
+ * @returns The joined `expects` property.
162
+ *
163
+ * @internal
164
+ */
165
+ /* @__NO_SIDE_EFFECTS__ */
166
+ function _joinExpects(values$1, separator) {
167
+ const list = [...new Set(values$1)];
168
+ if (list.length > 1) return `(${list.join(` ${separator} `)})`;
169
+ return list[0] ?? "never";
170
+ }
171
+ /* @__NO_SIDE_EFFECTS__ */
172
+ function integer(message$1) {
173
+ return {
174
+ kind: "validation",
175
+ type: "integer",
176
+ reference: integer,
177
+ async: false,
178
+ expects: null,
179
+ requirement: Number.isInteger,
180
+ message: message$1,
181
+ "~run"(dataset, config$1) {
182
+ if (dataset.typed && !this.requirement(dataset.value)) _addIssue(this, "integer", dataset, config$1);
183
+ return dataset;
184
+ }
185
+ };
186
+ }
187
+ /* @__NO_SIDE_EFFECTS__ */
188
+ function minValue(requirement, message$1) {
189
+ return {
190
+ kind: "validation",
191
+ type: "min_value",
192
+ reference: minValue,
193
+ async: false,
194
+ expects: `>=${requirement instanceof Date ? requirement.toJSON() : /* @__PURE__ */ _stringify(requirement)}`,
195
+ requirement,
196
+ message: message$1,
197
+ "~run"(dataset, config$1) {
198
+ if (dataset.typed && !(dataset.value >= this.requirement)) _addIssue(this, "value", dataset, config$1, { received: dataset.value instanceof Date ? dataset.value.toJSON() : /* @__PURE__ */ _stringify(dataset.value) });
199
+ return dataset;
200
+ }
201
+ };
202
+ }
203
+ /**
156
204
  * Returns the fallback value of the schema.
157
205
  *
158
206
  * @param schema The schema to get it from.
@@ -227,6 +275,45 @@ function array(item, message$1) {
227
275
  };
228
276
  }
229
277
  /* @__NO_SIDE_EFFECTS__ */
278
+ function boolean(message$1) {
279
+ return {
280
+ kind: "schema",
281
+ type: "boolean",
282
+ reference: boolean,
283
+ expects: "boolean",
284
+ async: false,
285
+ message: message$1,
286
+ get "~standard"() {
287
+ return /* @__PURE__ */ _getStandardProps(this);
288
+ },
289
+ "~run"(dataset, config$1) {
290
+ if (typeof dataset.value === "boolean") dataset.typed = true;
291
+ else _addIssue(this, "type", dataset, config$1);
292
+ return dataset;
293
+ }
294
+ };
295
+ }
296
+ /* @__NO_SIDE_EFFECTS__ */
297
+ function literal(literal_, message$1) {
298
+ return {
299
+ kind: "schema",
300
+ type: "literal",
301
+ reference: literal,
302
+ expects: /* @__PURE__ */ _stringify(literal_),
303
+ async: false,
304
+ literal: literal_,
305
+ message: message$1,
306
+ get "~standard"() {
307
+ return /* @__PURE__ */ _getStandardProps(this);
308
+ },
309
+ "~run"(dataset, config$1) {
310
+ if (dataset.value === this.literal) dataset.typed = true;
311
+ else _addIssue(this, "type", dataset, config$1);
312
+ return dataset;
313
+ }
314
+ };
315
+ }
316
+ /* @__NO_SIDE_EFFECTS__ */
230
317
  function nullable(wrapped, default_) {
231
318
  return {
232
319
  kind: "schema",
@@ -361,6 +448,26 @@ function optional(wrapped, default_) {
361
448
  };
362
449
  }
363
450
  /* @__NO_SIDE_EFFECTS__ */
451
+ function picklist(options, message$1) {
452
+ return {
453
+ kind: "schema",
454
+ type: "picklist",
455
+ reference: picklist,
456
+ expects: /* @__PURE__ */ _joinExpects(options.map(_stringify), "|"),
457
+ async: false,
458
+ options,
459
+ message: message$1,
460
+ get "~standard"() {
461
+ return /* @__PURE__ */ _getStandardProps(this);
462
+ },
463
+ "~run"(dataset, config$1) {
464
+ if (this.options.includes(dataset.value)) dataset.typed = true;
465
+ else _addIssue(this, "type", dataset, config$1);
466
+ return dataset;
467
+ }
468
+ };
469
+ }
470
+ /* @__NO_SIDE_EFFECTS__ */
364
471
  function string(message$1) {
365
472
  return {
366
473
  kind: "schema",
@@ -401,6 +508,96 @@ function unknown() {
401
508
  }
402
509
  };
403
510
  }
511
+ /* @__NO_SIDE_EFFECTS__ */
512
+ function variant(key, options, message$1) {
513
+ return {
514
+ kind: "schema",
515
+ type: "variant",
516
+ reference: variant,
517
+ expects: "Object",
518
+ async: false,
519
+ key,
520
+ options,
521
+ message: message$1,
522
+ get "~standard"() {
523
+ return /* @__PURE__ */ _getStandardProps(this);
524
+ },
525
+ "~run"(dataset, config$1) {
526
+ const input = dataset.value;
527
+ if (input && typeof input === "object") {
528
+ let outputDataset;
529
+ let maxDiscriminatorPriority = 0;
530
+ let invalidDiscriminatorKey = this.key;
531
+ let expectedDiscriminators = [];
532
+ const parseOptions = (variant$1, allKeys) => {
533
+ for (const schema of variant$1.options) {
534
+ if (schema.type === "variant") parseOptions(schema, new Set(allKeys).add(schema.key));
535
+ else {
536
+ let keysAreValid = true;
537
+ let currentPriority = 0;
538
+ for (const currentKey of allKeys) {
539
+ const discriminatorSchema = schema.entries[currentKey];
540
+ if (currentKey in input ? discriminatorSchema["~run"]({
541
+ typed: false,
542
+ value: input[currentKey]
543
+ }, { abortEarly: true }).issues : discriminatorSchema.type !== "exact_optional" && discriminatorSchema.type !== "optional" && discriminatorSchema.type !== "nullish") {
544
+ keysAreValid = false;
545
+ if (invalidDiscriminatorKey !== currentKey && (maxDiscriminatorPriority < currentPriority || maxDiscriminatorPriority === currentPriority && currentKey in input && !(invalidDiscriminatorKey in input))) {
546
+ maxDiscriminatorPriority = currentPriority;
547
+ invalidDiscriminatorKey = currentKey;
548
+ expectedDiscriminators = [];
549
+ }
550
+ if (invalidDiscriminatorKey === currentKey) expectedDiscriminators.push(schema.entries[currentKey].expects);
551
+ break;
552
+ }
553
+ currentPriority++;
554
+ }
555
+ if (keysAreValid) {
556
+ const optionDataset = schema["~run"]({ value: input }, config$1);
557
+ if (!outputDataset || !outputDataset.typed && optionDataset.typed) outputDataset = optionDataset;
558
+ }
559
+ }
560
+ if (outputDataset && !outputDataset.issues) break;
561
+ }
562
+ };
563
+ parseOptions(this, /* @__PURE__ */ new Set([this.key]));
564
+ if (outputDataset) return outputDataset;
565
+ _addIssue(this, "type", dataset, config$1, {
566
+ input: input[invalidDiscriminatorKey],
567
+ expected: /* @__PURE__ */ _joinExpects(expectedDiscriminators, "|"),
568
+ path: [{
569
+ type: "object",
570
+ origin: "value",
571
+ input,
572
+ key: invalidDiscriminatorKey,
573
+ value: input[invalidDiscriminatorKey]
574
+ }]
575
+ });
576
+ } else _addIssue(this, "type", dataset, config$1);
577
+ return dataset;
578
+ }
579
+ };
580
+ }
581
+ /* @__NO_SIDE_EFFECTS__ */
582
+ function pipe(...pipe$1) {
583
+ return {
584
+ ...pipe$1[0],
585
+ pipe: pipe$1,
586
+ get "~standard"() {
587
+ return /* @__PURE__ */ _getStandardProps(this);
588
+ },
589
+ "~run"(dataset, config$1) {
590
+ for (const item of pipe$1) if (item.kind !== "metadata") {
591
+ if (dataset.issues && (item.kind === "schema" || item.kind === "transformation")) {
592
+ dataset.typed = false;
593
+ break;
594
+ }
595
+ if (!dataset.issues || !config$1.abortEarly && !config$1.abortPipeEarly) dataset = item["~run"](dataset, config$1);
596
+ }
597
+ return dataset;
598
+ }
599
+ };
600
+ }
404
601
  /**
405
602
  * Parses an unknown input based on a schema.
406
603
  *
@@ -564,6 +761,12 @@ function formatDaemon(daemon) {
564
761
  return `Daemon: ${daemon.command} (ID: ${daemon.id})\nUser: ${daemon.user}\nProcesses: ${daemon.processes}\nStatus: ${daemon.status}`;
565
762
  }
566
763
  /**
764
+ * Format a daemon log.
765
+ */
766
+ function formatDaemonLog(daemonId, log) {
767
+ return `Daemon ${daemonId} log:\n${log}`;
768
+ }
769
+ /**
567
770
  * Format a list of firewall rules.
568
771
  */
569
772
  function formatFirewallRuleList(rules) {
@@ -745,6 +948,31 @@ function formatUser(user) {
745
948
  `Created: ${user.created_at}`
746
949
  ].join("\n");
747
950
  }
951
+ /**
952
+ * Format a list of services with their derived availability.
953
+ */
954
+ function formatServiceList(services) {
955
+ const lines = services.map((s) => {
956
+ const status = s.available ? "available" : "unavailable";
957
+ const detail = s.detail ? ` (${s.detail})` : "";
958
+ return `• ${s.service} — ${status}${detail}`;
959
+ });
960
+ return `${services.length} service(s):\n${lines.join("\n")}`;
961
+ }
962
+ /**
963
+ * Format a list of installed PHP versions.
964
+ */
965
+ function formatPhpVersionList(versions) {
966
+ if (versions.length === 0) return "No PHP versions found.";
967
+ const lines = versions.map((v) => `• PHP ${v.version} (ID: ${v.id}) — ${v.status}`);
968
+ return `${versions.length} PHP version(s):\n${lines.join("\n")}`;
969
+ }
970
+ /**
971
+ * Format a single PHP version.
972
+ */
973
+ function formatPhpVersion(version) {
974
+ return `PHP ${version.version} (ID: ${version.id})\nBinary: ${version.binary_name}\nStatus: ${version.status}`;
975
+ }
748
976
  //#endregion
749
977
  //#region src/errors.ts
750
978
  /**
@@ -960,7 +1188,8 @@ var READ_ACTIONS = [
960
1188
  "resolve",
961
1189
  "help",
962
1190
  "schema",
963
- "context"
1191
+ "context",
1192
+ "log"
964
1193
  ];
965
1194
  /**
966
1195
  * Write actions — operations that modify server state.
@@ -1088,6 +1317,22 @@ var TOOLS = [{
1088
1317
  enum: [...READ_ACTIONS],
1089
1318
  description: "Read action to perform. Use \"help\" for resource documentation."
1090
1319
  },
1320
+ setting: {
1321
+ type: "string",
1322
+ description: "PHP setting to read (php get): version, config, max-upload-size, max-execution-time, opcache"
1323
+ },
1324
+ version: {
1325
+ type: "string",
1326
+ description: "PHP version ID or version (e.g. \"8.3\", \"php83\") for php get"
1327
+ },
1328
+ type: {
1329
+ type: "string",
1330
+ description: "PHP configuration file for php get setting=config: cli, fpm, pool"
1331
+ },
1332
+ user: {
1333
+ type: "string",
1334
+ description: "FPM pool user for php get setting=config type=pool (optional)"
1335
+ },
1091
1336
  operations: {
1092
1337
  type: "array",
1093
1338
  description: "Array of operations for batch execution (max 10). Each operation needs resource, action, and any additional params.",
@@ -1153,7 +1398,7 @@ var TOOLS = [{
1153
1398
  },
1154
1399
  type: {
1155
1400
  type: "string",
1156
- description: "Resource type (e.g. app, web, worker for servers; mysql, postgres for databases; disk_usage, used_memory for monitors)"
1401
+ description: "Resource type (e.g. app, web, worker for servers; mysql, postgres for databases; disk_usage, used_memory for monitors; cli, fpm, pool for php configs)"
1157
1402
  },
1158
1403
  domain: {
1159
1404
  type: "string",
@@ -1165,7 +1410,7 @@ var TOOLS = [{
1165
1410
  },
1166
1411
  content: {
1167
1412
  type: "string",
1168
- description: "Content body for env variables, nginx config, or deployment script updates"
1413
+ description: "Content body for env variables, nginx config, deployment script or PHP config updates"
1169
1414
  },
1170
1415
  command: {
1171
1416
  type: "string",
@@ -1173,7 +1418,7 @@ var TOOLS = [{
1173
1418
  },
1174
1419
  user: {
1175
1420
  type: "string",
1176
- description: "Unix user to run as (daemons, scheduled jobs; e.g. forge, root)"
1421
+ description: "Unix user to run as (daemons, scheduled jobs; e.g. forge, root), or the FPM pool user (php config type=pool)"
1177
1422
  },
1178
1423
  port: {
1179
1424
  type: ["string", "number"],
@@ -1224,6 +1469,26 @@ var TOOLS = [{
1224
1469
  type: "array",
1225
1470
  description: "Server IDs to run a recipe on (e.g. [123, 456])",
1226
1471
  items: { type: "number" }
1472
+ },
1473
+ service: {
1474
+ type: "string",
1475
+ description: "Service to restart (services: nginx, php, mysql, postgres, redis, supervisor)"
1476
+ },
1477
+ version: {
1478
+ type: "string",
1479
+ description: "PHP version: required when restarting the php service (e.g. php83); version ID or version (e.g. \"8.3\") for php update setting=config"
1480
+ },
1481
+ setting: {
1482
+ type: "string",
1483
+ description: "PHP setting to write (php update): config, max-upload-size, max-execution-time, opcache"
1484
+ },
1485
+ value: {
1486
+ type: "number",
1487
+ description: "Integer for php update: megabytes for max-upload-size, seconds for max-execution-time"
1488
+ },
1489
+ enabled: {
1490
+ type: "boolean",
1491
+ description: "For php update setting=opcache: true enables OPcache, false disables it"
1227
1492
  }
1228
1493
  },
1229
1494
  required: ["resource", "action"]
@@ -1876,7 +2141,8 @@ var handleDaemons = createResourceHandler({
1876
2141
  "create",
1877
2142
  "update",
1878
2143
  "delete",
1879
- "restart"
2144
+ "restart",
2145
+ "log"
1880
2146
  ],
1881
2147
  inputSchemas: {
1882
2148
  list: /* @__PURE__ */ object({ server_id: /* @__PURE__ */ string() }),
@@ -1884,6 +2150,10 @@ var handleDaemons = createResourceHandler({
1884
2150
  server_id: /* @__PURE__ */ string(),
1885
2151
  id: /* @__PURE__ */ string()
1886
2152
  }),
2153
+ log: /* @__PURE__ */ object({
2154
+ server_id: /* @__PURE__ */ string(),
2155
+ id: /* @__PURE__ */ string()
2156
+ }),
1887
2157
  create: /* @__PURE__ */ object({
1888
2158
  server_id: /* @__PURE__ */ string(),
1889
2159
  command: /* @__PURE__ */ string()
@@ -1909,7 +2179,8 @@ var handleDaemons = createResourceHandler({
1909
2179
  create: createDaemon,
1910
2180
  update: updateDaemon,
1911
2181
  delete: deleteDaemon,
1912
- restart: restartDaemon
2182
+ restart: restartDaemon,
2183
+ log: getDaemonLog
1913
2184
  },
1914
2185
  hints: (_data, id, args) => getDaemonHints(String(args.server_id), id),
1915
2186
  formatResult: (action, data, args) => {
@@ -1920,6 +2191,7 @@ var handleDaemons = createResourceHandler({
1920
2191
  case "update": return formatDaemon(data);
1921
2192
  case "delete": return `Daemon ${args.id} deleted.`;
1922
2193
  case "restart": return `Daemon ${args.id} restarted.`;
2194
+ case "log": return formatDaemonLog(String(args.id), data);
1923
2195
  /* v8 ignore next */
1924
2196
  default: return "Done.";
1925
2197
  }
@@ -2499,7 +2771,8 @@ var RESOURCE_HELP = {
2499
2771
  get: "Get daemon details",
2500
2772
  create: "Create a new daemon",
2501
2773
  delete: "Delete a daemon",
2502
- restart: "Restart a daemon"
2774
+ restart: "Restart a daemon",
2775
+ log: "Get the latest daemon log output"
2503
2776
  },
2504
2777
  fields: {
2505
2778
  command: "Shell command to run",
@@ -2534,6 +2807,138 @@ var RESOURCE_HELP = {
2534
2807
  server_id: "123",
2535
2808
  id: "456"
2536
2809
  }
2810
+ },
2811
+ {
2812
+ description: "Get daemon log output",
2813
+ params: {
2814
+ resource: "daemons",
2815
+ action: "log",
2816
+ server_id: "123",
2817
+ id: "456"
2818
+ }
2819
+ }
2820
+ ]
2821
+ },
2822
+ services: {
2823
+ description: "List and restart server services (nginx, php, mysql, postgres, redis, supervisor)",
2824
+ scope: "server (requires server_id)",
2825
+ actions: {
2826
+ list: "List services with a derived availability flag (heuristic — the API has no services GET endpoint)",
2827
+ restart: "Restart a service (maps to the API action reboot). The php service requires a version."
2828
+ },
2829
+ fields: {
2830
+ service: "One of: nginx, php, mysql, postgres, redis, supervisor",
2831
+ available: "Heuristic derived from the server object attributes",
2832
+ detail: "Extra info (php_version, database_type, redis_status) when relevant",
2833
+ version: "PHP version (e.g. php83) — required when restarting php"
2834
+ },
2835
+ examples: [
2836
+ {
2837
+ description: "List services",
2838
+ params: {
2839
+ resource: "services",
2840
+ action: "list",
2841
+ server_id: "123"
2842
+ }
2843
+ },
2844
+ {
2845
+ description: "Restart nginx",
2846
+ params: {
2847
+ resource: "services",
2848
+ action: "restart",
2849
+ server_id: "123",
2850
+ service: "nginx"
2851
+ }
2852
+ },
2853
+ {
2854
+ description: "Restart php (version required)",
2855
+ params: {
2856
+ resource: "services",
2857
+ action: "restart",
2858
+ server_id: "123",
2859
+ service: "php",
2860
+ version: "php83"
2861
+ }
2862
+ }
2863
+ ]
2864
+ },
2865
+ php: {
2866
+ description: "Manage PHP on a server: installed versions, cli/fpm/pool configuration files, max upload size, max execution time and OPcache",
2867
+ scope: "server (requires server_id)",
2868
+ actions: {
2869
+ list: "List installed PHP versions (with their IDs)",
2870
+ get: "Read one setting: version, config, max-upload-size, max-execution-time or opcache",
2871
+ update: "Write one setting: config (replaces the whole file), max-upload-size, max-execution-time or opcache"
2872
+ },
2873
+ fields: {
2874
+ setting: "What to read or write: version, config, max-upload-size, max-execution-time, opcache",
2875
+ version: "PHP version ID, or a version such as \"8.3\", \"php83\" or \"php8.3\" (for setting=version and setting=config)",
2876
+ type: "Configuration file for setting=config: cli, fpm or pool",
2877
+ user: "Unix user of the FPM pool (optional, type=pool only)",
2878
+ content: "Full configuration file content (update setting=config)",
2879
+ value: "Integer for update: megabytes for max-upload-size, seconds for max-execution-time",
2880
+ enabled: "Boolean for update setting=opcache: true enables, false disables"
2881
+ },
2882
+ examples: [
2883
+ {
2884
+ description: "List installed PHP versions",
2885
+ params: {
2886
+ resource: "php",
2887
+ action: "list",
2888
+ server_id: "123"
2889
+ }
2890
+ },
2891
+ {
2892
+ description: "Read the FPM php.ini of PHP 8.3",
2893
+ params: {
2894
+ resource: "php",
2895
+ action: "get",
2896
+ server_id: "123",
2897
+ setting: "config",
2898
+ version: "8.3",
2899
+ type: "fpm"
2900
+ }
2901
+ },
2902
+ {
2903
+ description: "Replace the CLI php.ini of PHP 8.3",
2904
+ params: {
2905
+ resource: "php",
2906
+ action: "update",
2907
+ server_id: "123",
2908
+ setting: "config",
2909
+ version: "8.3",
2910
+ type: "cli",
2911
+ content: "memory_limit = 512M\n..."
2912
+ }
2913
+ },
2914
+ {
2915
+ description: "Set the max upload size to 128 MB",
2916
+ params: {
2917
+ resource: "php",
2918
+ action: "update",
2919
+ server_id: "123",
2920
+ setting: "max-upload-size",
2921
+ value: 128
2922
+ }
2923
+ },
2924
+ {
2925
+ description: "Read the OPcache status",
2926
+ params: {
2927
+ resource: "php",
2928
+ action: "get",
2929
+ server_id: "123",
2930
+ setting: "opcache"
2931
+ }
2932
+ },
2933
+ {
2934
+ description: "Enable OPcache",
2935
+ params: {
2936
+ resource: "php",
2937
+ action: "update",
2938
+ server_id: "123",
2939
+ setting: "opcache",
2940
+ enabled: true
2941
+ }
2537
2942
  }
2538
2943
  ]
2539
2944
  },
@@ -3069,6 +3474,138 @@ var handleNginxTemplates = createResourceHandler({
3069
3474
  }
3070
3475
  });
3071
3476
  //#endregion
3477
+ //#region src/handlers/php.ts
3478
+ var configFields = {
3479
+ server_id: /* @__PURE__ */ string(),
3480
+ setting: /* @__PURE__ */ literal("config"),
3481
+ version: /* @__PURE__ */ string(),
3482
+ type: /* @__PURE__ */ picklist(PHP_CONFIG_TYPES),
3483
+ user: /* @__PURE__ */ optional(/* @__PURE__ */ string())
3484
+ };
3485
+ /**
3486
+ * Read one PHP setting. Scalar settings are wrapped in an object for JSON output.
3487
+ */
3488
+ async function getPhpSetting(options, ctx) {
3489
+ const { server_id } = options;
3490
+ switch (options.setting) {
3491
+ case "version": return getPhpVersion({
3492
+ server_id,
3493
+ version: options.version
3494
+ }, ctx);
3495
+ case "config": return getPhpConfig({
3496
+ server_id,
3497
+ version: options.version,
3498
+ type: options.type,
3499
+ user: options.user
3500
+ }, ctx);
3501
+ case "max-upload-size": return { data: { max_upload_size: (await getPhpMaxUploadSize({ server_id }, ctx)).data } };
3502
+ case "max-execution-time": return { data: { max_execution_time: (await getPhpMaxExecutionTime({ server_id }, ctx)).data } };
3503
+ default: return { data: { opcache_enabled: (await getPhpOpcache({ server_id }, ctx)).data } };
3504
+ }
3505
+ }
3506
+ /**
3507
+ * Write one PHP setting.
3508
+ */
3509
+ function updatePhpSetting(options, ctx) {
3510
+ const { server_id } = options;
3511
+ switch (options.setting) {
3512
+ case "config": return updatePhpConfig({
3513
+ server_id,
3514
+ version: options.version,
3515
+ type: options.type,
3516
+ content: options.content,
3517
+ user: options.user
3518
+ }, ctx);
3519
+ case "max-upload-size": return updatePhpMaxUploadSize({
3520
+ server_id,
3521
+ size: options.value
3522
+ }, ctx);
3523
+ case "max-execution-time": return updatePhpMaxExecutionTime({
3524
+ server_id,
3525
+ seconds: options.value
3526
+ }, ctx);
3527
+ default: return options.enabled ? enablePhpOpcache({ server_id }, ctx) : disablePhpOpcache({ server_id }, ctx);
3528
+ }
3529
+ }
3530
+ /**
3531
+ * Format the result of a `get` for compact output.
3532
+ */
3533
+ function formatGet(data, args) {
3534
+ switch (args.setting) {
3535
+ case "version": return formatPhpVersion(data);
3536
+ case "config": return `PHP ${String(args.type)} configuration:\n${String(data)}`;
3537
+ case "max-upload-size": return `PHP max upload size: ${data.max_upload_size} MB`;
3538
+ case "max-execution-time": return `PHP max execution time: ${data.max_execution_time} seconds`;
3539
+ default: return `OPcache is ${data.opcache_enabled ? "enabled" : "disabled"}.`;
3540
+ }
3541
+ }
3542
+ /**
3543
+ * Format the confirmation of an `update`.
3544
+ */
3545
+ function formatUpdate(args) {
3546
+ switch (args.setting) {
3547
+ case "config": return `PHP ${String(args.type)} configuration updated.`;
3548
+ case "max-upload-size": return `PHP max upload size set to ${String(args.value)} MB.`;
3549
+ case "max-execution-time": return `PHP max execution time set to ${String(args.value)} seconds.`;
3550
+ default: return `OPcache ${args.enabled ? "enabled" : "disabled"}.`;
3551
+ }
3552
+ }
3553
+ var handlePhp = createResourceHandler({
3554
+ resource: "php",
3555
+ actions: [
3556
+ "list",
3557
+ "get",
3558
+ "update"
3559
+ ],
3560
+ inputSchemas: {
3561
+ list: /* @__PURE__ */ object({ server_id: /* @__PURE__ */ string() }),
3562
+ get: /* @__PURE__ */ variant("setting", [
3563
+ /* @__PURE__ */ object({
3564
+ server_id: /* @__PURE__ */ string(),
3565
+ setting: /* @__PURE__ */ literal("version"),
3566
+ version: /* @__PURE__ */ string()
3567
+ }),
3568
+ /* @__PURE__ */ object(configFields),
3569
+ /* @__PURE__ */ object({
3570
+ server_id: /* @__PURE__ */ string(),
3571
+ setting: /* @__PURE__ */ picklist([
3572
+ "max-upload-size",
3573
+ "max-execution-time",
3574
+ "opcache"
3575
+ ])
3576
+ })
3577
+ ]),
3578
+ update: /* @__PURE__ */ variant("setting", [
3579
+ /* @__PURE__ */ object({
3580
+ ...configFields,
3581
+ content: /* @__PURE__ */ string()
3582
+ }),
3583
+ /* @__PURE__ */ object({
3584
+ server_id: /* @__PURE__ */ string(),
3585
+ setting: /* @__PURE__ */ picklist(["max-upload-size", "max-execution-time"]),
3586
+ value: /* @__PURE__ */ pipe(/* @__PURE__ */ number(), /* @__PURE__ */ integer(), /* @__PURE__ */ minValue(0))
3587
+ }),
3588
+ /* @__PURE__ */ object({
3589
+ server_id: /* @__PURE__ */ string(),
3590
+ setting: /* @__PURE__ */ literal("opcache"),
3591
+ enabled: /* @__PURE__ */ boolean()
3592
+ })
3593
+ ])
3594
+ },
3595
+ executors: {
3596
+ list: listPhpVersions,
3597
+ get: getPhpSetting,
3598
+ update: updatePhpSetting
3599
+ },
3600
+ formatResult: (action, data, args) => {
3601
+ switch (action) {
3602
+ case "list": return formatPhpVersionList(data);
3603
+ case "get": return formatGet(data, args);
3604
+ default: return formatUpdate(args);
3605
+ }
3606
+ }
3607
+ });
3608
+ //#endregion
3072
3609
  //#region src/handlers/recipes.ts
3073
3610
  var handleRecipes = createResourceHandler({
3074
3611
  resource: "recipes",
@@ -3470,7 +4007,8 @@ var RESOURCE_SCHEMAS = {
3470
4007
  "get",
3471
4008
  "create",
3472
4009
  "delete",
3473
- "restart"
4010
+ "restart",
4011
+ "log"
3474
4012
  ],
3475
4013
  scope: "server",
3476
4014
  required: {
@@ -3478,7 +4016,8 @@ var RESOURCE_SCHEMAS = {
3478
4016
  get: ["server_id", "id"],
3479
4017
  create: ["server_id", "command"],
3480
4018
  delete: ["server_id", "id"],
3481
- restart: ["server_id", "id"]
4019
+ restart: ["server_id", "id"],
4020
+ log: ["server_id", "id"]
3482
4021
  },
3483
4022
  create: {
3484
4023
  command: {
@@ -3499,6 +4038,27 @@ var RESOURCE_SCHEMAS = {
3499
4038
  }
3500
4039
  }
3501
4040
  },
4041
+ services: {
4042
+ actions: ["list", "restart"],
4043
+ scope: "server",
4044
+ required: {
4045
+ list: ["server_id"],
4046
+ restart: ["server_id", "service"]
4047
+ }
4048
+ },
4049
+ php: {
4050
+ actions: [
4051
+ "list",
4052
+ "get",
4053
+ "update"
4054
+ ],
4055
+ scope: "server",
4056
+ required: {
4057
+ list: ["server_id"],
4058
+ get: ["server_id", "setting"],
4059
+ update: ["server_id", "setting"]
4060
+ }
4061
+ },
3502
4062
  "firewall-rules": {
3503
4063
  actions: [
3504
4064
  "list",
@@ -4123,6 +4683,32 @@ async function handleServers(action, args, ctx) {
4123
4683
  return _handleServers(action, args, ctx);
4124
4684
  }
4125
4685
  //#endregion
4686
+ //#region src/handlers/services.ts
4687
+ var handleServices = createResourceHandler({
4688
+ resource: "services",
4689
+ actions: ["list", "restart"],
4690
+ inputSchemas: {
4691
+ list: /* @__PURE__ */ object({ server_id: /* @__PURE__ */ string() }),
4692
+ restart: /* @__PURE__ */ object({
4693
+ server_id: /* @__PURE__ */ string(),
4694
+ service: /* @__PURE__ */ string(),
4695
+ version: /* @__PURE__ */ optional(/* @__PURE__ */ string())
4696
+ })
4697
+ },
4698
+ executors: {
4699
+ list: listServices,
4700
+ restart: restartService
4701
+ },
4702
+ formatResult: (action, data, args) => {
4703
+ switch (action) {
4704
+ case "list": return formatServiceList(data);
4705
+ case "restart": return `${String(args.service)} restart initiated on server ${String(args.server_id)}.`;
4706
+ /* v8 ignore next */
4707
+ default: return "Done.";
4708
+ }
4709
+ }
4710
+ });
4711
+ //#endregion
4126
4712
  //#region src/handlers/sites.ts
4127
4713
  var _handleSites = createResourceHandler({
4128
4714
  resource: "sites",
@@ -4378,6 +4964,8 @@ function routeToHandler(resource, action, args, ctx) {
4378
4964
  case "backups": return handleBackups(action, args, ctx);
4379
4965
  case "commands": return handleCommands(action, args, ctx);
4380
4966
  case "scheduled-jobs": return handleScheduledJobs(action, args, ctx);
4967
+ case "services": return handleServices(action, args, ctx);
4968
+ case "php": return handlePhp(action, args, ctx);
4381
4969
  case "user": return handleUser(action, args, ctx);
4382
4970
  case "batch": return handleBatch(action, args, ctx, routeToHandler);
4383
4971
  /* v8 ignore next 6 -- all valid resources are handled above; unreachable in practice */
@@ -4467,8 +5055,8 @@ async function executeToolWithCredentials(name, args, credentials) {
4467
5055
  }
4468
5056
  //#endregion
4469
5057
  //#region src/version.ts
4470
- var VERSION = "0.4.5";
5058
+ var VERSION = "0.4.7";
4471
5059
  //#endregion
4472
5060
  export { INSTRUCTIONS as a, getTools as i, executeToolWithCredentials as n, STDIO_ONLY_TOOLS as r, VERSION as t };
4473
5061
 
4474
- //# sourceMappingURL=version-BdjPN_IX.js.map
5062
+ //# sourceMappingURL=version-DAzDjx0T.js.map