@flui-cloud/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 (108) hide show
  1. package/lib/cli/src/commands/app/list.d.ts +3 -0
  2. package/lib/cli/src/commands/app/list.js +72 -18
  3. package/lib/cli/src/commands/app/status.d.ts +1 -0
  4. package/lib/cli/src/commands/app/status.js +27 -2
  5. package/lib/cli/src/commands/cluster/destroy.d.ts +1 -1
  6. package/lib/cli/src/commands/cluster/destroy.js +2 -2
  7. package/lib/cli/src/commands/deploy.d.ts +3 -0
  8. package/lib/cli/src/commands/deploy.js +19 -0
  9. package/lib/cli/src/commands/dev/creds.d.ts +0 -1
  10. package/lib/cli/src/commands/dev/creds.js +6 -27
  11. package/lib/cli/src/commands/dev/tunnel.js +8 -8
  12. package/lib/cli/src/commands/env/capacity.js +4 -4
  13. package/lib/cli/src/commands/env/create.d.ts +4 -1
  14. package/lib/cli/src/commands/env/create.js +78 -52
  15. package/lib/cli/src/commands/env/credentials.js +12 -12
  16. package/lib/cli/src/commands/env/destroy.d.ts +2 -1
  17. package/lib/cli/src/commands/env/destroy.js +45 -28
  18. package/lib/cli/src/commands/env/diag-ca.js +5 -5
  19. package/lib/cli/src/commands/env/export-config.d.ts +0 -17
  20. package/lib/cli/src/commands/env/export-config.js +50 -47
  21. package/lib/cli/src/commands/env/force-ready.d.ts +1 -1
  22. package/lib/cli/src/commands/env/force-ready.js +8 -8
  23. package/lib/cli/src/commands/env/inspect.js +5 -5
  24. package/lib/cli/src/commands/env/refresh-kubeconfig.js +4 -4
  25. package/lib/cli/src/commands/env/repair-ssh-ca.js +4 -4
  26. package/lib/cli/src/commands/env/repair-storage.d.ts +9 -0
  27. package/lib/cli/src/commands/env/repair-storage.js +82 -0
  28. package/lib/cli/src/commands/env/restart.d.ts +1 -1
  29. package/lib/cli/src/commands/env/restart.js +9 -9
  30. package/lib/cli/src/commands/env/scale-master.js +4 -4
  31. package/lib/cli/src/commands/env/scale-node.js +4 -4
  32. package/lib/cli/src/commands/env/set-master-protection.d.ts +16 -0
  33. package/lib/cli/src/commands/env/set-master-protection.js +120 -0
  34. package/lib/cli/src/commands/env/status.d.ts +1 -1
  35. package/lib/cli/src/commands/env/status.js +10 -10
  36. package/lib/cli/src/commands/env/stop.d.ts +1 -1
  37. package/lib/cli/src/commands/env/stop.js +8 -8
  38. package/lib/cli/src/commands/env/storage-expand.js +4 -4
  39. package/lib/cli/src/commands/env/storage.d.ts +1 -1
  40. package/lib/cli/src/commands/env/storage.js +5 -5
  41. package/lib/cli/src/commands/env/sync.js +5 -5
  42. package/lib/cli/src/commands/env/uncordon.js +4 -4
  43. package/lib/cli/src/commands/env/update-firewall.d.ts +13 -1
  44. package/lib/cli/src/commands/env/update-firewall.js +232 -126
  45. package/lib/cli/src/commands/integration/connect.d.ts +1 -0
  46. package/lib/cli/src/commands/integration/connect.js +19 -1
  47. package/lib/cli/src/commands/integration/reset.d.ts +13 -0
  48. package/lib/cli/src/commands/integration/reset.js +95 -0
  49. package/lib/cli/src/commands/integration/setup.d.ts +18 -0
  50. package/lib/cli/src/commands/integration/setup.js +320 -0
  51. package/lib/cli/src/commands/integration/status.d.ts +9 -0
  52. package/lib/cli/src/commands/integration/status.js +117 -0
  53. package/lib/cli/src/commands/node/list.d.ts +1 -0
  54. package/lib/cli/src/commands/node/list.js +19 -2
  55. package/lib/cli/src/commands/server-types/list.d.ts +3 -0
  56. package/lib/cli/src/commands/server-types/list.js +84 -0
  57. package/lib/cli/src/commands/ssh.js +5 -5
  58. package/lib/cli/src/commands/version.d.ts +18 -0
  59. package/lib/cli/src/commands/version.js +100 -0
  60. package/lib/cli/src/config/bootstrap.config.d.ts +10 -1
  61. package/lib/cli/src/config/bootstrap.config.js +24 -4
  62. package/lib/cli/src/config/preferences-schema.js +5 -5
  63. package/lib/cli/src/config/release-override.d.ts +43 -0
  64. package/lib/cli/src/config/release-override.js +203 -0
  65. package/lib/cli/src/config/release.config.d.ts +31 -0
  66. package/lib/cli/src/config/release.config.js +38 -0
  67. package/lib/cli/src/lib/prompts.d.ts +1 -6
  68. package/lib/cli/src/lib/prompts.js +33 -13
  69. package/lib/cli/src/lib/services/cli-app.service.d.ts +33 -0
  70. package/lib/cli/src/lib/services/cli-app.service.js +9 -0
  71. package/lib/cli/src/lib/services/reconciliation.service.js +1 -1
  72. package/lib/cli/src/lib/templates/firewall-rules.d.ts +2 -2
  73. package/lib/cli/src/lib/templates/firewall-rules.js +3 -3
  74. package/lib/cli/src/modules/cli-infrastructure.module.js +3 -3
  75. package/lib/cli/src/services/cli-cluster-creator.service.js +31 -6
  76. package/lib/cli/src/services/cli-clusters.service.d.ts +3 -3
  77. package/lib/cli/src/services/cli-clusters.service.js +57 -34
  78. package/lib/cli/src/services/cli-control-cluster.service.d.ts +129 -0
  79. package/lib/cli/src/services/cli-control-cluster.service.js +545 -0
  80. package/lib/cli/src/services/cli-endpoint-resolver.service.d.ts +1 -0
  81. package/lib/cli/src/services/cli-endpoint-resolver.service.js +25 -11
  82. package/lib/cli/src/services/cli-k3s-script.service.d.ts +8 -1
  83. package/lib/cli/src/services/cli-k3s-script.service.js +14 -6
  84. package/lib/src/config/release.config.d.ts +28 -0
  85. package/lib/src/config/release.config.js +35 -0
  86. package/lib/src/modules/applications/entities/application.entity.d.ts +13 -20
  87. package/lib/src/modules/applications/entities/application.entity.js +12 -0
  88. package/lib/src/modules/applications/enums/application-exposure.enum.d.ts +2 -1
  89. package/lib/src/modules/applications/enums/application-exposure.enum.js +1 -0
  90. package/lib/src/modules/applications/interfaces/source-config.interface.d.ts +1 -0
  91. package/lib/src/modules/infrastructure/clusters/entities/cluster.entity.d.ts +8 -2
  92. package/lib/src/modules/infrastructure/clusters/entities/cluster.entity.js +16 -1
  93. package/lib/src/modules/infrastructure/clusters/services/cluster-node-scaling.service.js +2 -2
  94. package/lib/src/modules/infrastructure/firewalls/templates/firewall-rules.template.d.ts +3 -2
  95. package/lib/src/modules/infrastructure/firewalls/templates/firewall-rules.template.js +11 -4
  96. package/lib/src/modules/infrastructure/shared/services/kubernetes.service.d.ts +26 -0
  97. package/lib/src/modules/infrastructure/shared/services/kubernetes.service.js +105 -8
  98. package/lib/src/modules/management/entities/provider-capabilities.entity.d.ts +2 -0
  99. package/lib/src/modules/providers/implementations/contabo/contabo-capabilities.service.js +2 -0
  100. package/lib/src/modules/providers/implementations/hetzner/hetzner-capabilities.service.js +3 -6
  101. package/lib/src/modules/providers/implementations/scaleway/scaleway-capabilities.service.js +2 -1
  102. package/lib/src/modules/providers/implementations/scaleway/scaleway-firewall.service.js +3 -1
  103. package/lib/src/modules/providers/implementations/scaleway/scaleway-provider.service.js +3 -1
  104. package/lib/src/modules/providers/interfaces/provider-capabilities.interface.d.ts +0 -2
  105. package/lib/src/modules/providers/services/hetzner-firewall.service.d.ts +1 -1
  106. package/lib/src/modules/providers/services/hetzner-firewall.service.js +2 -1
  107. package/oclif.manifest.json +1201 -854
  108. package/package.json +2 -2
@@ -115,6 +115,39 @@
115
115
  "allowNo": false,
116
116
  "type": "boolean"
117
117
  },
118
+ "cert-challenge": {
119
+ "description": "ACME challenge for the app endpoint (kind:CatalogApp). http-01 works without a DNS zone and forces a per-host cert; dns-01 needs a cluster DNS zone with a wildcard issuer. Default: derived from cluster config.",
120
+ "name": "cert-challenge",
121
+ "hasDynamicHelp": false,
122
+ "multiple": false,
123
+ "options": [
124
+ "http-01",
125
+ "dns-01"
126
+ ],
127
+ "type": "option"
128
+ },
129
+ "cert-provider": {
130
+ "description": "Certificate issuer for the app endpoint (kind:CatalogApp). Default: cluster default.",
131
+ "name": "cert-provider",
132
+ "hasDynamicHelp": false,
133
+ "multiple": false,
134
+ "options": [
135
+ "lets-encrypt",
136
+ "lets-encrypt-staging"
137
+ ],
138
+ "type": "option"
139
+ },
140
+ "hostname": {
141
+ "description": "How the app is exposed (kind:CatalogApp): ip (nip.io) or domain (cluster DNS zone). Default: derived from manifest/cluster.",
142
+ "name": "hostname",
143
+ "hasDynamicHelp": false,
144
+ "multiple": false,
145
+ "options": [
146
+ "ip",
147
+ "domain"
148
+ ],
149
+ "type": "option"
150
+ },
118
151
  "no-wait": {
119
152
  "description": "Alias for --detach (kind:CatalogApp compat)",
120
153
  "name": "no-wait",
@@ -266,6 +299,46 @@
266
299
  "update.js"
267
300
  ]
268
301
  },
302
+ "version": {
303
+ "aliases": [],
304
+ "args": {},
305
+ "description": "Show the CLI version and the platform release it pins (component image tags + bootstrap ref). Useful for debugging an install.",
306
+ "examples": [
307
+ "<%= config.bin %> <%= command.id %>",
308
+ "<%= config.bin %> <%= command.id %> --latest",
309
+ "<%= config.bin %> <%= command.id %> --json"
310
+ ],
311
+ "flags": {
312
+ "latest": {
313
+ "description": "Show what `env create --latest` would resolve to (mobile tags: bootstrap master, :latest images) instead of the pinned release",
314
+ "name": "latest",
315
+ "allowNo": false,
316
+ "type": "boolean"
317
+ },
318
+ "json": {
319
+ "description": "Output as JSON",
320
+ "name": "json",
321
+ "allowNo": false,
322
+ "type": "boolean"
323
+ }
324
+ },
325
+ "hasDynamicHelp": false,
326
+ "hiddenAliases": [],
327
+ "id": "version",
328
+ "pluginAlias": "@flui-cloud/cli",
329
+ "pluginName": "@flui-cloud/cli",
330
+ "pluginType": "core",
331
+ "strict": true,
332
+ "enableJsonFlag": false,
333
+ "isESM": false,
334
+ "relativePath": [
335
+ "lib",
336
+ "cli",
337
+ "src",
338
+ "commands",
339
+ "version.js"
340
+ ]
341
+ },
269
342
  "app:build": {
270
343
  "aliases": [],
271
344
  "args": {
@@ -650,6 +723,7 @@
650
723
  "description": "List all applications in the cluster",
651
724
  "examples": [
652
725
  "<%= config.bin %> <%= command.id %>",
726
+ "<%= config.bin %> <%= command.id %> --expanded",
653
727
  "<%= config.bin %> <%= command.id %> --output json"
654
728
  ],
655
729
  "flags": {
@@ -661,6 +735,13 @@
661
735
  "multiple": false,
662
736
  "type": "option"
663
737
  },
738
+ "expanded": {
739
+ "char": "x",
740
+ "description": "Show the individual components of composed apps",
741
+ "name": "expanded",
742
+ "allowNo": false,
743
+ "type": "boolean"
744
+ },
664
745
  "output": {
665
746
  "char": "o",
666
747
  "description": "Output format",
@@ -1455,7 +1536,7 @@
1455
1536
  "required": true
1456
1537
  }
1457
1538
  },
1458
- "description": "Permanently destroy a workload cluster and all its nodes. For the observability cluster use `flui env destroy`.",
1539
+ "description": "Permanently destroy a workload cluster and all its nodes. For the control cluster use `flui env destroy`.",
1459
1540
  "examples": [
1460
1541
  "<%= config.bin %> <%= command.id %> my-workload-cluster",
1461
1542
  "<%= config.bin %> <%= command.id %> my-workload-cluster --force",
@@ -1849,6 +1930,56 @@
1849
1930
  "use.js"
1850
1931
  ]
1851
1932
  },
1933
+ "dns:cleanup": {
1934
+ "aliases": [],
1935
+ "args": {},
1936
+ "description": "Delete all A records from a Hetzner DNS zone",
1937
+ "examples": [
1938
+ "<%= config.bin %> <%= command.id %> --domain example.com",
1939
+ "<%= config.bin %> <%= command.id %> --domain example.com --dry-run",
1940
+ "<%= config.bin %> <%= command.id %> --domain example.com --force"
1941
+ ],
1942
+ "flags": {
1943
+ "domain": {
1944
+ "description": "Hetzner DNS zone domain name",
1945
+ "name": "domain",
1946
+ "required": true,
1947
+ "hasDynamicHelp": false,
1948
+ "multiple": false,
1949
+ "type": "option"
1950
+ },
1951
+ "force": {
1952
+ "char": "f",
1953
+ "description": "Skip confirmation prompt",
1954
+ "name": "force",
1955
+ "allowNo": false,
1956
+ "type": "boolean"
1957
+ },
1958
+ "dry-run": {
1959
+ "description": "Preview without deleting",
1960
+ "name": "dry-run",
1961
+ "allowNo": false,
1962
+ "type": "boolean"
1963
+ }
1964
+ },
1965
+ "hasDynamicHelp": false,
1966
+ "hiddenAliases": [],
1967
+ "id": "dns:cleanup",
1968
+ "pluginAlias": "@flui-cloud/cli",
1969
+ "pluginName": "@flui-cloud/cli",
1970
+ "pluginType": "core",
1971
+ "strict": true,
1972
+ "enableJsonFlag": false,
1973
+ "isESM": false,
1974
+ "relativePath": [
1975
+ "lib",
1976
+ "cli",
1977
+ "src",
1978
+ "commands",
1979
+ "dns",
1980
+ "cleanup.js"
1981
+ ]
1982
+ },
1852
1983
  "dev:creds": {
1853
1984
  "aliases": [],
1854
1985
  "args": {},
@@ -1856,7 +1987,7 @@
1856
1987
  "examples": [
1857
1988
  "<%= config.bin %> <%= command.id %>",
1858
1989
  "<%= config.bin %> <%= command.id %> --dry-run",
1859
- "<%= config.bin %> <%= command.id %> --api-path ../flui.api"
1990
+ "<%= config.bin %> <%= command.id %> --api-path ../flui-core"
1860
1991
  ],
1861
1992
  "flags": {
1862
1993
  "dry-run": {
@@ -1872,7 +2003,7 @@
1872
2003
  "type": "boolean"
1873
2004
  },
1874
2005
  "api-path": {
1875
- "description": "Override resolved value for the \"apiPath\" preference (Path to the flui.api repo, used to locate the .env file written by env export-config)",
2006
+ "description": "Override resolved value for the \"apiPath\" preference (Path to the flui-core repo, used to locate the .env file written by env export-config)",
1876
2007
  "name": "api-path",
1877
2008
  "hasDynamicHelp": false,
1878
2009
  "multiple": false,
@@ -1906,7 +2037,7 @@
1906
2037
  "dev:tunnel": {
1907
2038
  "aliases": [],
1908
2039
  "args": {},
1909
- "description": "Open SSH tunnels from localhost to the observability cluster services.\nOn the remote side runs kubectl port-forward against the in-cluster Services,\nso no NodePort or kube-API exposure is required. Stay in foreground; CTRL-C to close.",
2040
+ "description": "Open SSH tunnels from localhost to the control cluster services.\nOn the remote side runs kubectl port-forward against the in-cluster Services,\nso no NodePort or kube-API exposure is required. Stay in foreground; CTRL-C to close.",
1910
2041
  "examples": [
1911
2042
  "<%= config.bin %> <%= command.id %>",
1912
2043
  "<%= config.bin %> <%= command.id %> --ports postgres,redis",
@@ -1953,41 +2084,34 @@
1953
2084
  "tunnel.js"
1954
2085
  ]
1955
2086
  },
1956
- "dns:cleanup": {
2087
+ "integration:connect": {
1957
2088
  "aliases": [],
1958
- "args": {},
1959
- "description": "Delete all A records from a Hetzner DNS zone",
2089
+ "args": {
2090
+ "provider": {
2091
+ "description": "Integration provider (currently only `github`)",
2092
+ "name": "provider",
2093
+ "options": [
2094
+ "github"
2095
+ ],
2096
+ "required": true
2097
+ }
2098
+ },
2099
+ "description": "Connect a third-party integration to your Flui account. Currently supports GitHub: opens a browser to install the Flui GitHub App, then waits for the local callback to confirm the connection.",
1960
2100
  "examples": [
1961
- "<%= config.bin %> <%= command.id %> --domain example.com",
1962
- "<%= config.bin %> <%= command.id %> --domain example.com --dry-run",
1963
- "<%= config.bin %> <%= command.id %> --domain example.com --force"
2101
+ "<%= config.bin %> <%= command.id %> github",
2102
+ "<%= config.bin %> <%= command.id %> github --headless"
1964
2103
  ],
1965
2104
  "flags": {
1966
- "domain": {
1967
- "description": "Hetzner DNS zone domain name",
1968
- "name": "domain",
1969
- "required": true,
1970
- "hasDynamicHelp": false,
1971
- "multiple": false,
1972
- "type": "option"
1973
- },
1974
- "force": {
1975
- "char": "f",
1976
- "description": "Skip confirmation prompt",
1977
- "name": "force",
1978
- "allowNo": false,
1979
- "type": "boolean"
1980
- },
1981
- "dry-run": {
1982
- "description": "Preview without deleting",
1983
- "name": "dry-run",
2105
+ "headless": {
2106
+ "description": "Print the install URL instead of opening a browser (useful over SSH)",
2107
+ "name": "headless",
1984
2108
  "allowNo": false,
1985
2109
  "type": "boolean"
1986
2110
  }
1987
2111
  },
1988
2112
  "hasDynamicHelp": false,
1989
2113
  "hiddenAliases": [],
1990
- "id": "dns:cleanup",
2114
+ "id": "integration:connect",
1991
2115
  "pluginAlias": "@flui-cloud/cli",
1992
2116
  "pluginName": "@flui-cloud/cli",
1993
2117
  "pluginType": "core",
@@ -1999,47 +2123,21 @@
1999
2123
  "cli",
2000
2124
  "src",
2001
2125
  "commands",
2002
- "dns",
2003
- "cleanup.js"
2126
+ "integration",
2127
+ "connect.js"
2004
2128
  ]
2005
2129
  },
2006
- "node:add": {
2130
+ "integration:installations": {
2007
2131
  "aliases": [],
2008
2132
  "args": {},
2009
- "description": "Add worker node(s) to the cluster. Provisions new servers and joins them to K3s.",
2133
+ "description": "List all GitHub App installations tracked by Flui. Requires admin privileges. Use the `installationId` shown here with `flui integration remove-installation` to delete a stale or wrong record.",
2010
2134
  "examples": [
2011
- "<%= config.bin %> <%= command.id %>",
2012
- "<%= config.bin %> <%= command.id %> --count 2",
2013
- "<%= config.bin %> <%= command.id %> --count 3 --no-wait"
2135
+ "<%= config.bin %> <%= command.id %>"
2014
2136
  ],
2015
- "flags": {
2016
- "cluster": {
2017
- "char": "c",
2018
- "description": "Cluster name or ID (default: auto-detect when only one cluster exists)",
2019
- "name": "cluster",
2020
- "hasDynamicHelp": false,
2021
- "multiple": false,
2022
- "type": "option"
2023
- },
2024
- "count": {
2025
- "char": "n",
2026
- "description": "Number of workers to add (1-5)",
2027
- "name": "count",
2028
- "default": 1,
2029
- "hasDynamicHelp": false,
2030
- "multiple": false,
2031
- "type": "option"
2032
- },
2033
- "no-wait": {
2034
- "description": "Return immediately after queuing the operation",
2035
- "name": "no-wait",
2036
- "allowNo": false,
2037
- "type": "boolean"
2038
- }
2039
- },
2137
+ "flags": {},
2040
2138
  "hasDynamicHelp": false,
2041
2139
  "hiddenAliases": [],
2042
- "id": "node:add",
2140
+ "id": "integration:installations",
2043
2141
  "pluginAlias": "@flui-cloud/cli",
2044
2142
  "pluginName": "@flui-cloud/cli",
2045
2143
  "pluginType": "core",
@@ -2051,44 +2149,21 @@
2051
2149
  "cli",
2052
2150
  "src",
2053
2151
  "commands",
2054
- "node",
2055
- "add.js"
2152
+ "integration",
2153
+ "installations.js"
2056
2154
  ]
2057
2155
  },
2058
- "node:list": {
2156
+ "integration:list": {
2059
2157
  "aliases": [],
2060
2158
  "args": {},
2061
- "description": "List all nodes in the cluster (master + workers)",
2159
+ "description": "List third-party integrations configured for your account and show whether each is connected.",
2062
2160
  "examples": [
2063
- "<%= config.bin %> <%= command.id %>",
2064
- "<%= config.bin %> <%= command.id %> --output json"
2161
+ "<%= config.bin %> <%= command.id %>"
2065
2162
  ],
2066
- "flags": {
2067
- "cluster": {
2068
- "char": "c",
2069
- "description": "Cluster name or ID (default: auto-detect when only one cluster exists)",
2070
- "name": "cluster",
2071
- "hasDynamicHelp": false,
2072
- "multiple": false,
2073
- "type": "option"
2074
- },
2075
- "output": {
2076
- "char": "o",
2077
- "description": "Output format",
2078
- "name": "output",
2079
- "default": "table",
2080
- "hasDynamicHelp": false,
2081
- "multiple": false,
2082
- "options": [
2083
- "table",
2084
- "json"
2085
- ],
2086
- "type": "option"
2087
- }
2088
- },
2163
+ "flags": {},
2089
2164
  "hasDynamicHelp": false,
2090
2165
  "hiddenAliases": [],
2091
- "id": "node:list",
2166
+ "id": "integration:list",
2092
2167
  "pluginAlias": "@flui-cloud/cli",
2093
2168
  "pluginName": "@flui-cloud/cli",
2094
2169
  "pluginType": "core",
@@ -2100,43 +2175,36 @@
2100
2175
  "cli",
2101
2176
  "src",
2102
2177
  "commands",
2103
- "node",
2178
+ "integration",
2104
2179
  "list.js"
2105
2180
  ]
2106
2181
  },
2107
- "node:remove": {
2182
+ "integration:remove-installation": {
2108
2183
  "aliases": [],
2109
2184
  "args": {
2110
- "nodeId": {
2111
- "description": "Node ID to remove (from `flui node list`)",
2112
- "name": "nodeId",
2185
+ "installationId": {
2186
+ "description": "GitHub installation ID (numeric). Get it with `flui integration installations`.",
2187
+ "name": "installationId",
2113
2188
  "required": true
2114
2189
  }
2115
2190
  },
2116
- "description": "Cordon, drain and remove a worker node from the cluster. Cannot remove the master.",
2191
+ "description": "Remove a GitHub App installation record from the Flui database. Requires admin privileges. Does NOT uninstall the app on GitHub — uninstall it there first, otherwise the next webhook will re-create the record.",
2117
2192
  "examples": [
2118
- "<%= config.bin %> <%= command.id %> <node-id>",
2119
- "<%= config.bin %> <%= command.id %> <node-id> --no-wait"
2193
+ "<%= config.bin %> <%= command.id %> 12345678",
2194
+ "<%= config.bin %> <%= command.id %> 12345678 --yes"
2120
2195
  ],
2121
2196
  "flags": {
2122
- "cluster": {
2123
- "char": "c",
2124
- "description": "Cluster name or ID (default: auto-detect when only one cluster exists)",
2125
- "name": "cluster",
2126
- "hasDynamicHelp": false,
2127
- "multiple": false,
2128
- "type": "option"
2129
- },
2130
- "no-wait": {
2131
- "description": "Return immediately after queuing the operation",
2132
- "name": "no-wait",
2197
+ "yes": {
2198
+ "char": "y",
2199
+ "description": "Skip the confirmation prompt",
2200
+ "name": "yes",
2133
2201
  "allowNo": false,
2134
2202
  "type": "boolean"
2135
2203
  }
2136
2204
  },
2137
2205
  "hasDynamicHelp": false,
2138
2206
  "hiddenAliases": [],
2139
- "id": "node:remove",
2207
+ "id": "integration:remove-installation",
2140
2208
  "pluginAlias": "@flui-cloud/cli",
2141
2209
  "pluginName": "@flui-cloud/cli",
2142
2210
  "pluginType": "core",
@@ -2148,11 +2216,11 @@
2148
2216
  "cli",
2149
2217
  "src",
2150
2218
  "commands",
2151
- "node",
2152
- "remove.js"
2219
+ "integration",
2220
+ "remove-installation.js"
2153
2221
  ]
2154
2222
  },
2155
- "integration:connect": {
2223
+ "integration:reset": {
2156
2224
  "aliases": [],
2157
2225
  "args": {
2158
2226
  "provider": {
@@ -2164,48 +2232,22 @@
2164
2232
  "required": true
2165
2233
  }
2166
2234
  },
2167
- "description": "Connect a third-party integration to your Flui account. Currently supports GitHub: opens a browser to install the Flui GitHub App, then waits for the local callback to confirm the connection.",
2235
+ "description": "Remove the instance-wide GitHub integration (admin). Clears the stored config plus all per-user tokens and App installations. Users will need to reconnect afterwards.",
2168
2236
  "examples": [
2169
2237
  "<%= config.bin %> <%= command.id %> github",
2170
- "<%= config.bin %> <%= command.id %> github --headless"
2238
+ "<%= config.bin %> <%= command.id %> github --yes"
2171
2239
  ],
2172
2240
  "flags": {
2173
- "headless": {
2174
- "description": "Print the install URL instead of opening a browser (useful over SSH)",
2175
- "name": "headless",
2241
+ "yes": {
2242
+ "description": "Skip the typed confirmation (for scripts / CI)",
2243
+ "name": "yes",
2176
2244
  "allowNo": false,
2177
2245
  "type": "boolean"
2178
2246
  }
2179
2247
  },
2180
2248
  "hasDynamicHelp": false,
2181
2249
  "hiddenAliases": [],
2182
- "id": "integration:connect",
2183
- "pluginAlias": "@flui-cloud/cli",
2184
- "pluginName": "@flui-cloud/cli",
2185
- "pluginType": "core",
2186
- "strict": true,
2187
- "enableJsonFlag": false,
2188
- "isESM": false,
2189
- "relativePath": [
2190
- "lib",
2191
- "cli",
2192
- "src",
2193
- "commands",
2194
- "integration",
2195
- "connect.js"
2196
- ]
2197
- },
2198
- "integration:installations": {
2199
- "aliases": [],
2200
- "args": {},
2201
- "description": "List all GitHub App installations tracked by Flui. Requires admin privileges. Use the `installationId` shown here with `flui integration remove-installation` to delete a stale or wrong record.",
2202
- "examples": [
2203
- "<%= config.bin %> <%= command.id %>"
2204
- ],
2205
- "flags": {},
2206
- "hasDynamicHelp": false,
2207
- "hiddenAliases": [],
2208
- "id": "integration:installations",
2250
+ "id": "integration:reset",
2209
2251
  "pluginAlias": "@flui-cloud/cli",
2210
2252
  "pluginName": "@flui-cloud/cli",
2211
2253
  "pluginType": "core",
@@ -2218,20 +2260,36 @@
2218
2260
  "src",
2219
2261
  "commands",
2220
2262
  "integration",
2221
- "installations.js"
2263
+ "reset.js"
2222
2264
  ]
2223
2265
  },
2224
- "integration:list": {
2266
+ "integration:setup-github-app": {
2225
2267
  "aliases": [],
2226
2268
  "args": {},
2227
- "description": "List third-party integrations configured for your account and show whether each is connected.",
2269
+ "description": "Configure the GitHub App credentials in Flui (admin only). Interactively prompts for App ID, slug, client ID/secret, webhook secret and private key path. Secrets are hidden during input and encrypted at rest in the database.",
2228
2270
  "examples": [
2229
- "<%= config.bin %> <%= command.id %>"
2271
+ "<%= config.bin %> <%= command.id %>",
2272
+ "<%= config.bin %> <%= command.id %> --private-key-file ./flui-cloud.pem"
2230
2273
  ],
2231
- "flags": {},
2274
+ "flags": {
2275
+ "private-key-file": {
2276
+ "description": "Path to the GitHub App private key PEM file (skips the path prompt)",
2277
+ "name": "private-key-file",
2278
+ "hasDynamicHelp": false,
2279
+ "multiple": false,
2280
+ "type": "option"
2281
+ },
2282
+ "callback-url": {
2283
+ "description": "OAuth callback URL configured on the GitHub App. Defaults to <api-url>/repositories/github-app/user-callback",
2284
+ "name": "callback-url",
2285
+ "hasDynamicHelp": false,
2286
+ "multiple": false,
2287
+ "type": "option"
2288
+ }
2289
+ },
2232
2290
  "hasDynamicHelp": false,
2233
2291
  "hiddenAliases": [],
2234
- "id": "integration:list",
2292
+ "id": "integration:setup-github-app",
2235
2293
  "pluginAlias": "@flui-cloud/cli",
2236
2294
  "pluginName": "@flui-cloud/cli",
2237
2295
  "pluginType": "core",
@@ -2244,35 +2302,37 @@
2244
2302
  "src",
2245
2303
  "commands",
2246
2304
  "integration",
2247
- "list.js"
2305
+ "setup-github-app.js"
2248
2306
  ]
2249
2307
  },
2250
- "integration:remove-installation": {
2308
+ "integration:setup": {
2251
2309
  "aliases": [],
2252
2310
  "args": {
2253
- "installationId": {
2254
- "description": "GitHub installation ID (numeric). Get it with `flui integration installations`.",
2255
- "name": "installationId",
2311
+ "provider": {
2312
+ "description": "Integration provider (currently only `github`)",
2313
+ "name": "provider",
2314
+ "options": [
2315
+ "github"
2316
+ ],
2256
2317
  "required": true
2257
2318
  }
2258
2319
  },
2259
- "description": "Remove a GitHub App installation record from the Flui database. Requires admin privileges. Does NOT uninstall the app on GitHub uninstall it there first, otherwise the next webhook will re-create the record.",
2320
+ "description": "Guided GitHub integration setup (admin). Pick GitHub App (recommended, creates the App on GitHub via manifest flow) or Personal Access Token (validates and saves a token).",
2260
2321
  "examples": [
2261
- "<%= config.bin %> <%= command.id %> 12345678",
2262
- "<%= config.bin %> <%= command.id %> 12345678 --yes"
2322
+ "<%= config.bin %> <%= command.id %> github",
2323
+ "<%= config.bin %> <%= command.id %> github --headless"
2263
2324
  ],
2264
2325
  "flags": {
2265
- "yes": {
2266
- "char": "y",
2267
- "description": "Skip the confirmation prompt",
2268
- "name": "yes",
2326
+ "headless": {
2327
+ "description": "Print URLs instead of opening a browser",
2328
+ "name": "headless",
2269
2329
  "allowNo": false,
2270
2330
  "type": "boolean"
2271
2331
  }
2272
2332
  },
2273
2333
  "hasDynamicHelp": false,
2274
2334
  "hiddenAliases": [],
2275
- "id": "integration:remove-installation",
2335
+ "id": "integration:setup",
2276
2336
  "pluginAlias": "@flui-cloud/cli",
2277
2337
  "pluginName": "@flui-cloud/cli",
2278
2338
  "pluginType": "core",
@@ -2285,36 +2345,29 @@
2285
2345
  "src",
2286
2346
  "commands",
2287
2347
  "integration",
2288
- "remove-installation.js"
2348
+ "setup.js"
2289
2349
  ]
2290
2350
  },
2291
- "integration:setup-github-app": {
2351
+ "integration:status": {
2292
2352
  "aliases": [],
2293
- "args": {},
2294
- "description": "Configure the GitHub App credentials in Flui (admin only). Interactively prompts for App ID, slug, client ID/secret, webhook secret and private key path. Secrets are hidden during input and encrypted at rest in the database.",
2295
- "examples": [
2296
- "<%= config.bin %> <%= command.id %>",
2297
- "<%= config.bin %> <%= command.id %> --private-key-file ./flui-cloud.pem"
2298
- ],
2299
- "flags": {
2300
- "private-key-file": {
2301
- "description": "Path to the GitHub App private key PEM file (skips the path prompt)",
2302
- "name": "private-key-file",
2303
- "hasDynamicHelp": false,
2304
- "multiple": false,
2305
- "type": "option"
2306
- },
2307
- "callback-url": {
2308
- "description": "OAuth callback URL configured on the GitHub App. Defaults to <api-url>/repositories/github-app/user-callback",
2309
- "name": "callback-url",
2310
- "hasDynamicHelp": false,
2311
- "multiple": false,
2312
- "type": "option"
2353
+ "args": {
2354
+ "provider": {
2355
+ "description": "Integration provider (currently only `github`)",
2356
+ "name": "provider",
2357
+ "options": [
2358
+ "github"
2359
+ ],
2360
+ "required": true
2313
2361
  }
2314
2362
  },
2363
+ "description": "Show the current GitHub integration status: configured mode, live health check, and (in PAT mode) your own connection state.",
2364
+ "examples": [
2365
+ "<%= config.bin %> <%= command.id %> github"
2366
+ ],
2367
+ "flags": {},
2315
2368
  "hasDynamicHelp": false,
2316
2369
  "hiddenAliases": [],
2317
- "id": "integration:setup-github-app",
2370
+ "id": "integration:status",
2318
2371
  "pluginAlias": "@flui-cloud/cli",
2319
2372
  "pluginName": "@flui-cloud/cli",
2320
2373
  "pluginType": "core",
@@ -2327,7 +2380,7 @@
2327
2380
  "src",
2328
2381
  "commands",
2329
2382
  "integration",
2330
- "setup-github-app.js"
2383
+ "status.js"
2331
2384
  ]
2332
2385
  },
2333
2386
  "env:capacity": {
@@ -2383,7 +2436,7 @@
2383
2436
  "env:create": {
2384
2437
  "aliases": [],
2385
2438
  "args": {},
2386
- "description": "Create observability cluster infrastructure on K3s",
2439
+ "description": "Create control cluster infrastructure on K3s",
2387
2440
  "examples": [
2388
2441
  "<%= config.bin %> <%= command.id %>",
2389
2442
  "<%= config.bin %> <%= command.id %> --node-size cx32",
@@ -2394,9 +2447,8 @@
2394
2447
  "flags": {
2395
2448
  "provider": {
2396
2449
  "char": "p",
2397
- "description": "Cloud provider for the observability cluster",
2450
+ "description": "Cloud provider for the control cluster (default: the profile's configured provider)",
2398
2451
  "name": "provider",
2399
- "default": "hetzner",
2400
2452
  "hasDynamicHelp": false,
2401
2453
  "multiple": false,
2402
2454
  "options": [
@@ -2451,7 +2503,7 @@
2451
2503
  "configure-firewall": {
2452
2504
  "description": "Automatically configure firewall after cluster creation",
2453
2505
  "name": "configure-firewall",
2454
- "allowNo": false,
2506
+ "allowNo": true,
2455
2507
  "type": "boolean"
2456
2508
  },
2457
2509
  "firewall-ip": {
@@ -2475,6 +2527,12 @@
2475
2527
  "allowNo": false,
2476
2528
  "type": "boolean"
2477
2529
  },
2530
+ "latest": {
2531
+ "description": "Install mobile dev tags instead of the pinned release: bootstrap scripts from `master` and `:latest` Docker images. Default: every component is pinned to the CLI release version.",
2532
+ "name": "latest",
2533
+ "allowNo": false,
2534
+ "type": "boolean"
2535
+ },
2478
2536
  "no-shared-storage": {
2479
2537
  "description": "Disable Flui shared storage (NFS+fscache). Default: shared storage enabled — master gets a Volume hosting the NFS export, workers mount it. Disable to fall back to local-path on each node bundled disk.",
2480
2538
  "name": "no-shared-storage",
@@ -2511,7 +2569,7 @@
2511
2569
  "env:credentials": {
2512
2570
  "aliases": [],
2513
2571
  "args": {},
2514
- "description": "Display observability cluster connection information.\nSecrets are hidden by default; pass --show-secrets to print them. To populate\na local .env.local for development use `flui dev creds` instead.",
2572
+ "description": "Display control cluster connection information.\nSecrets are hidden by default; pass --show-secrets to print them. To populate\na local .env.local for development use `flui dev creds` instead.",
2515
2573
  "examples": [
2516
2574
  "<%= config.bin %> <%= command.id %>",
2517
2575
  "<%= config.bin %> <%= command.id %> --format json",
@@ -2571,7 +2629,7 @@
2571
2629
  "env:destroy": {
2572
2630
  "aliases": [],
2573
2631
  "args": {},
2574
- "description": "Permanently delete observability cluster (WARNING: All data will be lost!)",
2632
+ "description": "Permanently delete control cluster (WARNING: All data will be lost!)",
2575
2633
  "examples": [
2576
2634
  "<%= config.bin %> <%= command.id %>",
2577
2635
  "<%= config.bin %> <%= command.id %> --force"
@@ -2664,14 +2722,14 @@
2664
2722
  "type": "boolean"
2665
2723
  },
2666
2724
  "api-path": {
2667
- "description": "Override resolved value for the \"apiPath\" preference (Path to the flui.api repo, used to locate the .env file written by env export-config)",
2725
+ "description": "Override resolved value for the \"apiPath\" preference (Path to the flui-core repo, used to locate the .env file written by env export-config)",
2668
2726
  "name": "api-path",
2669
2727
  "hasDynamicHelp": false,
2670
2728
  "multiple": false,
2671
2729
  "type": "option"
2672
2730
  },
2673
2731
  "dashboard-path": {
2674
- "description": "Override resolved value for the \"dashboardPath\" preference (Path to the flui.dashboard repo, used when syncing its config.json)",
2732
+ "description": "Override resolved value for the \"dashboardPath\" preference (Path to the flui-dashboard repo, used when syncing its config.json)",
2675
2733
  "name": "dashboard-path",
2676
2734
  "hasDynamicHelp": false,
2677
2735
  "multiple": false,
@@ -2724,7 +2782,7 @@
2724
2782
  "env:force-ready": {
2725
2783
  "aliases": [],
2726
2784
  "args": {},
2727
- "description": "Force observability cluster status to READY (use when cluster is working but stuck in ERROR or CREATING state)",
2785
+ "description": "Force control cluster status to READY (use when cluster is working but stuck in ERROR or CREATING state)",
2728
2786
  "examples": [
2729
2787
  "<%= config.bin %> <%= command.id %>",
2730
2788
  "<%= config.bin %> <%= command.id %> --force",
@@ -3036,10 +3094,44 @@
3036
3094
  "repair-ssh-ca.js"
3037
3095
  ]
3038
3096
  },
3097
+ "env:repair-storage": {
3098
+ "aliases": [],
3099
+ "args": {},
3100
+ "description": "Backfill the shared-storage volume id into the cluster DB. Repairs clusters whose flui-secrets/DB never received FLUI_SHARED_STORAGE_VOLUME_ID at create — symptom is sharedStorageVolumeId NULL in the DB and \"no Flui-managed shared storage volume\" on storage expand. Reads the volume id from the active profile, patches flui-secrets over SSH, then restarts flui-api so the bootstrap seeder backfills the DB.",
3101
+ "examples": [
3102
+ "<%= config.bin %> <%= command.id %>",
3103
+ "<%= config.bin %> <%= command.id %> --no-restart"
3104
+ ],
3105
+ "flags": {
3106
+ "no-restart": {
3107
+ "description": "Skip the flui-api rolling restart after patching the Secret",
3108
+ "name": "no-restart",
3109
+ "allowNo": false,
3110
+ "type": "boolean"
3111
+ }
3112
+ },
3113
+ "hasDynamicHelp": false,
3114
+ "hiddenAliases": [],
3115
+ "id": "env:repair-storage",
3116
+ "pluginAlias": "@flui-cloud/cli",
3117
+ "pluginName": "@flui-cloud/cli",
3118
+ "pluginType": "core",
3119
+ "strict": true,
3120
+ "enableJsonFlag": false,
3121
+ "isESM": false,
3122
+ "relativePath": [
3123
+ "lib",
3124
+ "cli",
3125
+ "src",
3126
+ "commands",
3127
+ "env",
3128
+ "repair-storage.js"
3129
+ ]
3130
+ },
3039
3131
  "env:restart": {
3040
3132
  "aliases": [],
3041
3133
  "args": {},
3042
- "description": "Restart stopped observability cluster servers",
3134
+ "description": "Restart stopped control cluster servers",
3043
3135
  "examples": [
3044
3136
  "<%= config.bin %> <%= command.id %>"
3045
3137
  ],
@@ -3164,10 +3256,49 @@
3164
3256
  "scale-node.js"
3165
3257
  ]
3166
3258
  },
3259
+ "env:set-master-protection": {
3260
+ "aliases": [],
3261
+ "args": {
3262
+ "action": {
3263
+ "description": "on | off | show",
3264
+ "name": "action",
3265
+ "options": [
3266
+ "on",
3267
+ "off",
3268
+ "show"
3269
+ ],
3270
+ "required": true
3271
+ }
3272
+ },
3273
+ "description": "Taint the control-cluster master so new pods schedule on workers (on), remove it (off), or report current state (show).",
3274
+ "examples": [
3275
+ "<%= config.bin %> <%= command.id %> on",
3276
+ "<%= config.bin %> <%= command.id %> off",
3277
+ "<%= config.bin %> <%= command.id %> show"
3278
+ ],
3279
+ "flags": {},
3280
+ "hasDynamicHelp": false,
3281
+ "hiddenAliases": [],
3282
+ "id": "env:set-master-protection",
3283
+ "pluginAlias": "@flui-cloud/cli",
3284
+ "pluginName": "@flui-cloud/cli",
3285
+ "pluginType": "core",
3286
+ "strict": true,
3287
+ "enableJsonFlag": false,
3288
+ "isESM": false,
3289
+ "relativePath": [
3290
+ "lib",
3291
+ "cli",
3292
+ "src",
3293
+ "commands",
3294
+ "env",
3295
+ "set-master-protection.js"
3296
+ ]
3297
+ },
3167
3298
  "env:status": {
3168
3299
  "aliases": [],
3169
3300
  "args": {},
3170
- "description": "Check observability cluster status",
3301
+ "description": "Check control cluster status",
3171
3302
  "examples": [
3172
3303
  "<%= config.bin %> <%= command.id %>"
3173
3304
  ],
@@ -3193,7 +3324,7 @@
3193
3324
  "env:stop": {
3194
3325
  "aliases": [],
3195
3326
  "args": {},
3196
- "description": "Shutdown observability cluster servers (saves costs while preserving data)",
3327
+ "description": "Shutdown control cluster servers (saves costs while preserving data)",
3197
3328
  "examples": [
3198
3329
  "<%= config.bin %> <%= command.id %>"
3199
3330
  ],
@@ -3261,7 +3392,7 @@
3261
3392
  "env:storage": {
3262
3393
  "aliases": [],
3263
3394
  "args": {},
3264
- "description": "Show shared storage status (Volume + NFS export + PVC summary) for the current observability cluster",
3395
+ "description": "Show shared storage status (Volume + NFS export + PVC summary) for the current control cluster",
3265
3396
  "examples": [
3266
3397
  "<%= config.bin %> <%= command.id %>"
3267
3398
  ],
@@ -3360,11 +3491,13 @@
3360
3491
  "env:update-firewall": {
3361
3492
  "aliases": [],
3362
3493
  "args": {},
3363
- "description": "Create or update firewall IP ranges for observability cluster",
3494
+ "description": "Manage SSH access (port 22) on the control cluster firewall. Updates only the SSH source IPs — every other rule is left untouched. Runs directly against the cloud provider, so it works even when your current IP is locked out.",
3364
3495
  "examples": [
3365
3496
  "<%= config.bin %> <%= command.id %>",
3366
3497
  "<%= config.bin %> <%= command.id %> --ip 203.0.113.42",
3367
- "<%= config.bin %> <%= command.id %> --ip \"203.0.113.0/24,198.51.100.5/32\""
3498
+ "<%= config.bin %> <%= command.id %> --add --ip 203.0.113.42",
3499
+ "<%= config.bin %> <%= command.id %> --remove --ip 198.51.100.5/32",
3500
+ "<%= config.bin %> <%= command.id %> --list"
3368
3501
  ],
3369
3502
  "flags": {
3370
3503
  "ip": {
@@ -3374,6 +3507,36 @@
3374
3507
  "hasDynamicHelp": false,
3375
3508
  "multiple": false,
3376
3509
  "type": "option"
3510
+ },
3511
+ "add": {
3512
+ "description": "Add the IP(s) to the existing SSH allowlist (keeps current entries)",
3513
+ "exclusive": [
3514
+ "remove",
3515
+ "list"
3516
+ ],
3517
+ "name": "add",
3518
+ "allowNo": false,
3519
+ "type": "boolean"
3520
+ },
3521
+ "remove": {
3522
+ "description": "Remove the IP(s) from the SSH allowlist",
3523
+ "exclusive": [
3524
+ "add",
3525
+ "list"
3526
+ ],
3527
+ "name": "remove",
3528
+ "allowNo": false,
3529
+ "type": "boolean"
3530
+ },
3531
+ "list": {
3532
+ "description": "Show the current SSH allowlist and exit (no changes)",
3533
+ "exclusive": [
3534
+ "add",
3535
+ "remove"
3536
+ ],
3537
+ "name": "list",
3538
+ "allowNo": false,
3539
+ "type": "boolean"
3377
3540
  }
3378
3541
  },
3379
3542
  "hasDynamicHelp": false,
@@ -3394,54 +3557,353 @@
3394
3557
  "update-firewall.js"
3395
3558
  ]
3396
3559
  },
3397
- "server-types:list": {
3560
+ "repo:connect": {
3398
3561
  "aliases": [],
3399
- "args": {},
3400
- "description": "List available server types for a provider",
3401
- "examples": [
3402
- "<%= config.bin %> <%= command.id %> --provider hetzner",
3403
- "<%= config.bin %> <%= command.id %> --provider hetzner --region fsn1",
3404
- "<%= config.bin %> <%= command.id %> --provider hetzner --json",
3405
- "<%= config.bin %> <%= command.id %> --provider hetzner --force-refresh"
3406
- ],
3407
- "flags": {
3408
- "provider": {
3409
- "char": "p",
3410
- "description": "Cloud provider",
3411
- "name": "provider",
3412
- "required": true,
3413
- "hasDynamicHelp": false,
3414
- "multiple": false,
3415
- "options": [
3416
- "hetzner",
3417
- "scaleway"
3418
- ],
3419
- "type": "option"
3420
- },
3421
- "region": {
3422
- "char": "r",
3423
- "description": "Filter by region/location",
3424
- "name": "region",
3425
- "hasDynamicHelp": false,
3426
- "multiple": false,
3427
- "type": "option"
3428
- },
3429
- "json": {
3430
- "description": "Output as JSON",
3431
- "name": "json",
3432
- "allowNo": false,
3433
- "type": "boolean"
3434
- },
3435
- "force-refresh": {
3436
- "description": "Force refresh cache from API",
3437
- "name": "force-refresh",
3438
- "allowNo": false,
3439
- "type": "boolean"
3562
+ "args": {
3563
+ "repo": {
3564
+ "description": "Full repository name `owner/repo`. Omit to pick interactively.",
3565
+ "name": "repo",
3566
+ "required": false
3440
3567
  }
3441
3568
  },
3569
+ "description": "Connect (import) a GitHub repository into your Flui account so it can be deployed with `flui deploy`. Pass the full name `owner/repo`, or omit it for an interactive picker over the repositories accessible via your GitHub integration.",
3570
+ "examples": [
3571
+ "<%= config.bin %> <%= command.id %> acme/my-app",
3572
+ "<%= config.bin %> <%= command.id %>"
3573
+ ],
3574
+ "flags": {},
3442
3575
  "hasDynamicHelp": false,
3443
3576
  "hiddenAliases": [],
3444
- "id": "server-types:list",
3577
+ "id": "repo:connect",
3578
+ "pluginAlias": "@flui-cloud/cli",
3579
+ "pluginName": "@flui-cloud/cli",
3580
+ "pluginType": "core",
3581
+ "strict": true,
3582
+ "enableJsonFlag": false,
3583
+ "isESM": false,
3584
+ "relativePath": [
3585
+ "lib",
3586
+ "cli",
3587
+ "src",
3588
+ "commands",
3589
+ "repo",
3590
+ "connect.js"
3591
+ ]
3592
+ },
3593
+ "repo:disconnect": {
3594
+ "aliases": [],
3595
+ "args": {
3596
+ "repo": {
3597
+ "description": "Full repository name `owner/repo`",
3598
+ "name": "repo",
3599
+ "required": true
3600
+ }
3601
+ },
3602
+ "description": "Disconnect a repository from your Flui account. Requires admin privileges. Does not delete the repository on GitHub.",
3603
+ "examples": [
3604
+ "<%= config.bin %> <%= command.id %> acme/my-app",
3605
+ "<%= config.bin %> <%= command.id %> acme/my-app --yes"
3606
+ ],
3607
+ "flags": {
3608
+ "yes": {
3609
+ "char": "y",
3610
+ "description": "Skip the confirmation prompt",
3611
+ "name": "yes",
3612
+ "allowNo": false,
3613
+ "type": "boolean"
3614
+ }
3615
+ },
3616
+ "hasDynamicHelp": false,
3617
+ "hiddenAliases": [],
3618
+ "id": "repo:disconnect",
3619
+ "pluginAlias": "@flui-cloud/cli",
3620
+ "pluginName": "@flui-cloud/cli",
3621
+ "pluginType": "core",
3622
+ "strict": true,
3623
+ "enableJsonFlag": false,
3624
+ "isESM": false,
3625
+ "relativePath": [
3626
+ "lib",
3627
+ "cli",
3628
+ "src",
3629
+ "commands",
3630
+ "repo",
3631
+ "disconnect.js"
3632
+ ]
3633
+ },
3634
+ "repo:list": {
3635
+ "aliases": [],
3636
+ "args": {},
3637
+ "description": "List repositories connected to your Flui account.",
3638
+ "examples": [
3639
+ "<%= config.bin %> <%= command.id %>",
3640
+ "<%= config.bin %> <%= command.id %> --output json"
3641
+ ],
3642
+ "flags": {
3643
+ "output": {
3644
+ "char": "o",
3645
+ "description": "Output format",
3646
+ "name": "output",
3647
+ "default": "text",
3648
+ "hasDynamicHelp": false,
3649
+ "multiple": false,
3650
+ "options": [
3651
+ "text",
3652
+ "json"
3653
+ ],
3654
+ "type": "option"
3655
+ }
3656
+ },
3657
+ "hasDynamicHelp": false,
3658
+ "hiddenAliases": [],
3659
+ "id": "repo:list",
3660
+ "pluginAlias": "@flui-cloud/cli",
3661
+ "pluginName": "@flui-cloud/cli",
3662
+ "pluginType": "core",
3663
+ "strict": true,
3664
+ "enableJsonFlag": false,
3665
+ "isESM": false,
3666
+ "relativePath": [
3667
+ "lib",
3668
+ "cli",
3669
+ "src",
3670
+ "commands",
3671
+ "repo",
3672
+ "list.js"
3673
+ ]
3674
+ },
3675
+ "node:add": {
3676
+ "aliases": [],
3677
+ "args": {},
3678
+ "description": "Add worker node(s) to the cluster. Provisions new servers and joins them to K3s.",
3679
+ "examples": [
3680
+ "<%= config.bin %> <%= command.id %>",
3681
+ "<%= config.bin %> <%= command.id %> --count 2",
3682
+ "<%= config.bin %> <%= command.id %> --count 3 --no-wait"
3683
+ ],
3684
+ "flags": {
3685
+ "cluster": {
3686
+ "char": "c",
3687
+ "description": "Cluster name or ID (default: auto-detect when only one cluster exists)",
3688
+ "name": "cluster",
3689
+ "hasDynamicHelp": false,
3690
+ "multiple": false,
3691
+ "type": "option"
3692
+ },
3693
+ "count": {
3694
+ "char": "n",
3695
+ "description": "Number of workers to add (1-5)",
3696
+ "name": "count",
3697
+ "default": 1,
3698
+ "hasDynamicHelp": false,
3699
+ "multiple": false,
3700
+ "type": "option"
3701
+ },
3702
+ "no-wait": {
3703
+ "description": "Return immediately after queuing the operation",
3704
+ "name": "no-wait",
3705
+ "allowNo": false,
3706
+ "type": "boolean"
3707
+ }
3708
+ },
3709
+ "hasDynamicHelp": false,
3710
+ "hiddenAliases": [],
3711
+ "id": "node:add",
3712
+ "pluginAlias": "@flui-cloud/cli",
3713
+ "pluginName": "@flui-cloud/cli",
3714
+ "pluginType": "core",
3715
+ "strict": true,
3716
+ "enableJsonFlag": false,
3717
+ "isESM": false,
3718
+ "relativePath": [
3719
+ "lib",
3720
+ "cli",
3721
+ "src",
3722
+ "commands",
3723
+ "node",
3724
+ "add.js"
3725
+ ]
3726
+ },
3727
+ "node:list": {
3728
+ "aliases": [],
3729
+ "args": {},
3730
+ "description": "List all nodes in the cluster (master + workers)",
3731
+ "examples": [
3732
+ "<%= config.bin %> <%= command.id %>",
3733
+ "<%= config.bin %> <%= command.id %> --output json"
3734
+ ],
3735
+ "flags": {
3736
+ "cluster": {
3737
+ "char": "c",
3738
+ "description": "Cluster name or ID (default: auto-detect when only one cluster exists)",
3739
+ "name": "cluster",
3740
+ "hasDynamicHelp": false,
3741
+ "multiple": false,
3742
+ "type": "option"
3743
+ },
3744
+ "output": {
3745
+ "char": "o",
3746
+ "description": "Output format",
3747
+ "name": "output",
3748
+ "default": "table",
3749
+ "hasDynamicHelp": false,
3750
+ "multiple": false,
3751
+ "options": [
3752
+ "table",
3753
+ "json"
3754
+ ],
3755
+ "type": "option"
3756
+ }
3757
+ },
3758
+ "hasDynamicHelp": false,
3759
+ "hiddenAliases": [],
3760
+ "id": "node:list",
3761
+ "pluginAlias": "@flui-cloud/cli",
3762
+ "pluginName": "@flui-cloud/cli",
3763
+ "pluginType": "core",
3764
+ "strict": true,
3765
+ "enableJsonFlag": false,
3766
+ "isESM": false,
3767
+ "relativePath": [
3768
+ "lib",
3769
+ "cli",
3770
+ "src",
3771
+ "commands",
3772
+ "node",
3773
+ "list.js"
3774
+ ]
3775
+ },
3776
+ "node:remove": {
3777
+ "aliases": [],
3778
+ "args": {
3779
+ "nodeId": {
3780
+ "description": "Node ID to remove (from `flui node list`)",
3781
+ "name": "nodeId",
3782
+ "required": true
3783
+ }
3784
+ },
3785
+ "description": "Cordon, drain and remove a worker node from the cluster. Cannot remove the master.",
3786
+ "examples": [
3787
+ "<%= config.bin %> <%= command.id %> <node-id>",
3788
+ "<%= config.bin %> <%= command.id %> <node-id> --no-wait"
3789
+ ],
3790
+ "flags": {
3791
+ "cluster": {
3792
+ "char": "c",
3793
+ "description": "Cluster name or ID (default: auto-detect when only one cluster exists)",
3794
+ "name": "cluster",
3795
+ "hasDynamicHelp": false,
3796
+ "multiple": false,
3797
+ "type": "option"
3798
+ },
3799
+ "no-wait": {
3800
+ "description": "Return immediately after queuing the operation",
3801
+ "name": "no-wait",
3802
+ "allowNo": false,
3803
+ "type": "boolean"
3804
+ }
3805
+ },
3806
+ "hasDynamicHelp": false,
3807
+ "hiddenAliases": [],
3808
+ "id": "node:remove",
3809
+ "pluginAlias": "@flui-cloud/cli",
3810
+ "pluginName": "@flui-cloud/cli",
3811
+ "pluginType": "core",
3812
+ "strict": true,
3813
+ "enableJsonFlag": false,
3814
+ "isESM": false,
3815
+ "relativePath": [
3816
+ "lib",
3817
+ "cli",
3818
+ "src",
3819
+ "commands",
3820
+ "node",
3821
+ "remove.js"
3822
+ ]
3823
+ },
3824
+ "server-types:list": {
3825
+ "aliases": [],
3826
+ "args": {},
3827
+ "description": "List available server types for a provider",
3828
+ "examples": [
3829
+ "<%= config.bin %> <%= command.id %> --provider hetzner",
3830
+ "<%= config.bin %> <%= command.id %> --provider hetzner --region fsn1",
3831
+ "<%= config.bin %> <%= command.id %> --provider scaleway --memory 16",
3832
+ "<%= config.bin %> <%= command.id %> --provider scaleway --memory 8-32",
3833
+ "<%= config.bin %> <%= command.id %> --provider scaleway --memory -32",
3834
+ "<%= config.bin %> <%= command.id %> --provider scaleway --sort memory",
3835
+ "<%= config.bin %> <%= command.id %> --provider scaleway --sort price --desc",
3836
+ "<%= config.bin %> <%= command.id %> --provider hetzner --json",
3837
+ "<%= config.bin %> <%= command.id %> --provider hetzner --force-refresh"
3838
+ ],
3839
+ "flags": {
3840
+ "provider": {
3841
+ "char": "p",
3842
+ "description": "Cloud provider",
3843
+ "name": "provider",
3844
+ "required": true,
3845
+ "hasDynamicHelp": false,
3846
+ "multiple": false,
3847
+ "options": [
3848
+ "hetzner",
3849
+ "scaleway"
3850
+ ],
3851
+ "type": "option"
3852
+ },
3853
+ "region": {
3854
+ "char": "r",
3855
+ "description": "Filter by region/location",
3856
+ "name": "region",
3857
+ "hasDynamicHelp": false,
3858
+ "multiple": false,
3859
+ "type": "option"
3860
+ },
3861
+ "memory": {
3862
+ "char": "m",
3863
+ "description": "Filter by RAM in GB: exact \"16\", range \"8-32\", min \"8-\", or max \"-32\"",
3864
+ "name": "memory",
3865
+ "hasDynamicHelp": false,
3866
+ "multiple": false,
3867
+ "type": "option"
3868
+ },
3869
+ "sort": {
3870
+ "char": "s",
3871
+ "description": "Sort by field",
3872
+ "name": "sort",
3873
+ "default": "price",
3874
+ "hasDynamicHelp": false,
3875
+ "multiple": false,
3876
+ "options": [
3877
+ "price",
3878
+ "memory",
3879
+ "cores",
3880
+ "disk",
3881
+ "name"
3882
+ ],
3883
+ "type": "option"
3884
+ },
3885
+ "desc": {
3886
+ "description": "Sort in descending order",
3887
+ "name": "desc",
3888
+ "allowNo": false,
3889
+ "type": "boolean"
3890
+ },
3891
+ "json": {
3892
+ "description": "Output as JSON",
3893
+ "name": "json",
3894
+ "allowNo": false,
3895
+ "type": "boolean"
3896
+ },
3897
+ "force-refresh": {
3898
+ "description": "Force refresh cache from API",
3899
+ "name": "force-refresh",
3900
+ "allowNo": false,
3901
+ "type": "boolean"
3902
+ }
3903
+ },
3904
+ "hasDynamicHelp": false,
3905
+ "hiddenAliases": [],
3906
+ "id": "server-types:list",
3445
3907
  "pluginAlias": "@flui-cloud/cli",
3446
3908
  "pluginName": "@flui-cloud/cli",
3447
3909
  "pluginType": "core",
@@ -3543,101 +4005,34 @@
3543
4005
  "allowNo": false,
3544
4006
  "type": "boolean"
3545
4007
  },
3546
- "k3s-version": {
3547
- "name": "k3s-version",
3548
- "default": "v1.35.4+k3s1",
3549
- "hasDynamicHelp": false,
3550
- "multiple": false,
3551
- "type": "option"
3552
- },
3553
- "skip-precheck": {
3554
- "name": "skip-precheck",
3555
- "allowNo": false,
3556
- "type": "boolean"
3557
- },
3558
- "best-effort": {
3559
- "description": "Proceed even on best-effort or unsupported distros without prompting",
3560
- "name": "best-effort",
3561
- "allowNo": false,
3562
- "type": "boolean"
3563
- },
3564
- "dry-run": {
3565
- "description": "Show what would happen, do not touch the remote host",
3566
- "name": "dry-run",
3567
- "allowNo": false,
3568
- "type": "boolean"
3569
- }
3570
- },
3571
- "hasDynamicHelp": false,
3572
- "hiddenAliases": [],
3573
- "id": "standalone:install",
3574
- "pluginAlias": "@flui-cloud/cli",
3575
- "pluginName": "@flui-cloud/cli",
3576
- "pluginType": "core",
3577
- "strict": true,
3578
- "enableJsonFlag": false,
3579
- "isESM": false,
3580
- "relativePath": [
3581
- "lib",
3582
- "cli",
3583
- "src",
3584
- "commands",
3585
- "standalone",
3586
- "install.js"
3587
- ]
3588
- },
3589
- "template:use": {
3590
- "aliases": [],
3591
- "args": {
3592
- "framework": {
3593
- "description": "Framework template to use (e.g. astro, nextjs, nestjs)",
3594
- "name": "framework",
3595
- "required": true
3596
- },
3597
- "name": {
3598
- "description": "Name for the new GitHub repository",
3599
- "name": "name",
3600
- "required": true
3601
- }
3602
- },
3603
- "description": "Create a new GitHub repository from a Flui framework template and connect it to your account.",
3604
- "examples": [
3605
- "<%= config.bin %> <%= command.id %> astro my-astro-site",
3606
- "<%= config.bin %> <%= command.id %> nextjs my-app --public",
3607
- "<%= config.bin %> <%= command.id %> nestjs my-api --org my-org"
3608
- ],
3609
- "flags": {
3610
- "org": {
3611
- "description": "GitHub organisation or user to create the repo under (default: your account)",
3612
- "name": "org",
3613
- "hasDynamicHelp": false,
3614
- "multiple": false,
3615
- "type": "option"
3616
- },
3617
- "description": {
3618
- "char": "d",
3619
- "description": "Repository description",
3620
- "name": "description",
4008
+ "k3s-version": {
4009
+ "name": "k3s-version",
4010
+ "default": "v1.35.4+k3s1",
3621
4011
  "hasDynamicHelp": false,
3622
4012
  "multiple": false,
3623
4013
  "type": "option"
3624
4014
  },
3625
- "public": {
3626
- "description": "Create as a public repository (default: private)",
3627
- "name": "public",
4015
+ "skip-precheck": {
4016
+ "name": "skip-precheck",
3628
4017
  "allowNo": false,
3629
4018
  "type": "boolean"
3630
4019
  },
3631
- "no-import": {
3632
- "description": "Skip auto-importing the repository into Flui",
3633
- "name": "no-import",
4020
+ "best-effort": {
4021
+ "description": "Proceed even on best-effort or unsupported distros without prompting",
4022
+ "name": "best-effort",
4023
+ "allowNo": false,
4024
+ "type": "boolean"
4025
+ },
4026
+ "dry-run": {
4027
+ "description": "Show what would happen, do not touch the remote host",
4028
+ "name": "dry-run",
3634
4029
  "allowNo": false,
3635
4030
  "type": "boolean"
3636
4031
  }
3637
4032
  },
3638
4033
  "hasDynamicHelp": false,
3639
4034
  "hiddenAliases": [],
3640
- "id": "template:use",
4035
+ "id": "standalone:install",
3641
4036
  "pluginAlias": "@flui-cloud/cli",
3642
4037
  "pluginName": "@flui-cloud/cli",
3643
4038
  "pluginType": "core",
@@ -3649,11 +4044,11 @@
3649
4044
  "cli",
3650
4045
  "src",
3651
4046
  "commands",
3652
- "template",
3653
- "use.js"
4047
+ "standalone",
4048
+ "install.js"
3654
4049
  ]
3655
4050
  },
3656
- "app:backup:create": {
4051
+ "app:snapshot:create": {
3657
4052
  "aliases": [],
3658
4053
  "args": {
3659
4054
  "name": {
@@ -3662,11 +4057,11 @@
3662
4057
  "required": true
3663
4058
  }
3664
4059
  },
3665
- "description": "Archive an application volume to S3-compatible object storage. When --bucket is omitted the cluster provider auto-provisions one (Scaleway: full-auto using your compute key; Hetzner: requires Object Storage credentials connected). Otherwise pass an explicit endpoint + --bucket and S3 credentials via flags or FLUI_S3_ACCESS_KEY/FLUI_S3_SECRET_KEY env.",
4060
+ "description": "Create a snapshot of an application volume. Today on every provider this is a full PVC clone built via the copy-pod export primitive (sink=pvc-clone) because workload PVCs use local-path. Cost: a full Volume per snapshot.",
3666
4061
  "examples": [
3667
4062
  "<%= config.bin %> <%= command.id %> my-app",
3668
- "<%= config.bin %> <%= command.id %> my-app --description nightly",
3669
- "<%= config.bin %> <%= command.id %> my-app -b external-bucket -e https://s3.eu-central-1.amazonaws.com -r eu-central-1"
4063
+ "<%= config.bin %> <%= command.id %> my-app --description before-upgrade",
4064
+ "<%= config.bin %> <%= command.id %> my-app --volume data"
3670
4065
  ],
3671
4066
  "flags": {
3672
4067
  "cluster": {
@@ -3687,64 +4082,16 @@
3687
4082
  },
3688
4083
  "description": {
3689
4084
  "char": "d",
3690
- "description": "Optional human-friendly tag appended to the key prefix",
4085
+ "description": "Optional human-friendly tag appended to the snapshot id",
3691
4086
  "name": "description",
3692
4087
  "hasDynamicHelp": false,
3693
4088
  "multiple": false,
3694
4089
  "type": "option"
3695
- },
3696
- "bucket": {
3697
- "char": "b",
3698
- "description": "Destination S3 bucket name. Omit to auto-provision via the cluster provider.",
3699
- "name": "bucket",
3700
- "hasDynamicHelp": false,
3701
- "multiple": false,
3702
- "type": "option"
3703
- },
3704
- "endpoint": {
3705
- "char": "e",
3706
- "description": "S3 endpoint URL (required when --bucket is set). Examples: https://s3.fr-par.scw.cloud, https://s3.eu-central-1.amazonaws.com",
3707
- "name": "endpoint",
3708
- "hasDynamicHelp": false,
3709
- "multiple": false,
3710
- "type": "option"
3711
- },
3712
- "region": {
3713
- "char": "r",
3714
- "description": "S3 region",
3715
- "name": "region",
3716
- "default": "auto",
3717
- "hasDynamicHelp": false,
3718
- "multiple": false,
3719
- "type": "option"
3720
- },
3721
- "access-key": {
3722
- "description": "S3 access key. Defaults to FLUI_S3_ACCESS_KEY env var.",
3723
- "env": "FLUI_S3_ACCESS_KEY",
3724
- "name": "access-key",
3725
- "hasDynamicHelp": false,
3726
- "multiple": false,
3727
- "type": "option"
3728
- },
3729
- "secret-key": {
3730
- "description": "S3 secret key. Defaults to FLUI_S3_SECRET_KEY env var.",
3731
- "env": "FLUI_S3_SECRET_KEY",
3732
- "name": "secret-key",
3733
- "hasDynamicHelp": false,
3734
- "multiple": false,
3735
- "type": "option"
3736
- },
3737
- "key-prefix": {
3738
- "description": "Override the destination key prefix (default: flui/<cluster>/<app>/<timestamp>/)",
3739
- "name": "key-prefix",
3740
- "hasDynamicHelp": false,
3741
- "multiple": false,
3742
- "type": "option"
3743
4090
  }
3744
4091
  },
3745
4092
  "hasDynamicHelp": false,
3746
4093
  "hiddenAliases": [],
3747
- "id": "app:backup:create",
4094
+ "id": "app:snapshot:create",
3748
4095
  "pluginAlias": "@flui-cloud/cli",
3749
4096
  "pluginName": "@flui-cloud/cli",
3750
4097
  "pluginType": "core",
@@ -3757,11 +4104,11 @@
3757
4104
  "src",
3758
4105
  "commands",
3759
4106
  "app",
3760
- "backup",
4107
+ "snapshot",
3761
4108
  "create.js"
3762
4109
  ]
3763
4110
  },
3764
- "app:backup:delete": {
4111
+ "app:snapshot:delete": {
3765
4112
  "aliases": [],
3766
4113
  "args": {
3767
4114
  "name": {
@@ -3769,15 +4116,16 @@
3769
4116
  "name": "name",
3770
4117
  "required": true
3771
4118
  },
3772
- "exportId": {
3773
- "description": "Export id (S3 key prefix) returned by `flui app backup create`",
3774
- "name": "exportId",
4119
+ "snapshotId": {
4120
+ "description": "Snapshot id (from `flui app snapshot list`)",
4121
+ "name": "snapshotId",
3775
4122
  "required": true
3776
4123
  }
3777
4124
  },
3778
- "description": "Delete an S3 backup of an application. Removes all objects under the export key prefix.",
4125
+ "description": "Delete a volume snapshot of an application.",
3779
4126
  "examples": [
3780
- "<%= config.bin %> <%= command.id %> my-app flui/<cluster>/<app>/20260510170000-abc123 -b my-bucket -e https://s3.fr-par.scw.cloud"
4127
+ "<%= config.bin %> <%= command.id %> my-app my-app-snap-20260510-abcdef",
4128
+ "<%= config.bin %> <%= command.id %> my-app my-app-snap-... --force"
3781
4129
  ],
3782
4130
  "flags": {
3783
4131
  "cluster": {
@@ -3788,49 +4136,6 @@
3788
4136
  "multiple": false,
3789
4137
  "type": "option"
3790
4138
  },
3791
- "bucket": {
3792
- "char": "b",
3793
- "description": "S3 bucket where the backup lives",
3794
- "name": "bucket",
3795
- "required": true,
3796
- "hasDynamicHelp": false,
3797
- "multiple": false,
3798
- "type": "option"
3799
- },
3800
- "endpoint": {
3801
- "char": "e",
3802
- "description": "S3 endpoint URL",
3803
- "name": "endpoint",
3804
- "required": true,
3805
- "hasDynamicHelp": false,
3806
- "multiple": false,
3807
- "type": "option"
3808
- },
3809
- "region": {
3810
- "char": "r",
3811
- "description": "S3 region",
3812
- "name": "region",
3813
- "default": "auto",
3814
- "hasDynamicHelp": false,
3815
- "multiple": false,
3816
- "type": "option"
3817
- },
3818
- "access-key": {
3819
- "description": "S3 access key id (defaults to FLUI_S3_ACCESS_KEY env)",
3820
- "env": "FLUI_S3_ACCESS_KEY",
3821
- "name": "access-key",
3822
- "hasDynamicHelp": false,
3823
- "multiple": false,
3824
- "type": "option"
3825
- },
3826
- "secret-key": {
3827
- "description": "S3 secret access key (defaults to FLUI_S3_SECRET_KEY env)",
3828
- "env": "FLUI_S3_SECRET_KEY",
3829
- "name": "secret-key",
3830
- "hasDynamicHelp": false,
3831
- "multiple": false,
3832
- "type": "option"
3833
- },
3834
4139
  "force": {
3835
4140
  "char": "f",
3836
4141
  "description": "Skip confirmation",
@@ -3841,7 +4146,7 @@
3841
4146
  },
3842
4147
  "hasDynamicHelp": false,
3843
4148
  "hiddenAliases": [],
3844
- "id": "app:backup:delete",
4149
+ "id": "app:snapshot:delete",
3845
4150
  "pluginAlias": "@flui-cloud/cli",
3846
4151
  "pluginName": "@flui-cloud/cli",
3847
4152
  "pluginType": "core",
@@ -3854,102 +4159,44 @@
3854
4159
  "src",
3855
4160
  "commands",
3856
4161
  "app",
3857
- "backup",
4162
+ "snapshot",
3858
4163
  "delete.js"
3859
4164
  ]
3860
4165
  },
3861
- "repo:connect": {
3862
- "aliases": [],
3863
- "args": {
3864
- "repo": {
3865
- "description": "Full repository name `owner/repo`. Omit to pick interactively.",
3866
- "name": "repo",
3867
- "required": false
3868
- }
3869
- },
3870
- "description": "Connect (import) a GitHub repository into your Flui account so it can be deployed with `flui deploy`. Pass the full name `owner/repo`, or omit it for an interactive picker over the repositories accessible via your GitHub integration.",
3871
- "examples": [
3872
- "<%= config.bin %> <%= command.id %> acme/my-app",
3873
- "<%= config.bin %> <%= command.id %>"
3874
- ],
3875
- "flags": {},
3876
- "hasDynamicHelp": false,
3877
- "hiddenAliases": [],
3878
- "id": "repo:connect",
3879
- "pluginAlias": "@flui-cloud/cli",
3880
- "pluginName": "@flui-cloud/cli",
3881
- "pluginType": "core",
3882
- "strict": true,
3883
- "enableJsonFlag": false,
3884
- "isESM": false,
3885
- "relativePath": [
3886
- "lib",
3887
- "cli",
3888
- "src",
3889
- "commands",
3890
- "repo",
3891
- "connect.js"
3892
- ]
3893
- },
3894
- "repo:disconnect": {
3895
- "aliases": [],
3896
- "args": {
3897
- "repo": {
3898
- "description": "Full repository name `owner/repo`",
3899
- "name": "repo",
3900
- "required": true
3901
- }
3902
- },
3903
- "description": "Disconnect a repository from your Flui account. Requires admin privileges. Does not delete the repository on GitHub.",
3904
- "examples": [
3905
- "<%= config.bin %> <%= command.id %> acme/my-app",
3906
- "<%= config.bin %> <%= command.id %> acme/my-app --yes"
3907
- ],
3908
- "flags": {
3909
- "yes": {
3910
- "char": "y",
3911
- "description": "Skip the confirmation prompt",
3912
- "name": "yes",
3913
- "allowNo": false,
3914
- "type": "boolean"
3915
- }
3916
- },
3917
- "hasDynamicHelp": false,
3918
- "hiddenAliases": [],
3919
- "id": "repo:disconnect",
3920
- "pluginAlias": "@flui-cloud/cli",
3921
- "pluginName": "@flui-cloud/cli",
3922
- "pluginType": "core",
3923
- "strict": true,
3924
- "enableJsonFlag": false,
3925
- "isESM": false,
3926
- "relativePath": [
3927
- "lib",
3928
- "cli",
3929
- "src",
3930
- "commands",
3931
- "repo",
3932
- "disconnect.js"
3933
- ]
3934
- },
3935
- "repo:list": {
4166
+ "app:snapshot:list": {
3936
4167
  "aliases": [],
3937
4168
  "args": {},
3938
- "description": "List repositories connected to your Flui account.",
4169
+ "description": "List volume snapshots. Use --app to filter to a single app, omit to list cluster-wide.",
3939
4170
  "examples": [
3940
4171
  "<%= config.bin %> <%= command.id %>",
3941
- "<%= config.bin %> <%= command.id %> --output json"
4172
+ "<%= config.bin %> <%= command.id %> --app my-app"
3942
4173
  ],
3943
4174
  "flags": {
4175
+ "cluster": {
4176
+ "char": "c",
4177
+ "description": "Cluster name or ID (default: auto-detect)",
4178
+ "name": "cluster",
4179
+ "hasDynamicHelp": false,
4180
+ "multiple": false,
4181
+ "type": "option"
4182
+ },
4183
+ "app": {
4184
+ "char": "a",
4185
+ "description": "Filter by application name or slug",
4186
+ "name": "app",
4187
+ "hasDynamicHelp": false,
4188
+ "multiple": false,
4189
+ "type": "option"
4190
+ },
3944
4191
  "output": {
3945
4192
  "char": "o",
3946
4193
  "description": "Output format",
3947
4194
  "name": "output",
3948
- "default": "text",
4195
+ "default": "table",
3949
4196
  "hasDynamicHelp": false,
3950
4197
  "multiple": false,
3951
4198
  "options": [
3952
- "text",
4199
+ "table",
3953
4200
  "json"
3954
4201
  ],
3955
4202
  "type": "option"
@@ -3957,7 +4204,7 @@
3957
4204
  },
3958
4205
  "hasDynamicHelp": false,
3959
4206
  "hiddenAliases": [],
3960
- "id": "repo:list",
4207
+ "id": "app:snapshot:list",
3961
4208
  "pluginAlias": "@flui-cloud/cli",
3962
4209
  "pluginName": "@flui-cloud/cli",
3963
4210
  "pluginType": "core",
@@ -3969,24 +4216,29 @@
3969
4216
  "cli",
3970
4217
  "src",
3971
4218
  "commands",
3972
- "repo",
4219
+ "app",
4220
+ "snapshot",
3973
4221
  "list.js"
3974
4222
  ]
3975
4223
  },
3976
- "app:snapshot:create": {
4224
+ "app:snapshot:restore": {
3977
4225
  "aliases": [],
3978
4226
  "args": {
3979
4227
  "name": {
3980
4228
  "description": "Application name or slug",
3981
4229
  "name": "name",
3982
4230
  "required": true
4231
+ },
4232
+ "snapshotId": {
4233
+ "description": "Snapshot id (from `flui app snapshot list`)",
4234
+ "name": "snapshotId",
4235
+ "required": true
3983
4236
  }
3984
4237
  },
3985
- "description": "Create a snapshot of an application volume. Today on every provider this is a full PVC clone built via the copy-pod export primitive (sink=pvc-clone) because workload PVCs use local-path. Cost: a full Volume per snapshot.",
4238
+ "description": "Restore a snapshot into a new side-by-side PVC. The application is not touched the new PVC is created in the same namespace and can be promoted later with `flui app snapshot swap`.",
3986
4239
  "examples": [
3987
- "<%= config.bin %> <%= command.id %> my-app",
3988
- "<%= config.bin %> <%= command.id %> my-app --description before-upgrade",
3989
- "<%= config.bin %> <%= command.id %> my-app --volume data"
4240
+ "<%= config.bin %> <%= command.id %> my-app my-app-snap-20260510-abcdef",
4241
+ "<%= config.bin %> <%= command.id %> my-app my-app-snap-... --swap"
3990
4242
  ],
3991
4243
  "flags": {
3992
4244
  "cluster": {
@@ -3997,26 +4249,24 @@
3997
4249
  "multiple": false,
3998
4250
  "type": "option"
3999
4251
  },
4252
+ "swap": {
4253
+ "description": "Immediately swap the restored PVC into the live application (rolling restart). Old PVC is preserved as a backup.",
4254
+ "name": "swap",
4255
+ "allowNo": false,
4256
+ "type": "boolean"
4257
+ },
4000
4258
  "volume": {
4001
4259
  "char": "v",
4002
- "description": "Volume (PVC) name when the app has multiple volumes. Required if more than one PVC exists.",
4260
+ "description": "Application volume name to swap when --swap is set. Required if the app has multiple volumes.",
4003
4261
  "name": "volume",
4004
4262
  "hasDynamicHelp": false,
4005
4263
  "multiple": false,
4006
4264
  "type": "option"
4007
- },
4008
- "description": {
4009
- "char": "d",
4010
- "description": "Optional human-friendly tag appended to the snapshot id",
4011
- "name": "description",
4012
- "hasDynamicHelp": false,
4013
- "multiple": false,
4014
- "type": "option"
4015
4265
  }
4016
4266
  },
4017
4267
  "hasDynamicHelp": false,
4018
4268
  "hiddenAliases": [],
4019
- "id": "app:snapshot:create",
4269
+ "id": "app:snapshot:restore",
4020
4270
  "pluginAlias": "@flui-cloud/cli",
4021
4271
  "pluginName": "@flui-cloud/cli",
4022
4272
  "pluginType": "core",
@@ -4030,10 +4280,10 @@
4030
4280
  "commands",
4031
4281
  "app",
4032
4282
  "snapshot",
4033
- "create.js"
4283
+ "restore.js"
4034
4284
  ]
4035
4285
  },
4036
- "app:snapshot:delete": {
4286
+ "app:snapshot:swap": {
4037
4287
  "aliases": [],
4038
4288
  "args": {
4039
4289
  "name": {
@@ -4041,16 +4291,16 @@
4041
4291
  "name": "name",
4042
4292
  "required": true
4043
4293
  },
4044
- "snapshotId": {
4045
- "description": "Snapshot id (from `flui app snapshot list`)",
4046
- "name": "snapshotId",
4294
+ "newPvcName": {
4295
+ "description": "PVC name to swap into the application",
4296
+ "name": "newPvcName",
4047
4297
  "required": true
4048
4298
  }
4049
4299
  },
4050
- "description": "Delete a volume snapshot of an application.",
4300
+ "description": "Swap the application volume to a different PVC (typically one created by `flui app snapshot restore`). Triggers a rolling restart. The previous PVC is preserved as a backup.",
4051
4301
  "examples": [
4052
- "<%= config.bin %> <%= command.id %> my-app my-app-snap-20260510-abcdef",
4053
- "<%= config.bin %> <%= command.id %> my-app my-app-snap-... --force"
4302
+ "<%= config.bin %> <%= command.id %> my-app my-app-data-restored-20260511",
4303
+ "<%= config.bin %> <%= command.id %> my-app new-pvc --volume data --force"
4054
4304
  ],
4055
4305
  "flags": {
4056
4306
  "cluster": {
@@ -4061,6 +4311,14 @@
4061
4311
  "multiple": false,
4062
4312
  "type": "option"
4063
4313
  },
4314
+ "volume": {
4315
+ "char": "v",
4316
+ "description": "Application volume name (default: the single volume)",
4317
+ "name": "volume",
4318
+ "hasDynamicHelp": false,
4319
+ "multiple": false,
4320
+ "type": "option"
4321
+ },
4064
4322
  "force": {
4065
4323
  "char": "f",
4066
4324
  "description": "Skip confirmation",
@@ -4071,7 +4329,7 @@
4071
4329
  },
4072
4330
  "hasDynamicHelp": false,
4073
4331
  "hiddenAliases": [],
4074
- "id": "app:snapshot:delete",
4332
+ "id": "app:snapshot:swap",
4075
4333
  "pluginAlias": "@flui-cloud/cli",
4076
4334
  "pluginName": "@flui-cloud/cli",
4077
4335
  "pluginType": "core",
@@ -4085,51 +4343,61 @@
4085
4343
  "commands",
4086
4344
  "app",
4087
4345
  "snapshot",
4088
- "delete.js"
4346
+ "swap.js"
4089
4347
  ]
4090
4348
  },
4091
- "app:snapshot:list": {
4349
+ "template:use": {
4092
4350
  "aliases": [],
4093
- "args": {},
4094
- "description": "List volume snapshots. Use --app to filter to a single app, omit to list cluster-wide.",
4351
+ "args": {
4352
+ "framework": {
4353
+ "description": "Framework template to use (e.g. astro, nextjs, nestjs)",
4354
+ "name": "framework",
4355
+ "required": true
4356
+ },
4357
+ "name": {
4358
+ "description": "Name for the new GitHub repository",
4359
+ "name": "name",
4360
+ "required": true
4361
+ }
4362
+ },
4363
+ "description": "Create a new GitHub repository from a Flui framework template and connect it to your account.",
4095
4364
  "examples": [
4096
- "<%= config.bin %> <%= command.id %>",
4097
- "<%= config.bin %> <%= command.id %> --app my-app"
4365
+ "<%= config.bin %> <%= command.id %> astro my-astro-site",
4366
+ "<%= config.bin %> <%= command.id %> nextjs my-app --public",
4367
+ "<%= config.bin %> <%= command.id %> nestjs my-api --org my-org"
4098
4368
  ],
4099
4369
  "flags": {
4100
- "cluster": {
4101
- "char": "c",
4102
- "description": "Cluster name or ID (default: auto-detect)",
4103
- "name": "cluster",
4370
+ "org": {
4371
+ "description": "GitHub organisation or user to create the repo under (default: your account)",
4372
+ "name": "org",
4104
4373
  "hasDynamicHelp": false,
4105
4374
  "multiple": false,
4106
4375
  "type": "option"
4107
4376
  },
4108
- "app": {
4109
- "char": "a",
4110
- "description": "Filter by application name or slug",
4111
- "name": "app",
4377
+ "description": {
4378
+ "char": "d",
4379
+ "description": "Repository description",
4380
+ "name": "description",
4112
4381
  "hasDynamicHelp": false,
4113
4382
  "multiple": false,
4114
4383
  "type": "option"
4115
4384
  },
4116
- "output": {
4117
- "char": "o",
4118
- "description": "Output format",
4119
- "name": "output",
4120
- "default": "table",
4121
- "hasDynamicHelp": false,
4122
- "multiple": false,
4123
- "options": [
4124
- "table",
4125
- "json"
4126
- ],
4127
- "type": "option"
4385
+ "public": {
4386
+ "description": "Create as a public repository (default: private)",
4387
+ "name": "public",
4388
+ "allowNo": false,
4389
+ "type": "boolean"
4390
+ },
4391
+ "no-import": {
4392
+ "description": "Skip auto-importing the repository into Flui",
4393
+ "name": "no-import",
4394
+ "allowNo": false,
4395
+ "type": "boolean"
4128
4396
  }
4129
4397
  },
4130
4398
  "hasDynamicHelp": false,
4131
4399
  "hiddenAliases": [],
4132
- "id": "app:snapshot:list",
4400
+ "id": "template:use",
4133
4401
  "pluginAlias": "@flui-cloud/cli",
4134
4402
  "pluginName": "@flui-cloud/cli",
4135
4403
  "pluginType": "core",
@@ -4141,29 +4409,24 @@
4141
4409
  "cli",
4142
4410
  "src",
4143
4411
  "commands",
4144
- "app",
4145
- "snapshot",
4146
- "list.js"
4412
+ "template",
4413
+ "use.js"
4147
4414
  ]
4148
4415
  },
4149
- "app:snapshot:restore": {
4416
+ "app:backup:create": {
4150
4417
  "aliases": [],
4151
4418
  "args": {
4152
4419
  "name": {
4153
4420
  "description": "Application name or slug",
4154
4421
  "name": "name",
4155
4422
  "required": true
4156
- },
4157
- "snapshotId": {
4158
- "description": "Snapshot id (from `flui app snapshot list`)",
4159
- "name": "snapshotId",
4160
- "required": true
4161
4423
  }
4162
4424
  },
4163
- "description": "Restore a snapshot into a new side-by-side PVC. The application is not touched the new PVC is created in the same namespace and can be promoted later with `flui app snapshot swap`.",
4425
+ "description": "Archive an application volume to S3-compatible object storage. When --bucket is omitted the cluster provider auto-provisions one (Scaleway: full-auto using your compute key; Hetzner: requires Object Storage credentials connected). Otherwise pass an explicit endpoint + --bucket and S3 credentials via flags or FLUI_S3_ACCESS_KEY/FLUI_S3_SECRET_KEY env.",
4164
4426
  "examples": [
4165
- "<%= config.bin %> <%= command.id %> my-app my-app-snap-20260510-abcdef",
4166
- "<%= config.bin %> <%= command.id %> my-app my-app-snap-... --swap"
4427
+ "<%= config.bin %> <%= command.id %> my-app",
4428
+ "<%= config.bin %> <%= command.id %> my-app --description nightly",
4429
+ "<%= config.bin %> <%= command.id %> my-app -b external-bucket -e https://s3.eu-central-1.amazonaws.com -r eu-central-1"
4167
4430
  ],
4168
4431
  "flags": {
4169
4432
  "cluster": {
@@ -4174,24 +4437,74 @@
4174
4437
  "multiple": false,
4175
4438
  "type": "option"
4176
4439
  },
4177
- "swap": {
4178
- "description": "Immediately swap the restored PVC into the live application (rolling restart). Old PVC is preserved as a backup.",
4179
- "name": "swap",
4180
- "allowNo": false,
4181
- "type": "boolean"
4182
- },
4183
4440
  "volume": {
4184
4441
  "char": "v",
4185
- "description": "Application volume name to swap when --swap is set. Required if the app has multiple volumes.",
4442
+ "description": "Volume (PVC) name when the app has multiple volumes. Required if more than one PVC exists.",
4186
4443
  "name": "volume",
4187
4444
  "hasDynamicHelp": false,
4188
4445
  "multiple": false,
4189
4446
  "type": "option"
4447
+ },
4448
+ "description": {
4449
+ "char": "d",
4450
+ "description": "Optional human-friendly tag appended to the key prefix",
4451
+ "name": "description",
4452
+ "hasDynamicHelp": false,
4453
+ "multiple": false,
4454
+ "type": "option"
4455
+ },
4456
+ "bucket": {
4457
+ "char": "b",
4458
+ "description": "Destination S3 bucket name. Omit to auto-provision via the cluster provider.",
4459
+ "name": "bucket",
4460
+ "hasDynamicHelp": false,
4461
+ "multiple": false,
4462
+ "type": "option"
4463
+ },
4464
+ "endpoint": {
4465
+ "char": "e",
4466
+ "description": "S3 endpoint URL (required when --bucket is set). Examples: https://s3.fr-par.scw.cloud, https://s3.eu-central-1.amazonaws.com",
4467
+ "name": "endpoint",
4468
+ "hasDynamicHelp": false,
4469
+ "multiple": false,
4470
+ "type": "option"
4471
+ },
4472
+ "region": {
4473
+ "char": "r",
4474
+ "description": "S3 region",
4475
+ "name": "region",
4476
+ "default": "auto",
4477
+ "hasDynamicHelp": false,
4478
+ "multiple": false,
4479
+ "type": "option"
4480
+ },
4481
+ "access-key": {
4482
+ "description": "S3 access key. Defaults to FLUI_S3_ACCESS_KEY env var.",
4483
+ "env": "FLUI_S3_ACCESS_KEY",
4484
+ "name": "access-key",
4485
+ "hasDynamicHelp": false,
4486
+ "multiple": false,
4487
+ "type": "option"
4488
+ },
4489
+ "secret-key": {
4490
+ "description": "S3 secret key. Defaults to FLUI_S3_SECRET_KEY env var.",
4491
+ "env": "FLUI_S3_SECRET_KEY",
4492
+ "name": "secret-key",
4493
+ "hasDynamicHelp": false,
4494
+ "multiple": false,
4495
+ "type": "option"
4496
+ },
4497
+ "key-prefix": {
4498
+ "description": "Override the destination key prefix (default: flui/<cluster>/<app>/<timestamp>/)",
4499
+ "name": "key-prefix",
4500
+ "hasDynamicHelp": false,
4501
+ "multiple": false,
4502
+ "type": "option"
4190
4503
  }
4191
4504
  },
4192
4505
  "hasDynamicHelp": false,
4193
4506
  "hiddenAliases": [],
4194
- "id": "app:snapshot:restore",
4507
+ "id": "app:backup:create",
4195
4508
  "pluginAlias": "@flui-cloud/cli",
4196
4509
  "pluginName": "@flui-cloud/cli",
4197
4510
  "pluginType": "core",
@@ -4204,11 +4517,11 @@
4204
4517
  "src",
4205
4518
  "commands",
4206
4519
  "app",
4207
- "snapshot",
4208
- "restore.js"
4520
+ "backup",
4521
+ "create.js"
4209
4522
  ]
4210
4523
  },
4211
- "app:snapshot:swap": {
4524
+ "app:backup:delete": {
4212
4525
  "aliases": [],
4213
4526
  "args": {
4214
4527
  "name": {
@@ -4216,16 +4529,15 @@
4216
4529
  "name": "name",
4217
4530
  "required": true
4218
4531
  },
4219
- "newPvcName": {
4220
- "description": "PVC name to swap into the application",
4221
- "name": "newPvcName",
4532
+ "exportId": {
4533
+ "description": "Export id (S3 key prefix) returned by `flui app backup create`",
4534
+ "name": "exportId",
4222
4535
  "required": true
4223
4536
  }
4224
4537
  },
4225
- "description": "Swap the application volume to a different PVC (typically one created by `flui app snapshot restore`). Triggers a rolling restart. The previous PVC is preserved as a backup.",
4538
+ "description": "Delete an S3 backup of an application. Removes all objects under the export key prefix.",
4226
4539
  "examples": [
4227
- "<%= config.bin %> <%= command.id %> my-app my-app-data-restored-20260511",
4228
- "<%= config.bin %> <%= command.id %> my-app new-pvc --volume data --force"
4540
+ "<%= config.bin %> <%= command.id %> my-app flui/<cluster>/<app>/20260510170000-abc123 -b my-bucket -e https://s3.fr-par.scw.cloud"
4229
4541
  ],
4230
4542
  "flags": {
4231
4543
  "cluster": {
@@ -4236,10 +4548,45 @@
4236
4548
  "multiple": false,
4237
4549
  "type": "option"
4238
4550
  },
4239
- "volume": {
4240
- "char": "v",
4241
- "description": "Application volume name (default: the single volume)",
4242
- "name": "volume",
4551
+ "bucket": {
4552
+ "char": "b",
4553
+ "description": "S3 bucket where the backup lives",
4554
+ "name": "bucket",
4555
+ "required": true,
4556
+ "hasDynamicHelp": false,
4557
+ "multiple": false,
4558
+ "type": "option"
4559
+ },
4560
+ "endpoint": {
4561
+ "char": "e",
4562
+ "description": "S3 endpoint URL",
4563
+ "name": "endpoint",
4564
+ "required": true,
4565
+ "hasDynamicHelp": false,
4566
+ "multiple": false,
4567
+ "type": "option"
4568
+ },
4569
+ "region": {
4570
+ "char": "r",
4571
+ "description": "S3 region",
4572
+ "name": "region",
4573
+ "default": "auto",
4574
+ "hasDynamicHelp": false,
4575
+ "multiple": false,
4576
+ "type": "option"
4577
+ },
4578
+ "access-key": {
4579
+ "description": "S3 access key id (defaults to FLUI_S3_ACCESS_KEY env)",
4580
+ "env": "FLUI_S3_ACCESS_KEY",
4581
+ "name": "access-key",
4582
+ "hasDynamicHelp": false,
4583
+ "multiple": false,
4584
+ "type": "option"
4585
+ },
4586
+ "secret-key": {
4587
+ "description": "S3 secret access key (defaults to FLUI_S3_SECRET_KEY env)",
4588
+ "env": "FLUI_S3_SECRET_KEY",
4589
+ "name": "secret-key",
4243
4590
  "hasDynamicHelp": false,
4244
4591
  "multiple": false,
4245
4592
  "type": "option"
@@ -4254,7 +4601,7 @@
4254
4601
  },
4255
4602
  "hasDynamicHelp": false,
4256
4603
  "hiddenAliases": [],
4257
- "id": "app:snapshot:swap",
4604
+ "id": "app:backup:delete",
4258
4605
  "pluginAlias": "@flui-cloud/cli",
4259
4606
  "pluginName": "@flui-cloud/cli",
4260
4607
  "pluginType": "core",
@@ -4267,8 +4614,8 @@
4267
4614
  "src",
4268
4615
  "commands",
4269
4616
  "app",
4270
- "snapshot",
4271
- "swap.js"
4617
+ "backup",
4618
+ "delete.js"
4272
4619
  ]
4273
4620
  },
4274
4621
  "app:image:delete": {
@@ -4608,116 +4955,75 @@
4608
4955
  "test.js"
4609
4956
  ]
4610
4957
  },
4611
- "backup:policy:create": {
4958
+ "backup:restore:create": {
4612
4959
  "aliases": [],
4613
4960
  "args": {},
4614
- "description": "Create a backup policy",
4615
- "examples": [
4616
- "<%= config.bin %> <%= command.id %> --name daily-all --cluster <id> --scope cluster_all --schedule \"0 2 * * *\" --retention-days 14 --destination <destId>",
4617
- "<%= config.bin %> <%= command.id %> --name app-snap --cluster <id> --scope applications --scope-namespaces ns1,ns2 --destination <destId>"
4618
- ],
4961
+ "description": "Create a restore job",
4619
4962
  "flags": {
4620
- "name": {
4621
- "name": "name",
4963
+ "artifact": {
4964
+ "description": "Backup artifact ID",
4965
+ "name": "artifact",
4622
4966
  "required": true,
4623
4967
  "hasDynamicHelp": false,
4624
4968
  "multiple": false,
4625
4969
  "type": "option"
4626
4970
  },
4627
- "cluster": {
4628
- "description": "Cluster ID",
4629
- "name": "cluster",
4971
+ "source-destination": {
4972
+ "name": "source-destination",
4630
4973
  "required": true,
4631
4974
  "hasDynamicHelp": false,
4632
4975
  "multiple": false,
4633
4976
  "type": "option"
4634
4977
  },
4635
- "scope": {
4636
- "name": "scope",
4978
+ "target-cluster": {
4979
+ "description": "Cluster to restore into",
4980
+ "name": "target-cluster",
4637
4981
  "required": true,
4638
4982
  "hasDynamicHelp": false,
4639
4983
  "multiple": false,
4640
- "options": [
4641
- "cluster_all",
4642
- "namespaces",
4643
- "applications",
4644
- "label_selector"
4645
- ],
4646
- "type": "option"
4647
- },
4648
- "scope-namespaces": {
4649
- "description": "Comma-separated namespaces (for scope=namespaces)",
4650
- "name": "scope-namespaces",
4651
- "hasDynamicHelp": false,
4652
- "multiple": false,
4653
- "type": "option"
4654
- },
4655
- "scope-apps": {
4656
- "description": "Comma-separated application IDs (for scope=applications)",
4657
- "name": "scope-apps",
4658
- "hasDynamicHelp": false,
4659
- "multiple": false,
4660
4984
  "type": "option"
4661
4985
  },
4662
- "profile": {
4663
- "name": "profile",
4664
- "default": "single",
4986
+ "target-kind": {
4987
+ "name": "target-kind",
4988
+ "required": true,
4665
4989
  "hasDynamicHelp": false,
4666
4990
  "multiple": false,
4667
4991
  "options": [
4668
- "single",
4669
- "mirrored",
4670
- "custom"
4992
+ "cluster",
4993
+ "namespace",
4994
+ "application",
4995
+ "observability"
4671
4996
  ],
4672
4997
  "type": "option"
4673
4998
  },
4674
- "schedule": {
4675
- "description": "Cron schedule (e.g. \"0 2 * * *\" for daily 02:00 UTC)",
4676
- "name": "schedule",
4999
+ "target-namespace": {
5000
+ "description": "Required when --target-kind=namespace",
5001
+ "name": "target-namespace",
4677
5002
  "hasDynamicHelp": false,
4678
5003
  "multiple": false,
4679
5004
  "type": "option"
4680
5005
  },
4681
- "retention-days": {
4682
- "name": "retention-days",
4683
- "default": 30,
5006
+ "target-app": {
5007
+ "description": "Required when --target-kind=application",
5008
+ "name": "target-app",
4684
5009
  "hasDynamicHelp": false,
4685
5010
  "multiple": false,
4686
5011
  "type": "option"
4687
5012
  },
4688
- "retention-max-copies": {
4689
- "name": "retention-max-copies",
5013
+ "strategy": {
5014
+ "name": "strategy",
4690
5015
  "hasDynamicHelp": false,
4691
5016
  "multiple": false,
4692
- "type": "option"
4693
- },
4694
- "include-pvcs": {
4695
- "name": "include-pvcs",
4696
- "allowNo": false,
4697
- "type": "boolean"
4698
- },
4699
- "include-etcd-l1": {
4700
- "name": "include-etcd-l1",
4701
- "allowNo": false,
4702
- "type": "boolean"
4703
- },
4704
- "enabled": {
4705
- "name": "enabled",
4706
- "allowNo": true,
4707
- "type": "boolean"
4708
- },
4709
- "destination": {
4710
- "description": "Destination spec: <destId>[:primary|replica[:priority]] (repeatable)",
4711
- "name": "destination",
4712
- "required": true,
4713
- "hasDynamicHelp": false,
4714
- "multiple": true,
5017
+ "options": [
5018
+ "velero_rebuild",
5019
+ "os_snapshot"
5020
+ ],
4715
5021
  "type": "option"
4716
5022
  }
4717
5023
  },
4718
5024
  "hasDynamicHelp": false,
4719
5025
  "hiddenAliases": [],
4720
- "id": "backup:policy:create",
5026
+ "id": "backup:restore:create",
4721
5027
  "pluginAlias": "@flui-cloud/cli",
4722
5028
  "pluginName": "@flui-cloud/cli",
4723
5029
  "pluginType": "core",
@@ -4730,58 +5036,15 @@
4730
5036
  "src",
4731
5037
  "commands",
4732
5038
  "backup",
4733
- "policy",
5039
+ "restore",
4734
5040
  "create.js"
4735
5041
  ]
4736
5042
  },
4737
- "backup:policy:delete": {
4738
- "aliases": [],
4739
- "args": {
4740
- "id": {
4741
- "name": "id",
4742
- "required": true
4743
- }
4744
- },
4745
- "description": "Delete a backup policy (existing artifacts are retained)",
4746
- "flags": {
4747
- "yes": {
4748
- "char": "y",
4749
- "name": "yes",
4750
- "allowNo": false,
4751
- "type": "boolean"
4752
- }
4753
- },
4754
- "hasDynamicHelp": false,
4755
- "hiddenAliases": [],
4756
- "id": "backup:policy:delete",
4757
- "pluginAlias": "@flui-cloud/cli",
4758
- "pluginName": "@flui-cloud/cli",
4759
- "pluginType": "core",
4760
- "strict": true,
4761
- "enableJsonFlag": false,
4762
- "isESM": false,
4763
- "relativePath": [
4764
- "lib",
4765
- "cli",
4766
- "src",
4767
- "commands",
4768
- "backup",
4769
- "policy",
4770
- "delete.js"
4771
- ]
4772
- },
4773
- "backup:policy:list": {
5043
+ "backup:restore:list": {
4774
5044
  "aliases": [],
4775
5045
  "args": {},
4776
- "description": "List backup policies",
5046
+ "description": "List restore jobs",
4777
5047
  "flags": {
4778
- "cluster": {
4779
- "description": "Filter by cluster ID",
4780
- "name": "cluster",
4781
- "hasDynamicHelp": false,
4782
- "multiple": false,
4783
- "type": "option"
4784
- },
4785
5048
  "json": {
4786
5049
  "name": "json",
4787
5050
  "allowNo": false,
@@ -4790,7 +5053,7 @@
4790
5053
  },
4791
5054
  "hasDynamicHelp": false,
4792
5055
  "hiddenAliases": [],
4793
- "id": "backup:policy:list",
5056
+ "id": "backup:restore:list",
4794
5057
  "pluginAlias": "@flui-cloud/cli",
4795
5058
  "pluginName": "@flui-cloud/cli",
4796
5059
  "pluginType": "core",
@@ -4803,50 +5066,14 @@
4803
5066
  "src",
4804
5067
  "commands",
4805
5068
  "backup",
4806
- "policy",
5069
+ "restore",
4807
5070
  "list.js"
4808
5071
  ]
4809
5072
  },
4810
- "backup:policy:show": {
4811
- "aliases": [],
4812
- "args": {
4813
- "id": {
4814
- "description": "Policy ID",
4815
- "name": "id",
4816
- "required": true
4817
- }
4818
- },
4819
- "description": "Show a backup policy by ID",
4820
- "flags": {
4821
- "json": {
4822
- "name": "json",
4823
- "allowNo": false,
4824
- "type": "boolean"
4825
- }
4826
- },
4827
- "hasDynamicHelp": false,
4828
- "hiddenAliases": [],
4829
- "id": "backup:policy:show",
4830
- "pluginAlias": "@flui-cloud/cli",
4831
- "pluginName": "@flui-cloud/cli",
4832
- "pluginType": "core",
4833
- "strict": true,
4834
- "enableJsonFlag": false,
4835
- "isESM": false,
4836
- "relativePath": [
4837
- "lib",
4838
- "cli",
4839
- "src",
4840
- "commands",
4841
- "backup",
4842
- "policy",
4843
- "show.js"
4844
- ]
4845
- },
4846
- "backup:restore:create": {
5073
+ "backup:restore:preview": {
4847
5074
  "aliases": [],
4848
5075
  "args": {},
4849
- "description": "Create a restore job",
5076
+ "description": "Preview what a restore would touch (resources to be created/replaced)",
4850
5077
  "flags": {
4851
5078
  "artifact": {
4852
5079
  "description": "Backup artifact ID",
@@ -4856,62 +5083,18 @@
4856
5083
  "multiple": false,
4857
5084
  "type": "option"
4858
5085
  },
4859
- "source-destination": {
4860
- "name": "source-destination",
4861
- "required": true,
4862
- "hasDynamicHelp": false,
4863
- "multiple": false,
4864
- "type": "option"
4865
- },
4866
- "target-cluster": {
4867
- "description": "Cluster to restore into",
4868
- "name": "target-cluster",
4869
- "required": true,
4870
- "hasDynamicHelp": false,
4871
- "multiple": false,
4872
- "type": "option"
4873
- },
4874
- "target-kind": {
4875
- "name": "target-kind",
4876
- "required": true,
4877
- "hasDynamicHelp": false,
4878
- "multiple": false,
4879
- "options": [
4880
- "cluster",
4881
- "namespace",
4882
- "application",
4883
- "observability"
4884
- ],
4885
- "type": "option"
4886
- },
4887
- "target-namespace": {
4888
- "description": "Required when --target-kind=namespace",
4889
- "name": "target-namespace",
4890
- "hasDynamicHelp": false,
4891
- "multiple": false,
4892
- "type": "option"
4893
- },
4894
- "target-app": {
4895
- "description": "Required when --target-kind=application",
4896
- "name": "target-app",
4897
- "hasDynamicHelp": false,
4898
- "multiple": false,
4899
- "type": "option"
4900
- },
4901
- "strategy": {
4902
- "name": "strategy",
5086
+ "source-destination": {
5087
+ "description": "Source destination ID (where the artifact lives)",
5088
+ "name": "source-destination",
5089
+ "required": true,
4903
5090
  "hasDynamicHelp": false,
4904
5091
  "multiple": false,
4905
- "options": [
4906
- "velero_rebuild",
4907
- "os_snapshot"
4908
- ],
4909
5092
  "type": "option"
4910
5093
  }
4911
5094
  },
4912
5095
  "hasDynamicHelp": false,
4913
5096
  "hiddenAliases": [],
4914
- "id": "backup:restore:create",
5097
+ "id": "backup:restore:preview",
4915
5098
  "pluginAlias": "@flui-cloud/cli",
4916
5099
  "pluginName": "@flui-cloud/cli",
4917
5100
  "pluginType": "core",
@@ -4925,13 +5108,18 @@
4925
5108
  "commands",
4926
5109
  "backup",
4927
5110
  "restore",
4928
- "create.js"
5111
+ "preview.js"
4929
5112
  ]
4930
5113
  },
4931
- "backup:restore:list": {
5114
+ "backup:restore:show": {
4932
5115
  "aliases": [],
4933
- "args": {},
4934
- "description": "List restore jobs",
5116
+ "args": {
5117
+ "id": {
5118
+ "name": "id",
5119
+ "required": true
5120
+ }
5121
+ },
5122
+ "description": "Show a restore job by ID",
4935
5123
  "flags": {
4936
5124
  "json": {
4937
5125
  "name": "json",
@@ -4941,7 +5129,7 @@
4941
5129
  },
4942
5130
  "hasDynamicHelp": false,
4943
5131
  "hiddenAliases": [],
4944
- "id": "backup:restore:list",
5132
+ "id": "backup:restore:show",
4945
5133
  "pluginAlias": "@flui-cloud/cli",
4946
5134
  "pluginName": "@flui-cloud/cli",
4947
5135
  "pluginType": "core",
@@ -4955,25 +5143,55 @@
4955
5143
  "commands",
4956
5144
  "backup",
4957
5145
  "restore",
4958
- "list.js"
5146
+ "show.js"
4959
5147
  ]
4960
5148
  },
4961
- "backup:restore:preview": {
5149
+ "backup:job:list": {
4962
5150
  "aliases": [],
4963
5151
  "args": {},
4964
- "description": "Preview what a restore would touch (resources to be created/replaced)",
5152
+ "description": "List backup jobs for a cluster",
4965
5153
  "flags": {
4966
- "artifact": {
4967
- "description": "Backup artifact ID",
4968
- "name": "artifact",
5154
+ "cluster": {
5155
+ "description": "Cluster ID",
5156
+ "name": "cluster",
4969
5157
  "required": true,
4970
5158
  "hasDynamicHelp": false,
4971
5159
  "multiple": false,
4972
5160
  "type": "option"
4973
5161
  },
4974
- "source-destination": {
4975
- "description": "Source destination ID (where the artifact lives)",
4976
- "name": "source-destination",
5162
+ "json": {
5163
+ "name": "json",
5164
+ "allowNo": false,
5165
+ "type": "boolean"
5166
+ }
5167
+ },
5168
+ "hasDynamicHelp": false,
5169
+ "hiddenAliases": [],
5170
+ "id": "backup:job:list",
5171
+ "pluginAlias": "@flui-cloud/cli",
5172
+ "pluginName": "@flui-cloud/cli",
5173
+ "pluginType": "core",
5174
+ "strict": true,
5175
+ "enableJsonFlag": false,
5176
+ "isESM": false,
5177
+ "relativePath": [
5178
+ "lib",
5179
+ "cli",
5180
+ "src",
5181
+ "commands",
5182
+ "backup",
5183
+ "job",
5184
+ "list.js"
5185
+ ]
5186
+ },
5187
+ "backup:job:run": {
5188
+ "aliases": [],
5189
+ "args": {},
5190
+ "description": "Trigger an on-demand backup job for a given policy",
5191
+ "flags": {
5192
+ "policy": {
5193
+ "description": "Policy ID",
5194
+ "name": "policy",
4977
5195
  "required": true,
4978
5196
  "hasDynamicHelp": false,
4979
5197
  "multiple": false,
@@ -4982,7 +5200,7 @@
4982
5200
  },
4983
5201
  "hasDynamicHelp": false,
4984
5202
  "hiddenAliases": [],
4985
- "id": "backup:restore:preview",
5203
+ "id": "backup:job:run",
4986
5204
  "pluginAlias": "@flui-cloud/cli",
4987
5205
  "pluginName": "@flui-cloud/cli",
4988
5206
  "pluginType": "core",
@@ -4995,11 +5213,11 @@
4995
5213
  "src",
4996
5214
  "commands",
4997
5215
  "backup",
4998
- "restore",
4999
- "preview.js"
5216
+ "job",
5217
+ "run.js"
5000
5218
  ]
5001
5219
  },
5002
- "backup:restore:show": {
5220
+ "backup:job:show": {
5003
5221
  "aliases": [],
5004
5222
  "args": {
5005
5223
  "id": {
@@ -5007,7 +5225,7 @@
5007
5225
  "required": true
5008
5226
  }
5009
5227
  },
5010
- "description": "Show a restore job by ID",
5228
+ "description": "Show a backup job by ID",
5011
5229
  "flags": {
5012
5230
  "json": {
5013
5231
  "name": "json",
@@ -5017,7 +5235,7 @@
5017
5235
  },
5018
5236
  "hasDynamicHelp": false,
5019
5237
  "hiddenAliases": [],
5020
- "id": "backup:restore:show",
5238
+ "id": "backup:job:show",
5021
5239
  "pluginAlias": "@flui-cloud/cli",
5022
5240
  "pluginName": "@flui-cloud/cli",
5023
5241
  "pluginType": "core",
@@ -5030,7 +5248,7 @@
5030
5248
  "src",
5031
5249
  "commands",
5032
5250
  "backup",
5033
- "restore",
5251
+ "job",
5034
5252
  "show.js"
5035
5253
  ]
5036
5254
  },
@@ -5132,11 +5350,22 @@
5132
5350
  "status.js"
5133
5351
  ]
5134
5352
  },
5135
- "backup:job:list": {
5353
+ "backup:policy:create": {
5136
5354
  "aliases": [],
5137
5355
  "args": {},
5138
- "description": "List backup jobs for a cluster",
5356
+ "description": "Create a backup policy",
5357
+ "examples": [
5358
+ "<%= config.bin %> <%= command.id %> --name daily-all --cluster <id> --scope cluster_all --schedule \"0 2 * * *\" --retention-days 14 --destination <destId>",
5359
+ "<%= config.bin %> <%= command.id %> --name app-snap --cluster <id> --scope applications --scope-namespaces ns1,ns2 --destination <destId>"
5360
+ ],
5139
5361
  "flags": {
5362
+ "name": {
5363
+ "name": "name",
5364
+ "required": true,
5365
+ "hasDynamicHelp": false,
5366
+ "multiple": false,
5367
+ "type": "option"
5368
+ },
5140
5369
  "cluster": {
5141
5370
  "description": "Cluster ID",
5142
5371
  "name": "cluster",
@@ -5145,15 +5374,92 @@
5145
5374
  "multiple": false,
5146
5375
  "type": "option"
5147
5376
  },
5148
- "json": {
5149
- "name": "json",
5377
+ "scope": {
5378
+ "name": "scope",
5379
+ "required": true,
5380
+ "hasDynamicHelp": false,
5381
+ "multiple": false,
5382
+ "options": [
5383
+ "cluster_all",
5384
+ "namespaces",
5385
+ "applications",
5386
+ "label_selector"
5387
+ ],
5388
+ "type": "option"
5389
+ },
5390
+ "scope-namespaces": {
5391
+ "description": "Comma-separated namespaces (for scope=namespaces)",
5392
+ "name": "scope-namespaces",
5393
+ "hasDynamicHelp": false,
5394
+ "multiple": false,
5395
+ "type": "option"
5396
+ },
5397
+ "scope-apps": {
5398
+ "description": "Comma-separated application IDs (for scope=applications)",
5399
+ "name": "scope-apps",
5400
+ "hasDynamicHelp": false,
5401
+ "multiple": false,
5402
+ "type": "option"
5403
+ },
5404
+ "profile": {
5405
+ "name": "profile",
5406
+ "default": "single",
5407
+ "hasDynamicHelp": false,
5408
+ "multiple": false,
5409
+ "options": [
5410
+ "single",
5411
+ "mirrored",
5412
+ "custom"
5413
+ ],
5414
+ "type": "option"
5415
+ },
5416
+ "schedule": {
5417
+ "description": "Cron schedule (e.g. \"0 2 * * *\" for daily 02:00 UTC)",
5418
+ "name": "schedule",
5419
+ "hasDynamicHelp": false,
5420
+ "multiple": false,
5421
+ "type": "option"
5422
+ },
5423
+ "retention-days": {
5424
+ "name": "retention-days",
5425
+ "default": 30,
5426
+ "hasDynamicHelp": false,
5427
+ "multiple": false,
5428
+ "type": "option"
5429
+ },
5430
+ "retention-max-copies": {
5431
+ "name": "retention-max-copies",
5432
+ "hasDynamicHelp": false,
5433
+ "multiple": false,
5434
+ "type": "option"
5435
+ },
5436
+ "include-pvcs": {
5437
+ "name": "include-pvcs",
5438
+ "allowNo": false,
5439
+ "type": "boolean"
5440
+ },
5441
+ "include-etcd-l1": {
5442
+ "name": "include-etcd-l1",
5150
5443
  "allowNo": false,
5151
5444
  "type": "boolean"
5445
+ },
5446
+ "enabled": {
5447
+ "name": "enabled",
5448
+ "allowNo": true,
5449
+ "type": "boolean"
5450
+ },
5451
+ "destination": {
5452
+ "description": "Destination spec: <destId>[:primary|replica[:priority]] (repeatable)",
5453
+ "name": "destination",
5454
+ "required": true,
5455
+ "hasDynamicHelp": false,
5456
+ "multiple": true,
5457
+ "type": "option"
5152
5458
  }
5153
5459
  },
5154
5460
  "hasDynamicHelp": false,
5155
5461
  "hiddenAliases": [],
5156
- "id": "backup:job:list",
5462
+ "id": "backup:policy:create",
5157
5463
  "pluginAlias": "@flui-cloud/cli",
5158
5464
  "pluginName": "@flui-cloud/cli",
5159
5465
  "pluginType": "core",
@@ -5166,27 +5472,67 @@
5166
5472
  "src",
5167
5473
  "commands",
5168
5474
  "backup",
5169
- "job",
5170
- "list.js"
5475
+ "policy",
5476
+ "create.js"
5171
5477
  ]
5172
5478
  },
5173
- "backup:job:run": {
5479
+ "backup:policy:delete": {
5480
+ "aliases": [],
5481
+ "args": {
5482
+ "id": {
5483
+ "name": "id",
5484
+ "required": true
5485
+ }
5486
+ },
5487
+ "description": "Delete a backup policy (existing artifacts are retained)",
5488
+ "flags": {
5489
+ "yes": {
5490
+ "char": "y",
5491
+ "name": "yes",
5492
+ "allowNo": false,
5493
+ "type": "boolean"
5494
+ }
5495
+ },
5496
+ "hasDynamicHelp": false,
5497
+ "hiddenAliases": [],
5498
+ "id": "backup:policy:delete",
5499
+ "pluginAlias": "@flui-cloud/cli",
5500
+ "pluginName": "@flui-cloud/cli",
5501
+ "pluginType": "core",
5502
+ "strict": true,
5503
+ "enableJsonFlag": false,
5504
+ "isESM": false,
5505
+ "relativePath": [
5506
+ "lib",
5507
+ "cli",
5508
+ "src",
5509
+ "commands",
5510
+ "backup",
5511
+ "policy",
5512
+ "delete.js"
5513
+ ]
5514
+ },
5515
+ "backup:policy:list": {
5174
5516
  "aliases": [],
5175
5517
  "args": {},
5176
- "description": "Trigger an on-demand backup job for a given policy",
5518
+ "description": "List backup policies",
5177
5519
  "flags": {
5178
- "policy": {
5179
- "description": "Policy ID",
5180
- "name": "policy",
5181
- "required": true,
5520
+ "cluster": {
5521
+ "description": "Filter by cluster ID",
5522
+ "name": "cluster",
5182
5523
  "hasDynamicHelp": false,
5183
5524
  "multiple": false,
5184
5525
  "type": "option"
5526
+ },
5527
+ "json": {
5528
+ "name": "json",
5529
+ "allowNo": false,
5530
+ "type": "boolean"
5185
5531
  }
5186
5532
  },
5187
5533
  "hasDynamicHelp": false,
5188
5534
  "hiddenAliases": [],
5189
- "id": "backup:job:run",
5535
+ "id": "backup:policy:list",
5190
5536
  "pluginAlias": "@flui-cloud/cli",
5191
5537
  "pluginName": "@flui-cloud/cli",
5192
5538
  "pluginType": "core",
@@ -5199,19 +5545,20 @@
5199
5545
  "src",
5200
5546
  "commands",
5201
5547
  "backup",
5202
- "job",
5203
- "run.js"
5548
+ "policy",
5549
+ "list.js"
5204
5550
  ]
5205
5551
  },
5206
- "backup:job:show": {
5552
+ "backup:policy:show": {
5207
5553
  "aliases": [],
5208
5554
  "args": {
5209
5555
  "id": {
5556
+ "description": "Policy ID",
5210
5557
  "name": "id",
5211
5558
  "required": true
5212
5559
  }
5213
5560
  },
5214
- "description": "Show a backup job by ID",
5561
+ "description": "Show a backup policy by ID",
5215
5562
  "flags": {
5216
5563
  "json": {
5217
5564
  "name": "json",
@@ -5221,7 +5568,7 @@
5221
5568
  },
5222
5569
  "hasDynamicHelp": false,
5223
5570
  "hiddenAliases": [],
5224
- "id": "backup:job:show",
5571
+ "id": "backup:policy:show",
5225
5572
  "pluginAlias": "@flui-cloud/cli",
5226
5573
  "pluginName": "@flui-cloud/cli",
5227
5574
  "pluginType": "core",
@@ -5234,10 +5581,10 @@
5234
5581
  "src",
5235
5582
  "commands",
5236
5583
  "backup",
5237
- "job",
5584
+ "policy",
5238
5585
  "show.js"
5239
5586
  ]
5240
5587
  }
5241
5588
  },
5242
- "version": "0.0.1"
5589
+ "version": "0.2.0"
5243
5590
  }